From 4551f5f0dbb4971633c8aeae3d29a7437da5316d Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Tue, 26 Nov 2019 08:07:55 +0100 Subject: untar: Properly make parent path Close #3823. --- cpukit/libmisc/untar/untar.c | 190 +++++---------------- testsuites/libtests/Makefile.am | 8 +- testsuites/libtests/tar01/home/abc/def/test_script | 2 + testsuites/libtests/tar01/home/test_script | 2 - testsuites/libtests/tar01/init.c | 30 ++-- 5 files changed, 67 insertions(+), 165 deletions(-) create mode 100755 testsuites/libtests/tar01/home/abc/def/test_script delete mode 100755 testsuites/libtests/tar01/home/test_script diff --git a/cpukit/libmisc/untar/untar.c b/cpukit/libmisc/untar/untar.c index ec4a5479cd..a2f09fb99f 100644 --- a/cpukit/libmisc/untar/untar.c +++ b/cpukit/libmisc/untar/untar.c @@ -1,14 +1,9 @@ /** * @file - + * * @brief Untar an Image + * * @ingroup libmisc_untar_img Untar Image - - * FIXME: - * 1. Symbolic links are not created. - * 2. Untar_FromMemory uses FILE *fp. - * 3. How to determine end of archive? - */ /* @@ -105,143 +100,61 @@ Print_Error(const rtems_printer *printer, const char* message, const char* path) message, path, errno, strerror(errno)); } -/* - * Get the type of node on in the file system if present. - */ -static int -Stat_Node(const char* path) -{ - struct stat sb; - if (stat(path, &sb) < 0) - return -1; - if (S_ISDIR(sb.st_mode)) - return DIRTYPE; - return REGTYPE; -} - /* * Make the directory path for a file if it does not exist. */ static int -Make_Path(const rtems_printer *printer, const char* filename, int linktype) +Make_Path(const rtems_printer *printer, char *path) { - char* copy = strdup(filename); - char* path = copy; + char *p; /* * Skip leading path separators. */ - while (*path == '/') + while (*path == '/') { ++path; + } - /* - * Any path left? - */ - if (*path != '\0') { - bool path_end = false; - char* end = path; - int r; - - /* - * Split the path into directory components. Check the node and if a file - * and not the end of the path remove it and create a directory. If a - * directory and not the end of the path decend into the directory. - */ - while (!path_end) { - while (*end != '\0' && *end != '/') - ++end; - - /* - * Are we at the end of the path? - */ - if (*end == '\0') - path_end = true; + p = path; - /* - * Split the path. - */ - *end = '\0'; + for (; ; ++p) { + if (p[0] == '\0') { + return 0; + } else if (p[0] != '/') { + continue; + } - /* - * Get the node's status, exists, error, directory or regular? Regular - * means not a directory. - */ - r = Stat_Node(path); + *p = '\0'; + if (p[1] == '\0') { + /* Speculatively unlink the last component so that it can be re-created */ + unlink(path); + return 0; + } - /* - * If there are errors other than not existing we are finished. - */ - if (r < 0 && errno != ENOENT) { - Print_Error(printer, "stat", path); - return -1; - } + if (mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO) != 0) { + if (errno == EEXIST || errno == EISDIR) { + struct stat sb; - /* - * If a file remove and create a directory if not the end. - */ - if (r == REGTYPE) { - r = unlink(path); - if (r < 0) { - Print_Error(printer, "unlink", path); - free(copy); + if (stat(path, &sb) != 0) { return -1; } - if (!path_end) { - r = mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO); - if (r < 0) { - Print_Error(printer, "mkdir (unlink)", path); - free(copy); + + if (!S_ISDIR(sb.st_mode)) { + if (unlink(path) != 0) { + Print_Error(printer, "unlink", path); return -1; } - } - } - else if (r < 0) { - /* - * Node does not exist which means the rest of the path will not exist. - */ - while (!path_end) { - r = mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO); - if (r < 0) { - Print_Error(printer, "mkdir", path); - free(copy); + + if (mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO) != 0) { + Print_Error(printer, "mkdir (unlink)", path); return -1; } - if (!path_end) { - *end = '/'; - ++end; - } - while (*end != '\0' && *end != '/') - ++end; - if (*end == '\0') - path_end = true; - } - } - else if (path_end && r == DIRTYPE && linktype != DIRTYPE) { - /* - * We only handle a directory if at the end of the path and the end is - * a file. If we cannot remove the directory because it is not empty we - * raise an error. Otherwise this is a directory and we do nothing - * which lets us decend into it. - */ - r = rmdir(path); - if (r < 0) { - Print_Error(printer, "rmdir", path); - free(copy); - return -1; } } - - /* - * If not the end of the path put back the directory separator. - */ - if (!path_end) { - *end = '/'; - ++end; - } } - } - free(copy); + *p = '/'; + } return 0; } @@ -252,9 +165,10 @@ Untar_ProcessHeader( const char *bufr ) { - int sum; - int hdr_chksum; - int retval = UNTAR_SUCCESSFUL; + int sum; + int hdr_chksum; + int retval = UNTAR_SUCCESSFUL; + int r; ctx->file_name[0] = '\0'; ctx->file_size = 0; @@ -290,7 +204,7 @@ Untar_ProcessHeader( * with it. */ - if (Make_Path(ctx->printer, ctx->file_path, ctx->linkflag) < 0) { + if (Make_Path(ctx->printer, ctx->file_path) != 0) { retval = UNTAR_FAIL; } @@ -298,33 +212,21 @@ Untar_ProcessHeader( strlcpy(ctx->link_name, &bufr[157], sizeof(ctx->link_name)); rtems_printf(ctx->printer, "untar: symlink: %s -> %s\n", ctx->link_name, ctx->file_path); - symlink(ctx->link_name, ctx->file_path); + r = symlink(ctx->link_name, ctx->file_path); + if (r != 0) { + Print_Error(ctx->printer, "symlink", ctx->file_path); + retval = UNTAR_FAIL; + } } else if (ctx->linkflag == REGTYPE) { rtems_printf(ctx->printer, "untar: file: %s (s:%lu,m:%04lo)\n", ctx->file_path, ctx->file_size, ctx->mode); ctx->nblocks = (((ctx->file_size) + 511) & ~511) / 512; } else if (ctx->linkflag == DIRTYPE) { - int r; rtems_printf(ctx->printer, "untar: dir: %s\n", ctx->file_path); - r = mkdir(ctx->file_path, S_IRWXU | S_IRWXG | S_IRWXO); - if (r < 0) { - if (errno == EEXIST) { - struct stat stat_buf; - if (stat(ctx->file_path, &stat_buf) == 0) { - if (S_ISDIR(stat_buf.st_mode)) { - r = 0; - } else { - r = unlink(ctx->file_path); - if (r == 0) { - r = mkdir(ctx->file_path, ctx->mode); - } - } - } - } - if (r < 0) { - Print_Error(ctx->printer, "mkdir", ctx->file_path); - retval = UNTAR_FAIL; - } + r = mkdir(ctx->file_path, ctx->mode); + if (r != 0) { + Print_Error(ctx->printer, "mkdir", ctx->file_path); + retval = UNTAR_FAIL; } } diff --git a/testsuites/libtests/Makefile.am b/testsuites/libtests/Makefile.am index 9af8098062..a22e153c30 100644 --- a/testsuites/libtests/Makefile.am +++ b/testsuites/libtests/Makefile.am @@ -1288,9 +1288,9 @@ endif tar01_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_FLAGS_tar01) \ $(support_includes) $(test_includes) -I$(top_srcdir)/include tar01_LDADD = $(RTEMS_ROOT)cpukit/librtemscpu.a $(RTEMS_ROOT)cpukit/libz.a $(LDADD) -tar01.tar: Makefile +tar01.tar: $(srcdir)/tar01/home/test_file $(srcdir)/tar01/home/abc/def/test_script $(srcdir)/tar01/symlink @rm -f $@ - $(AM_V_GEN)$(PAX) -w -f $@ -s ,$(srcdir)/tar01/,, $(srcdir)/tar01/home $(srcdir)/tar01/symlink + $(AM_V_GEN)$(PAX) -w -f $@ -s ,$(srcdir)/tar01/,, $+ tar01-tar.c: tar01.tar $(AM_V_GEN)$(BIN2C) -C $< $@ tar01-tar.h: tar01.tar @@ -1327,9 +1327,9 @@ tar02_SOURCES = tar02/init.c ../psxtests/psxfile01/test_cat.c \ tar02-tar.c tar02-tar.h tar02_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_FLAGS_tar02) \ $(support_includes) $(test_includes) -I$(top_srcdir)/include -tar02.tar: Makefile +tar02.tar: $(srcdir)/tar01/home/test_file $(srcdir)/tar01/home/abc/def/test_script $(srcdir)/tar01/symlink @rm -f $@ - $(AM_V_GEN)$(PAX) -w -f $@ -s ,$(srcdir)/tar01/,, $(srcdir)/tar01/home $(srcdir)/tar01/symlink + $(AM_V_GEN)$(PAX) -w -f $@ -s ,$(srcdir)/tar01/,, $+ tar02-tar.c: tar02.tar $(AM_V_GEN)$(BIN2C) -C $< $@ tar02-tar.h: tar02.tar diff --git a/testsuites/libtests/tar01/home/abc/def/test_script b/testsuites/libtests/tar01/home/abc/def/test_script new file mode 100755 index 0000000000..884924820b --- /dev/null +++ b/testsuites/libtests/tar01/home/abc/def/test_script @@ -0,0 +1,2 @@ +#! joel +ls -las /dev diff --git a/testsuites/libtests/tar01/home/test_script b/testsuites/libtests/tar01/home/test_script deleted file mode 100755 index 884924820b..0000000000 --- a/testsuites/libtests/tar01/home/test_script +++ /dev/null @@ -1,2 +0,0 @@ -#! joel -ls -las /dev diff --git a/testsuites/libtests/tar01/init.c b/testsuites/libtests/tar01/init.c index 8891911288..371ea71920 100644 --- a/testsuites/libtests/tar01/init.c +++ b/testsuites/libtests/tar01/init.c @@ -85,9 +85,9 @@ void test_untar_from_memory(void) test_cat( "/home/test_file", 0, 0 ); /******************/ - printf( "========= /home/test_script =========\n" ); - test_cat( "/home/test_script", 0, 0 ); - test_untar_check_mode("/home/test_script", 0755); + printf( "========= /home/abc/def/test_script =========\n" ); + test_cat( "/home/abc/def/test_script", 0, 0 ); + test_untar_check_mode("/home/abc/def/test_script", 0755); /******************/ printf( "========= /symlink =========\n" ); @@ -133,9 +133,9 @@ void test_untar_from_file(void) test_cat( "/dest/home/test_file", 0, 0 ); /******************/ - printf( "========= /dest/home/test_script =========\n" ); - test_cat( "/dest/home/test_script", 0, 0 ); - test_untar_check_mode("/dest/home/test_script", 0755); + printf( "========= /dest/home/abc/def/test_script =========\n" ); + test_cat( "/dest/home/abc/def/test_script", 0, 0 ); + test_untar_check_mode("/dest/home/abc/def/test_script", 0755); /******************/ printf( "========= /dest/symlink =========\n" ); @@ -179,9 +179,9 @@ void test_untar_chunks_from_memory(void) test_cat( "/dest2/home/test_file", 0, 0 ); /******************/ - printf( "========= /dest2/home/test_script =========\n" ); - test_cat( "/dest2/home/test_script", 0, 0 ); - test_untar_check_mode("/dest2/home/test_script", 0755); + printf( "========= /dest2/home/abc/def/test_script =========\n" ); + test_cat( "/dest2/home/abc/def/test_script", 0, 0 ); + test_untar_check_mode("/dest2/home/abc/def/test_script", 0755); /******************/ printf( "========= /dest2/symlink =========\n" ); @@ -225,9 +225,9 @@ void test_untar_unzip_tgz(void) test_cat( "/dest3/home/test_file", 0, 0 ); /******************/ - printf( "========= /dest3/home/test_script =========\n" ); - test_cat( "/dest3/home/test_script", 0, 0 ); - test_untar_check_mode("/dest3/home/test_script", 0755); + printf( "========= /dest3/home/abc/def/test_script =========\n" ); + test_cat( "/dest3/home/abc/def/test_script", 0, 0 ); + test_untar_check_mode("/dest3/home/abc/def/test_script", 0755); /******************/ printf( "========= /dest3/symlink =========\n" ); @@ -275,9 +275,9 @@ void test_untar_unzip_txz(void) test_cat( "/dest4/home/test_file", 0, 0 ); /******************/ - printf( "========= /dest4/home/test_script =========\n" ); - test_cat( "/dest4/home/test_script", 0, 0 ); - test_untar_check_mode("/dest4/home/test_script", 0755); + printf( "========= /dest4/home/abc/def/test_script =========\n" ); + test_cat( "/dest4/home/abc/def/test_script", 0, 0 ); + test_untar_check_mode("/dest4/home/abc/def/test_script", 0755); /******************/ printf( "========= /dest4/symlink =========\n" ); -- cgit v1.2.3