diff --git a/libcomposefs/lcfs-writer-erofs.c b/libcomposefs/lcfs-writer-erofs.c index eda6c7ee..ce5589cd 100644 --- a/libcomposefs/lcfs-writer-erofs.c +++ b/libcomposefs/lcfs-writer-erofs.c @@ -1746,7 +1746,7 @@ static struct lcfs_node_s *lcfs_build_node_from_image(struct lcfs_image_data *da memcpy(name_buf, tail_data, file_size); name_buf[file_size] = 0; - if (lcfs_node_set_payload(node, name_buf) < 0) + if (lcfs_node_set_symlink_payload(node, name_buf) < 0) return NULL; } else if (type == S_IFREG && file_size != 0 && erofs_inode_is_flat(cino)) { diff --git a/libcomposefs/lcfs-writer.c b/libcomposefs/lcfs-writer.c index 7a3e5b50..b3f4303d 100644 --- a/libcomposefs/lcfs-writer.c +++ b/libcomposefs/lcfs-writer.c @@ -813,7 +813,7 @@ struct lcfs_node_s *lcfs_load_node_from_file(int dirfd, const char *fname, return NULL; target[r] = '\0'; - r = lcfs_node_set_payload(ret, target); + r = lcfs_node_set_symlink_payload(ret, target); if (r < 0) return NULL; } @@ -917,6 +917,33 @@ int lcfs_node_set_payload(struct lcfs_node_s *node, const char *payload) return 0; } +int lcfs_node_set_symlink_payload(struct lcfs_node_s *node, const char *payload) +{ + // Caller must have ensured this + assert((node->inode.st_mode & S_IFMT) == S_IFLNK); + // Symlink target must be non-empty + if (payload == NULL || !*payload) { + errno = EINVAL; + return -1; + } + // Call the "raw" API for setting payloads, which also verifies + // maximum length. + if (lcfs_node_set_payload(node, payload) < 0) { + return -1; + } + // We must have set a payload now + assert(node->payload); + // Historically we accept any arbitrary data in the dumpfile + // for the file size for symlink, and end up ignoring it + // ultimately when we write the EROFS. However previously + // it was pretty confusing as the in-memory node data + // could have a bogus size. If somehow the inode state claimed + // something else for size, let's always replace it with the symlink + // length which is canonical. + node->inode.st_size = strlen(node->payload); + return 0; +} + const char *lcfs_node_get_payload(struct lcfs_node_s *node) { return node->payload; diff --git a/libcomposefs/lcfs-writer.h b/libcomposefs/lcfs-writer.h index f08acc09..ea705b3c 100644 --- a/libcomposefs/lcfs-writer.h +++ b/libcomposefs/lcfs-writer.h @@ -108,6 +108,8 @@ LCFS_EXTERN const char *lcfs_node_get_xattr_name(struct lcfs_node_s *node, size_t index); LCFS_EXTERN int lcfs_node_set_payload(struct lcfs_node_s *node, const char *payload); +LCFS_EXTERN int lcfs_node_set_symlink_payload(struct lcfs_node_s *node, + const char *payload); LCFS_EXTERN const char *lcfs_node_get_payload(struct lcfs_node_s *node); LCFS_EXTERN int lcfs_node_set_content(struct lcfs_node_s *node, diff --git a/tools/mkcomposefs.c b/tools/mkcomposefs.c index 03988887..8c300725 100644 --- a/tools/mkcomposefs.c +++ b/tools/mkcomposefs.c @@ -440,6 +440,7 @@ static char *tree_from_dump_line(dump_info *info, const char *line, size_t line_ if (lcfs_node_try_set_mode(node, mode) < 0) { return make_error("Invalid mode %o", (unsigned int)mode); } + unsigned int type = mode & S_IFMT; err = tree_add_node(info, path, node); if (err) @@ -509,20 +510,22 @@ static char *tree_from_dump_line(dump_info *info, const char *line, size_t line_ if (digest == NULL && err) return err; - lcfs_node_set_size(node, size); + if (type != S_IFLNK) + lcfs_node_set_size(node, size); lcfs_node_set_nlink(node, nlink); lcfs_node_set_uid(node, uid); lcfs_node_set_gid(node, gid); lcfs_node_set_rdev64(node, rdev); lcfs_node_set_mtime(node, &mtime); // Validate that symlinks are non-empty - if ((mode & S_IFMT) == S_IFLNK) { - if (payload == NULL) { - return make_error("Invalid empty symlink"); + if (type == S_IFLNK) { + if (lcfs_node_set_symlink_payload(node, payload) < 0) { + return make_error("Invalid symlink"); } + } else { + if (lcfs_node_set_payload(node, payload) < 0) + return make_error("Invalid payload"); } - if (lcfs_node_set_payload(node, payload) < 0) - return make_error("Invalid payload"); if (content) { ret = lcfs_node_set_content(node, (uint8_t *)content, size); if (ret < 0)