From b16616ef092e8cd97674aac3380c5d7c600d7c61 Mon Sep 17 00:00:00 2001 From: David Oberhollenzer Date: Thu, 19 Dec 2019 16:31:39 +0100 Subject: Add hard link support to gensquashfs and tar2sqfs In libtar, set a special flag if the header is actually a hard link. In tar2sqfs, create a hard link node and skip the rest for hard links. Also refues to set the root attributes from a hard link, it may refere to a node that we have missed earlier, there is nothing else that we can do here. In fstree_from_file, add a "link" command for adding hard links. Signed-off-by: David Oberhollenzer --- doc/gensquashfs.1 | 3 ++- include/tar.h | 1 + lib/fstree/fstree_from_file.c | 14 ++++++++++++++ lib/tar/read_header.c | 3 +-- mkfs/options.c | 3 ++- tar/tar2sqfs.c | 15 ++++++++++++++- 6 files changed, 34 insertions(+), 5 deletions(-) diff --git a/doc/gensquashfs.1 b/doc/gensquashfs.1 index 04dd968..0de39bf 100644 --- a/doc/gensquashfs.1 +++ b/doc/gensquashfs.1 @@ -105,6 +105,7 @@ file [] dir nod slink +link pipe sock .fi @@ -131,7 +132,7 @@ Optional location of the input file. Can be specified relative to either the description file or the pack directory. If omitted, the image path is used as a relative path. T} -;Symlink target. +;Symlink or hardlink target. ;Mode/permissions of the entry. ;Numeric user id. ;Numeric group id. diff --git a/include/tar.h b/include/tar.h index 22563c4..617148f 100644 --- a/include/tar.h +++ b/include/tar.h @@ -84,6 +84,7 @@ typedef struct { sqfs_u64 actual_size; sqfs_u64 record_size; bool unknown_record; + bool is_hard_link; tar_xattr_t *xattr; /* broken out since struct stat could contain diff --git a/lib/fstree/fstree_from_file.c b/lib/fstree/fstree_from_file.c index 9cdf9a1..bf11755 100644 --- a/lib/fstree/fstree_from_file.c +++ b/lib/fstree/fstree_from_file.c @@ -62,6 +62,19 @@ static int add_file(fstree_t *fs, const char *filename, size_t line_num, return add_generic(fs, filename, line_num, path, basic, extra); } +static int add_hard_link(fstree_t *fs, const char *filename, size_t line_num, + const char *path, struct stat *basic, const char *extra) +{ + (void)basic; + + if (fstree_add_hard_link(fs, path, extra) == NULL) { + fprintf(stderr, "%s: " PRI_SZ ": %s\n", + filename, line_num, strerror(errno)); + return -1; + } + return 0; +} + static const struct { const char *keyword; unsigned int mode; @@ -71,6 +84,7 @@ static const struct { } file_list_hooks[] = { { "dir", S_IFDIR, false, add_generic }, { "slink", S_IFLNK, true, add_generic }, + { "link", 0, true, add_hard_link }, { "nod", 0, true, add_device }, { "pipe", S_IFIFO, false, add_generic }, { "sock", S_IFSOCK, false, add_generic }, diff --git a/lib/tar/read_header.c b/lib/tar/read_header.c index 7d209ae..f82f9a5 100644 --- a/lib/tar/read_header.c +++ b/lib/tar/read_header.c @@ -345,8 +345,7 @@ static int decode_header(const tar_header_t *hdr, unsigned int set_by_pax, out->sb.st_mode |= S_IFREG; break; case TAR_TYPE_LINK: - /* XXX: hard links are not support yet */ - out->sb.st_mode = S_IFLNK | 0777; + out->is_hard_link = true; break; case TAR_TYPE_SLINK: out->sb.st_mode = S_IFLNK | 0777; diff --git a/mkfs/options.c b/mkfs/options.c index 39ecdc7..fd6ca46 100644 --- a/mkfs/options.c +++ b/mkfs/options.c @@ -112,6 +112,7 @@ const char *help_details = "dir \n" "nod \n" "slink \n" +"link \n" "pipe \n" "sock \n" "\n" @@ -120,7 +121,7 @@ const char *help_details = " If given, location of the input file. Either absolute or relative\n" " to the description file. If omitted, the image path is used,\n" " relative to the description file.\n" -" Symlink target.\n" +" Symlink or hardlink target.\n" " Mode/permissions of the entry.\n" " Numeric user id.\n" " Numeric group id.\n" diff --git a/tar/tar2sqfs.c b/tar/tar2sqfs.c index 63933eb..f522239 100644 --- a/tar/tar2sqfs.c +++ b/tar/tar2sqfs.c @@ -355,6 +355,19 @@ static int create_node_and_repack_data(tar_header_decoded_t *hdr) { tree_node_t *node; + if (hdr->is_hard_link) { + node = fstree_add_hard_link(&sqfs.fs, hdr->name, + hdr->link_target); + if (node == NULL) + goto fail_errno; + + if (!cfg.quiet) { + printf("Hard link %s -> %s\n", hdr->name, + hdr->link_target); + } + return 0; + } + if (!keep_time) { hdr->sb.st_mtime = sqfs.fs.defaults.st_mtime; } @@ -385,7 +398,7 @@ fail_errno: static int set_root_attribs(const tar_header_decoded_t *hdr) { - if (!S_ISDIR(hdr->sb.st_mode)) { + if (hdr->is_hard_link || !S_ISDIR(hdr->sb.st_mode)) { fprintf(stderr, "'%s' is not a directory!\n", hdr->name); return -1; } -- cgit v1.2.3