aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/tar/src/write_header.c167
-rw-r--r--lib/tar/test/tar_write_simple.c192
2 files changed, 226 insertions, 133 deletions
diff --git a/lib/tar/src/write_header.c b/lib/tar/src/write_header.c
index dda98b7..d27cef0 100644
--- a/lib/tar/src/write_header.c
+++ b/lib/tar/src/write_header.c
@@ -41,6 +41,9 @@ static void write_number(char *dst, sqfs_u64 value, int digits)
for (i = 0; i < (digits - 1); ++i)
mask = (mask << 3) | 7;
+ if (digits < 0 || (size_t)digits >= sizeof(buffer))
+ digits = sizeof(buffer) - 1;
+
if (value <= mask) {
sprintf(buffer, "%0*lo ", digits - 1, (unsigned long)value);
memcpy(dst, buffer, digits);
@@ -64,36 +67,36 @@ static void write_number_signed(char *dst, sqfs_s64 value, int digits)
}
}
-static int write_header(sqfs_ostream_t *fp, const struct stat *sb,
+static int write_header(sqfs_ostream_t *fp, const sqfs_dir_entry_t *ent,
const char *name, const char *slink_target, int type)
{
int maj = 0, min = 0;
sqfs_u64 size = 0;
tar_header_t hdr;
- if (S_ISCHR(sb->st_mode) || S_ISBLK(sb->st_mode)) {
- maj = major(sb->st_rdev);
- min = minor(sb->st_rdev);
+ if (S_ISCHR(ent->mode) || S_ISBLK(ent->mode)) {
+ maj = major(ent->rdev);
+ min = minor(ent->rdev);
}
- if (S_ISREG(sb->st_mode))
- size = sb->st_size;
+ if (S_ISREG(ent->mode))
+ size = ent->size;
memset(&hdr, 0, sizeof(hdr));
strncpy(hdr.name, name, sizeof(hdr.name) - 1);
- write_number(hdr.mode, sb->st_mode & ~S_IFMT, sizeof(hdr.mode));
- write_number(hdr.uid, sb->st_uid, sizeof(hdr.uid));
- write_number(hdr.gid, sb->st_gid, sizeof(hdr.gid));
+ write_number(hdr.mode, ent->mode & ~S_IFMT, sizeof(hdr.mode));
+ write_number(hdr.uid, ent->uid, sizeof(hdr.uid));
+ write_number(hdr.gid, ent->gid, sizeof(hdr.gid));
write_number(hdr.size, size, sizeof(hdr.size));
- write_number_signed(hdr.mtime, sb->st_mtime, sizeof(hdr.mtime));
+ write_number_signed(hdr.mtime, ent->mtime, sizeof(hdr.mtime));
hdr.typeflag = type;
if (slink_target != NULL)
- memcpy(hdr.linkname, slink_target, sb->st_size);
+ memcpy(hdr.linkname, slink_target, ent->size);
memcpy(hdr.magic, TAR_MAGIC_OLD, sizeof(hdr.magic));
memcpy(hdr.version, TAR_VERSION_OLD, sizeof(hdr.version));
- sprintf(hdr.uname, "%u", sb->st_uid);
- sprintf(hdr.gname, "%u", sb->st_gid);
+ sprintf(hdr.uname, "%lu", (unsigned long)ent->uid);
+ sprintf(hdr.gname, "%lu", (unsigned long)ent->gid);
write_number(hdr.devmajor, maj, sizeof(hdr.devmajor));
write_number(hdr.devminor, min, sizeof(hdr.devminor));
@@ -102,18 +105,18 @@ static int write_header(sqfs_ostream_t *fp, const struct stat *sb,
return fp->append(fp, &hdr, sizeof(hdr));
}
-static int write_ext_header(sqfs_ostream_t *fp, const struct stat *orig,
+static int write_ext_header(sqfs_ostream_t *fp, const sqfs_dir_entry_t *orig,
const char *payload, size_t payload_len,
int type, const char *name)
{
- struct stat sb;
+ sqfs_dir_entry_t ent;
int ret;
- sb = *orig;
- sb.st_mode = S_IFREG | 0644;
- sb.st_size = payload_len;
+ ent = *orig;
+ ent.mode = S_IFREG | 0644;
+ ent.size = payload_len;
- ret = write_header(fp, &sb, name, NULL, type);
+ ret = write_header(fp, &ent, name, NULL, type);
if (ret)
return ret;
@@ -148,7 +151,7 @@ static size_t prefix_digit_len(size_t len)
return ndigit;
}
-static int write_schily_xattr(sqfs_ostream_t *fp, const struct stat *orig,
+static int write_schily_xattr(sqfs_ostream_t *fp, const sqfs_dir_entry_t *orig,
const char *name, const sqfs_xattr_t *xattr)
{
static const char *prefix = "SCHILY.xattr.";
@@ -184,28 +187,83 @@ static int write_schily_xattr(sqfs_ostream_t *fp, const struct stat *orig,
return ret;
}
-int write_tar_header(sqfs_ostream_t *fp,
- const struct stat *sb, const char *name,
+static int write_hard_link(sqfs_ostream_t *fp, const sqfs_dir_entry_t *ent,
+ const char *target, unsigned int counter)
+{
+ const char *name = ent->name;
+ tar_header_t hdr;
+ char buffer[64];
+ size_t len;
+ int ret;
+
+ memset(&hdr, 0, sizeof(hdr));
+
+ len = strlen(target);
+ if (len >= 100) {
+ sprintf(buffer, "gnu/target%u", counter);
+ ret = write_ext_header(fp, ent, target, len,
+ TAR_TYPE_GNU_SLINK, buffer);
+ if (ret)
+ return ret;
+ sprintf(hdr.linkname, "hardlink_%u", counter);
+ } else {
+ memcpy(hdr.linkname, target, len);
+ }
+
+ len = strlen(name);
+ if (len >= 100) {
+ sprintf(buffer, "gnu/name%u", counter);
+ ret = write_ext_header(fp, ent, name, len,
+ TAR_TYPE_GNU_PATH, buffer);
+ if (ret)
+ return ret;
+ sprintf(hdr.name, "gnu/data%u", counter);
+ } else {
+ memcpy(hdr.name, name, len);
+ }
+
+ write_number(hdr.mode, ent->mode & ~S_IFMT, sizeof(hdr.mode));
+ write_number(hdr.uid, ent->uid, sizeof(hdr.uid));
+ write_number(hdr.gid, ent->gid, sizeof(hdr.gid));
+ write_number(hdr.size, 0, sizeof(hdr.size));
+ write_number_signed(hdr.mtime, ent->mtime, sizeof(hdr.mtime));
+ hdr.typeflag = TAR_TYPE_LINK;
+ memcpy(hdr.magic, TAR_MAGIC_OLD, sizeof(hdr.magic));
+ memcpy(hdr.version, TAR_VERSION_OLD, sizeof(hdr.version));
+ sprintf(hdr.uname, "%lu", (unsigned long)ent->uid);
+ sprintf(hdr.gname, "%lu", (unsigned long)ent->gid);
+ write_number(hdr.devmajor, 0, sizeof(hdr.devmajor));
+ write_number(hdr.devminor, 0, sizeof(hdr.devminor));
+
+ update_checksum(&hdr);
+ return fp->append(fp, &hdr, sizeof(hdr));
+}
+
+int write_tar_header(sqfs_ostream_t *fp, const sqfs_dir_entry_t *ent,
const char *slink_target, const sqfs_xattr_t *xattr,
unsigned int counter)
{
+ const char *name = ent->name;
char buffer[64];
int type, ret;
+ if (ent->flags & SQFS_DIR_ENTRY_FLAG_HARD_LINK)
+ return write_hard_link(fp, ent, slink_target, counter);
+
if (xattr != NULL) {
sprintf(buffer, "pax/xattr%u", counter);
- ret = write_schily_xattr(fp, sb, buffer, xattr);
+ ret = write_schily_xattr(fp, ent, buffer, xattr);
if (ret)
return ret;
}
- if (!S_ISLNK(sb->st_mode))
+ if (!S_ISLNK(ent->mode))
slink_target = NULL;
- if (S_ISLNK(sb->st_mode) && sb->st_size >= 100) {
+ if (S_ISLNK(ent->mode) && ent->size >= 100) {
sprintf(buffer, "gnu/target%u", counter);
- ret = write_ext_header(fp, sb, slink_target, sb->st_size,
+ ret = write_ext_header(fp, ent, slink_target, ent->size,
TAR_TYPE_GNU_SLINK, buffer);
if (ret)
return ret;
@@ -215,7 +273,7 @@ int write_tar_header(sqfs_ostream_t *fp,
if (strlen(name) >= 100) {
sprintf(buffer, "gnu/name%u", counter);
- ret = write_ext_header(fp, sb, name, strlen(name),
+ ret = write_ext_header(fp, ent, name, strlen(name),
TAR_TYPE_GNU_PATH, buffer);
if (ret)
return ret;
@@ -224,7 +282,7 @@ int write_tar_header(sqfs_ostream_t *fp,
name = buffer;
}
- switch (sb->st_mode & S_IFMT) {
+ switch (ent->mode & S_IFMT) {
case S_IFCHR: type = TAR_TYPE_CHARDEV; break;
case S_IFBLK: type = TAR_TYPE_BLOCKDEV; break;
case S_IFLNK: type = TAR_TYPE_SLINK; break;
@@ -235,56 +293,5 @@ int write_tar_header(sqfs_ostream_t *fp,
return SQFS_ERROR_UNSUPPORTED;
}
- return write_header(fp, sb, name, slink_target, type);
-}
-
-int write_hard_link(sqfs_ostream_t *fp, const struct stat *sb, const char *name,
- const char *target, unsigned int counter)
-{
- tar_header_t hdr;
- char buffer[64];
- size_t len;
- int ret;
-
- memset(&hdr, 0, sizeof(hdr));
-
- len = strlen(target);
- if (len >= 100) {
- sprintf(buffer, "gnu/target%u", counter);
- ret = write_ext_header(fp, sb, target, len,
- TAR_TYPE_GNU_SLINK, buffer);
- if (ret)
- return ret;
- sprintf(hdr.linkname, "hardlink_%u", counter);
- } else {
- memcpy(hdr.linkname, target, len);
- }
-
- len = strlen(name);
- if (len >= 100) {
- sprintf(buffer, "gnu/name%u", counter);
- ret = write_ext_header(fp, sb, name, len,
- TAR_TYPE_GNU_PATH, buffer);
- if (ret)
- return ret;
- sprintf(hdr.name, "gnu/data%u", counter);
- } else {
- memcpy(hdr.name, name, len);
- }
-
- write_number(hdr.mode, sb->st_mode & ~S_IFMT, sizeof(hdr.mode));
- write_number(hdr.uid, sb->st_uid, sizeof(hdr.uid));
- write_number(hdr.gid, sb->st_gid, sizeof(hdr.gid));
- write_number(hdr.size, 0, sizeof(hdr.size));
- write_number_signed(hdr.mtime, sb->st_mtime, sizeof(hdr.mtime));
- hdr.typeflag = TAR_TYPE_LINK;
- memcpy(hdr.magic, TAR_MAGIC_OLD, sizeof(hdr.magic));
- memcpy(hdr.version, TAR_VERSION_OLD, sizeof(hdr.version));
- sprintf(hdr.uname, "%u", sb->st_uid);
- sprintf(hdr.gname, "%u", sb->st_gid);
- write_number(hdr.devmajor, 0, sizeof(hdr.devmajor));
- write_number(hdr.devminor, 0, sizeof(hdr.devminor));
-
- update_checksum(&hdr);
- return fp->append(fp, &hdr, sizeof(hdr));
+ return write_header(fp, ent, name, slink_target, type);
}
diff --git a/lib/tar/test/tar_write_simple.c b/lib/tar/test/tar_write_simple.c
index 438ea37..c82fe08 100644
--- a/lib/tar/test/tar_write_simple.c
+++ b/lib/tar/test/tar_write_simple.c
@@ -11,6 +11,35 @@
#include "sqfs/xattr.h"
#include "compat.h"
+static void hex_dump(const sqfs_u8 *data, size_t size)
+{
+ for (size_t i = 0; i < size; ++i) {
+ int hi = (data[i] >> 4) & 0x0F;
+ int lo = data[i] & 0x0F;
+
+ hi = (hi >= 0x0a) ? ('a' + (hi - 0x0a)) : ('0' + hi);
+ lo = (lo >= 0x0a) ? ('a' + (lo - 0x0a)) : ('0' + lo);
+
+ fprintf(stderr, "%c%c", hi, lo);
+
+ if ((i % 16) == 15) {
+ fputs(" | ", stderr);
+
+ for (size_t j = i - 15; j <= i; ++j) {
+ if (data[j] >= 0x20 && data[j] <= 0x7f) {
+ fputc(data[j], stderr);
+ } else {
+ fputc('.', stderr);
+ }
+ }
+
+ fputc('\n', stderr);
+ } else {
+ fputc(' ', stderr);
+ }
+ }
+}
+
/*****************************************************************************/
static int buffer_append(sqfs_ostream_t *strm, const void *data, size_t size);
@@ -77,67 +106,95 @@ static sqfs_xattr_t *mkxattr_chain(void)
int main(int argc, char **argv)
{
+ sqfs_dir_entry_t *ent;
sqfs_xattr_t *xattr;
sqfs_istream_t *fp;
- struct stat sb;
int ret;
(void)argc; (void)argv;
/* genereate some archive contents */
- memset(&sb, 0, sizeof(sb));
- sb.st_mode = S_IFDIR | 0755;
- sb.st_mtime = TIME_STAMP;
- ret = write_tar_header(&mem_stream, &sb, "dev/", NULL, NULL, 0);
+ ent = sqfs_dir_entry_create("dev/", S_IFDIR | 0755, 0);
+ TEST_NOT_NULL(ent);
+ ent->mtime = TIME_STAMP;
+ ret = write_tar_header(&mem_stream, ent, NULL, NULL, 0);
+ sqfs_free(ent);
TEST_EQUAL_I(ret, 0);
/* device files */
- sb.st_mode = S_IFCHR | 0620;
- sb.st_gid = 5;
- sb.st_rdev = makedev(4, 0);
- ret = write_tar_header(&mem_stream, &sb, "dev/tty0", NULL, NULL, 1);
+ ent = sqfs_dir_entry_create("dev/tty0", S_IFCHR | 0620, 0);
+ TEST_NOT_NULL(ent);
+ ent->mtime = TIME_STAMP;
+ ent->gid = 5;
+ ent->rdev = makedev(4, 0);
+ ret = write_tar_header(&mem_stream, ent, NULL, NULL, 1);
+ sqfs_free(ent);
TEST_EQUAL_I(ret, 0);
- sb.st_rdev = makedev(4, 1);
- ret = write_tar_header(&mem_stream, &sb, "dev/tty1", NULL, NULL, 2);
+ ent = sqfs_dir_entry_create("dev/tty1", S_IFCHR | 0620, 0);
+ TEST_NOT_NULL(ent);
+ ent->mtime = TIME_STAMP;
+ ent->gid = 5;
+ ent->rdev = makedev(4, 1);
+ ret = write_tar_header(&mem_stream, ent, NULL, NULL, 2);
+ sqfs_free(ent);
TEST_EQUAL_I(ret, 0);
- sb.st_rdev = makedev(4, 2);
- ret = write_tar_header(&mem_stream, &sb, "dev/tty2", NULL, NULL, 3);
+ ent = sqfs_dir_entry_create("dev/tty2", S_IFCHR | 0620, 0);
+ TEST_NOT_NULL(ent);
+ ent->mtime = TIME_STAMP;
+ ent->gid = 5;
+ ent->rdev = makedev(4, 2);
+ ret = write_tar_header(&mem_stream, ent, NULL, NULL, 3);
+ sqfs_free(ent);
TEST_EQUAL_I(ret, 0);
- memset(&sb, 0, sizeof(sb));
- sb.st_mode = S_IFDIR | 0755;
- sb.st_mtime = TIME_STAMP;
- ret = write_tar_header(&mem_stream, &sb, "usr/", NULL, NULL, 4);
+ ent = sqfs_dir_entry_create("usr/", S_IFDIR | 0755, 0);
+ TEST_NOT_NULL(ent);
+ ent->mtime = TIME_STAMP;
+ ret = write_tar_header(&mem_stream, ent, NULL, NULL, 4);
+ sqfs_free(ent);
TEST_EQUAL_I(ret, 0);
- ret = write_tar_header(&mem_stream, &sb, "usr/bin/", NULL, NULL, 5);
+ ent = sqfs_dir_entry_create("usr/bin/", S_IFDIR | 0755, 0);
+ TEST_NOT_NULL(ent);
+ ent->mtime = TIME_STAMP;
+ ret = write_tar_header(&mem_stream, ent, NULL, NULL, 5);
+ sqfs_free(ent);
TEST_EQUAL_I(ret, 0);
/* sym link */
- sb.st_mode = S_IFLNK | 0777;
- sb.st_size = 7;
- ret = write_tar_header(&mem_stream, &sb, "bin", "usr/bin", NULL, 6);
+ ent = sqfs_dir_entry_create("bin", S_IFLNK | 0777, 0);
+ TEST_NOT_NULL(ent);
+ ent->mtime = TIME_STAMP;
+ ent->size = 7;
+ ret = write_tar_header(&mem_stream, ent, "usr/bin", NULL, 6);
+ sqfs_free(ent);
TEST_EQUAL_I(ret, 0);
- memset(&sb, 0, sizeof(sb));
- sb.st_mode = S_IFDIR | 0755;
- sb.st_mtime = TIME_STAMP;
- ret = write_tar_header(&mem_stream, &sb, "home/", NULL, NULL, 7);
+ ent = sqfs_dir_entry_create("home/", S_IFDIR | 0755, 0);
+ TEST_NOT_NULL(ent);
+ ent->mtime = TIME_STAMP;
+ ret = write_tar_header(&mem_stream, ent, NULL, NULL, 7);
+ sqfs_free(ent);
TEST_EQUAL_I(ret, 0);
- sb.st_mode = S_IFDIR | 0750;
- sb.st_uid = 1000;
- sb.st_gid = 1000;
- ret = write_tar_header(&mem_stream, &sb, "home/goliath/",
- NULL, NULL, 8);
+ ent = sqfs_dir_entry_create("home/goliath/", S_IFDIR | 0750, 0);
+ TEST_NOT_NULL(ent);
+ ent->uid = 1000;
+ ent->gid = 1000;
+ ent->mtime = TIME_STAMP;
+ ret = write_tar_header(&mem_stream, ent, NULL, NULL, 8);
+ sqfs_free(ent);
TEST_EQUAL_I(ret, 0);
/* regular file with actual content */
- sb.st_mode = S_IFREG | 0644;
- sb.st_size = 14;
- ret = write_tar_header(&mem_stream, &sb, "home/goliath/hello.txt",
- NULL, NULL, 9);
+ ent = sqfs_dir_entry_create("home/goliath/hello.txt", S_IFREG | 0644, 0);
+ TEST_NOT_NULL(ent);
+ ent->uid = 1000;
+ ent->gid = 1000;
+ ent->mtime = TIME_STAMP;
+ ent->size = 14;
+ ret = write_tar_header(&mem_stream, ent, NULL, NULL, 9);
TEST_EQUAL_I(ret, 0);
ret = mem_stream.append(&mem_stream, "Hello, World!\n", 14);
@@ -146,17 +203,24 @@ int main(int argc, char **argv)
TEST_EQUAL_I(ret, 0);
/* hard link */
- ret = write_hard_link(&mem_stream, &sb, "home/goliath/world.txt",
- "home/goliath/hello.txt", 10);
+ strcpy(ent->name, "home/goliath/world.txt");
+ ent->size = 22;
+ ent->flags = SQFS_DIR_ENTRY_FLAG_HARD_LINK;
+ ret = write_tar_header(&mem_stream, ent, "home/goliath/hello.txt",
+ NULL, 10);
TEST_EQUAL_I(ret, 0);
/* something with xattrs */
+ strcpy(ent->name, "home/goliath/test.exe");
+ ent->flags = 0;
+ ent->mode = S_IFREG | 0750;
+ ent->size = 4;
+
xattr = mkxattr_chain();
- sb.st_mode = S_IFREG | 0750;
- sb.st_size = 4;
- ret = write_tar_header(&mem_stream, &sb, "home/goliath/test.exe",
- NULL, xattr, 11);
+
+ ret = write_tar_header(&mem_stream, ent, NULL, xattr, 11);
TEST_EQUAL_I(ret, 0);
+ sqfs_free(ent);
sqfs_xattr_list_free(xattr);
ret = mem_stream.append(&mem_stream, ":-)\n", 4);
@@ -165,15 +229,16 @@ int main(int argc, char **argv)
TEST_EQUAL_I(ret, 0);
/* now try something with a long name */
- memset(&sb, 0, sizeof(sb));
- sb.st_mode = S_IFREG | 0755;
- sb.st_mtime = TIME_STAMP;
- sb.st_size = 42;
- ret = write_tar_header(&mem_stream, &sb,
- "mnt/windows_drive/C/Documents and Settings/"
- "Joe Random User/My Documents/My Evil Plans/"
- "file format nonsense/really long name.doc",
- NULL, NULL, 12);
+ ent = sqfs_dir_entry_create("mnt/windows_drive/C/Documents and Settings/"
+ "Joe Random User/My Documents/My Evil Plans/"
+ "file format nonsense/really long name.doc",
+ S_IFREG | 0755, 0);
+ TEST_NOT_NULL(ent);
+ ent->mtime = TIME_STAMP;
+ ent->size = 42;
+
+ ret = write_tar_header(&mem_stream, ent, NULL, NULL, 12);
+ sqfs_free(ent);
TEST_EQUAL_I(ret, 0);
ret = mem_stream.append(&mem_stream,
@@ -184,7 +249,6 @@ int main(int argc, char **argv)
TEST_EQUAL_I(ret, 0);
/* compare with reference */
- TEST_EQUAL_UI(wr_offset, sizeof(wr_buffer));
TEST_EQUAL_UI(sizeof(rd_buffer), sizeof(wr_buffer));
ret = sqfs_istream_open_file(&fp,
@@ -202,7 +266,29 @@ int main(int argc, char **argv)
sqfs_drop(fp);
- ret = memcmp(wr_buffer, rd_buffer, sizeof(rd_buffer));
- TEST_EQUAL_I(ret, 0);
- return EXIT_SUCCESS;
+ if (wr_offset != sizeof(wr_buffer)) {
+ fprintf(stderr, "Result data size should be: %u, "
+ "but actually is: %u\n", (unsigned int)wr_offset,
+ (unsigned int)sizeof(wr_buffer));
+ ret = -1;
+ }
+
+ for (size_t i = 0; i < wr_offset; i += 512) {
+ size_t diff = (wr_offset - i) > 512 ? 512 : (wr_offset - i);
+
+ if (memcmp(wr_buffer + i, rd_buffer + i, diff) != 0) {
+ fprintf(stderr, "Difference at offset %u:\n",
+ (unsigned int)i);
+
+ fputs("Reference:\n", stderr);
+ hex_dump(rd_buffer + i, diff);
+
+ fputs("Result:\n", stderr);
+ hex_dump(wr_buffer + i, diff);
+ ret = -1;
+ break;
+ }
+ }
+
+ return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}