[rtems commit] untar: Properly make parent path

Sebastian Huber sebh at rtems.org
Tue Nov 26 07:34:53 UTC 2019


Module:    rtems
Branch:    master
Commit:    4551f5f0dbb4971633c8aeae3d29a7437da5316d
Changeset: http://git.rtems.org/rtems/commit/?id=4551f5f0dbb4971633c8aeae3d29a7437da5316d

Author:    Sebastian Huber <sebastian.huber at embedded-brains.de>
Date:      Tue Nov 26 08:07:55 2019 +0100

untar: Properly make parent path

Close #3823.

---

 cpukit/libmisc/untar/untar.c                       | 190 +++++----------------
 testsuites/libtests/Makefile.am                    |   8 +-
 .../libtests/tar01/home/{ => abc/def}/test_script  |   0
 testsuites/libtests/tar01/init.c                   |  30 ++--
 4 files changed, 65 insertions(+), 163 deletions(-)

diff --git a/cpukit/libmisc/untar/untar.c b/cpukit/libmisc/untar/untar.c
index ec4a547..a2f09fb 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?
-
  */
 
 /*
@@ -106,142 +101,60 @@ Print_Error(const rtems_printer *printer, const char* message, const char* path)
 }
 
 /*
- * 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 9af8098..a22e153 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/test_script b/testsuites/libtests/tar01/home/abc/def/test_script
similarity index 100%
rename from testsuites/libtests/tar01/home/test_script
rename to testsuites/libtests/tar01/home/abc/def/test_script
diff --git a/testsuites/libtests/tar01/init.c b/testsuites/libtests/tar01/init.c
index 8891911..371ea71 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" );



More information about the vc mailing list