aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/gensquashfs.13
-rw-r--r--include/tar.h1
-rw-r--r--lib/fstree/fstree_from_file.c14
-rw-r--r--lib/tar/read_header.c3
-rw-r--r--mkfs/options.c3
-rw-r--r--tar/tar2sqfs.c15
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 <path> <mode> <uid> <gid> [<location>]
dir <path> <mode> <uid> <gid>
nod <path> <mode> <uid> <gid> <dev_type> <maj> <min>
slink <path> <mode> <uid> <gid> <target>
+link <path> <dummy> <dummy> <dummy> <target>
pipe <path> <mode> <uid> <gid>
sock <path> <mode> <uid> <gid>
.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}
-<target>;Symlink target.
+<target>;Symlink or hardlink target.
<mode>;Mode/permissions of the entry.
<uid>;Numeric user id.
<gid>;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 <path> <mode> <uid> <gid>\n"
"nod <path> <mode> <uid> <gid> <dev_type> <maj> <min>\n"
"slink <path> <mode> <uid> <gid> <target>\n"
+"link <path> <dummy> <dummy> <dummy> <target>\n"
"pipe <path> <mode> <uid> <gid>\n"
"sock <path> <mode> <uid> <gid>\n"
"\n"
@@ -120,7 +121,7 @@ const char *help_details =
"<location> 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"
-"<target> Symlink target.\n"
+"<target> Symlink or hardlink target.\n"
"<mode> Mode/permissions of the entry.\n"
"<uid> Numeric user id.\n"
"<gid> 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;
}