浏览代码

BUG: Fix mem leaks related to th_get_pathname. Change this implementation of th_get_pathname so that it *always* returns a strdup'ed value. Callers must now free non-NULL returns from th_get_pathname. Change all callers to call free appropriately.

David Cole 20 年之前
父节点
当前提交
0323a0d6d2
共有 4 个文件被更改,包括 286 次插入18 次删除
  1. 3 1
      Utilities/cmtar/decode.c
  2. 237 12
      Utilities/cmtar/extract.c
  3. 7 3
      Utilities/cmtar/output.c
  4. 39 2
      Utilities/cmtar/wrapper.c

+ 3 - 1
Utilities/cmtar/decode.c

@@ -31,13 +31,15 @@
 
 
 /* determine full path name */
+/* caller must "free" returned pointer when done with it */
+/* th_get_pathname return values come directly from strdup */
 char *
 th_get_pathname(TAR *t)
 {
   char filename[TAR_MAXPATHLEN];
 
   if (t->th_buf.gnu_longname)
-    return t->th_buf.gnu_longname;
+    return strdup(t->th_buf.gnu_longname);
 
   if (t->th_buf.prefix[0] != '\0')
   {

+ 237 - 12
Utilities/cmtar/extract.c

@@ -61,8 +61,18 @@ tar_set_file_perms(TAR *t, char *realname)
   gid_t gid;
   struct utimbuf ut;
   char *filename;
+  char *pathname = 0;
+
+  if (realname)
+    {
+    filename = realname;
+    }
+  else
+    {
+    pathname = th_get_pathname(t);
+    filename = pathname;
+    }
 
-  filename = (realname ? realname : th_get_pathname(t));
   mode = th_get_mode(t);
   uid = th_get_uid(t);
   gid = th_get_gid(t);
@@ -86,6 +96,10 @@ tar_set_file_perms(TAR *t, char *realname)
         filename, uid, gid, strerror(errno));
 # endif
 #endif /* HAVE_LCHOWN */
+    if (pathname)
+      {
+      free(pathname);
+      }
       return -1;
     }
 
@@ -95,6 +109,10 @@ tar_set_file_perms(TAR *t, char *realname)
 #ifdef DEBUG
     perror("utime()");
 #endif
+    if (pathname)
+      {
+      free(pathname);
+      }
     return -1;
   }
   /* change permissions */
@@ -103,6 +121,10 @@ tar_set_file_perms(TAR *t, char *realname)
 #ifdef DEBUG
     perror("chmod()");
 #endif
+    if (pathname)
+      {
+      free(pathname);
+      }
     return -1;
   }
 
@@ -113,6 +135,10 @@ tar_set_file_perms(TAR *t, char *realname)
   (void)mode;
 #endif /* WIN32 */
 
+  if (pathname)
+    {
+    free(pathname);
+    }
   return 0;
 }
 
@@ -123,6 +149,7 @@ tar_extract_file(TAR *t, char *realname)
 {
   int i;
   linkname_t *lnp;
+  char *pathname = 0;
 
   if (t->options & TAR_NOOVERWRITE)
   {
@@ -170,12 +197,17 @@ tar_extract_file(TAR *t, char *realname)
   lnp = (linkname_t *)calloc(1, sizeof(linkname_t));
   if (lnp == NULL)
     return -1;
-  strlcpy(lnp->ln_save, th_get_pathname(t), sizeof(lnp->ln_save));
+  pathname = th_get_pathname(t);
+  strlcpy(lnp->ln_save, pathname, sizeof(lnp->ln_save));
   strlcpy(lnp->ln_real, realname, sizeof(lnp->ln_real));
 #ifdef DEBUG
   printf("tar_extract_file(): calling libtar_hash_add(): key=\"%s\", "
-         "value=\"%s\"\n", th_get_pathname(t), realname);
+         "value=\"%s\"\n", pathname, realname);
 #endif
+  if (pathname)
+    {
+    free(pathname);
+    }
   if (libtar_hash_add(t->h, lnp) != 0)
     return -1;
 
@@ -195,6 +227,7 @@ tar_extract_regfile(TAR *t, char *realname)
   int i, k;
   char buf[T_BLOCKSIZE];
   char *filename;
+  char *pathname = 0;
 
 #ifdef DEBUG
   printf("==> tar_extract_regfile(t=0x%lx, realname=\"%s\")\n", t,
@@ -207,7 +240,15 @@ tar_extract_regfile(TAR *t, char *realname)
     return -1;
   }
 
-  filename = (realname ? realname : th_get_pathname(t));
+  if (realname)
+    {
+    filename = realname;
+    }
+  else
+    {
+    pathname = th_get_pathname(t);
+    filename = pathname;
+    }
   mode = th_get_mode(t);
   size = th_get_size(t);
   uid = th_get_uid(t);
@@ -220,6 +261,10 @@ tar_extract_regfile(TAR *t, char *realname)
 
   if (mkdirhier(dirname(buf)) == -1)
     {
+    if (pathname)
+      {
+      free(pathname);
+      }
     return -1;
     }
 
@@ -237,6 +282,10 @@ tar_extract_regfile(TAR *t, char *realname)
 #ifdef DEBUG
     perror("open()");
 #endif
+    if (pathname)
+      {
+      free(pathname);
+      }
     return -1;
   }
 
@@ -247,6 +296,10 @@ tar_extract_regfile(TAR *t, char *realname)
 #ifdef DEBUG
     perror("fchown()");
 #endif
+    if (pathname)
+      {
+      free(pathname);
+      }
     return -1;
   }
 
@@ -256,6 +309,10 @@ tar_extract_regfile(TAR *t, char *realname)
 #ifdef DEBUG
     perror("fchmod()");
 #endif
+    if (pathname)
+      {
+      free(pathname);
+      }
     return -1;
   }
 #endif
@@ -268,18 +325,34 @@ tar_extract_regfile(TAR *t, char *realname)
     {
       if (k != -1)
         errno = EINVAL;
+      if (pathname)
+        {
+        free(pathname);
+        }
       return -1;
     }
 
     /* write block to output file */
     if (write(fdout, buf,
         ((i > T_BLOCKSIZE) ? T_BLOCKSIZE : i)) == -1)
+      {
+      if (pathname)
+        {
+        free(pathname);
+        }
       return -1;
+      }
   }
 
   /* close output file */
   if (close(fdout) == -1)
+    {
+    if (pathname)
+      {
+      free(pathname);
+      }
     return -1;
+    }
 
 #ifdef DEBUG
   printf("### done extracting %s\n", filename);
@@ -290,6 +363,10 @@ tar_extract_regfile(TAR *t, char *realname)
   (void)uid;
   (void)mode;
 
+  if (pathname)
+    {
+    free(pathname);
+    }
   return 0;
 }
 
@@ -333,6 +410,7 @@ tar_extract_hardlink(TAR * t, char *realname)
   linkname_t *lnp;
   libtar_hashptr_t hp;
   char buf[T_BLOCKSIZE];
+  char *pathname = 0;
 
   if (!TH_ISLNK(t))
   {
@@ -340,7 +418,15 @@ tar_extract_hardlink(TAR * t, char *realname)
     return -1;
   }
 
-  filename = (realname ? realname : th_get_pathname(t));
+  if (realname)
+    {
+    filename = realname;
+    }
+  else
+    {
+    pathname = th_get_pathname(t);
+    filename = pathname;
+    }
 
   /* Make a copy of the string because dirname and mkdirhier may modify the
    * string */
@@ -348,7 +434,13 @@ tar_extract_hardlink(TAR * t, char *realname)
   buf[sizeof(buf)-1] = 0;
 
   if (mkdirhier(dirname(buf)) == -1)
+    {
+    if (pathname)
+      {
+      free(pathname);
+      }
     return -1;
+    }
   libtar_hashptr_reset(&hp);
   if (libtar_hash_getkey(t->h, &hp, th_get_linkname(t),
              (libtar_matchfunc_t)libtar_str_match) != 0)
@@ -371,9 +463,17 @@ tar_extract_hardlink(TAR * t, char *realname)
 #ifdef DEBUG
     perror("link()");
 #endif
+    if (pathname)
+      {
+      free(pathname);
+      }
     return -1;
   }
 
+  if (pathname)
+    {
+    free(pathname);
+    }
   return 0;
 }
 
@@ -384,6 +484,7 @@ tar_extract_symlink(TAR *t, char *realname)
 {
   char *filename;
   char buf[T_BLOCKSIZE];
+  char *pathname = 0;
 
 #ifndef _WIN32
   if (!TH_ISSYM(t))
@@ -393,7 +494,15 @@ tar_extract_symlink(TAR *t, char *realname)
   }
 #endif
 
-  filename = (realname ? realname : th_get_pathname(t));
+  if (realname)
+    {
+    filename = realname;
+    }
+  else
+    {
+    pathname = th_get_pathname(t);
+    filename = pathname;
+    }
 
   /* Make a copy of the string because dirname and mkdirhier may modify the
    * string */
@@ -401,10 +510,20 @@ tar_extract_symlink(TAR *t, char *realname)
   buf[sizeof(buf)-1] = 0;
 
   if (mkdirhier(dirname(buf)) == -1)
+    {
+    if (pathname)
+      {
+      free(pathname);
+      }
     return -1;
+    }
 
   if (unlink(filename) == -1 && errno != ENOENT)
     {
+    if (pathname)
+      {
+      free(pathname);
+      }
     return -1;
     }
 
@@ -419,9 +538,17 @@ tar_extract_symlink(TAR *t, char *realname)
 #ifdef DEBUG
     perror("symlink()");
 #endif
+    if (pathname)
+      {
+      free(pathname);
+      }
     return -1;
   }
 
+  if (pathname)
+    {
+    free(pathname);
+    }
   return 0;
 }
 
@@ -434,6 +561,7 @@ tar_extract_chardev(TAR *t, char *realname)
   unsigned long devmaj, devmin;
   char *filename;
   char buf[T_BLOCKSIZE];
+  char *pathname = 0;
 
 #ifndef _WIN32
   if (!TH_ISCHR(t))
@@ -442,7 +570,15 @@ tar_extract_chardev(TAR *t, char *realname)
     return -1;
   }
 #endif
-  filename = (realname ? realname : th_get_pathname(t));
+  if (realname)
+    {
+    filename = realname;
+    }
+  else
+    {
+    pathname = th_get_pathname(t);
+    filename = pathname;
+    }
   mode = th_get_mode(t);
   devmaj = th_get_devmajor(t);
   devmin = th_get_devminor(t);
@@ -453,7 +589,13 @@ tar_extract_chardev(TAR *t, char *realname)
   buf[sizeof(buf)-1] = 0;
 
   if (mkdirhier(dirname(buf)) == -1)
+    {
+    if (pathname)
+      {
+      free(pathname);
+      }
     return -1;
+    }
 
 #ifdef DEBUG
   printf("  ==> extracting: %s (character device %ld,%ld)\n",
@@ -471,9 +613,17 @@ tar_extract_chardev(TAR *t, char *realname)
 #ifdef DEBUG
     perror("mknod()");
 #endif
+    if (pathname)
+      {
+      free(pathname);
+      }
     return -1;
   }
 
+  if (pathname)
+    {
+    free(pathname);
+    }
   return 0;
 }
 
@@ -486,6 +636,7 @@ tar_extract_blockdev(TAR *t, char *realname)
   unsigned long devmaj, devmin;
   char *filename;
   char buf[T_BLOCKSIZE];
+  char *pathname = 0;
 
   if (!TH_ISBLK(t))
   {
@@ -493,7 +644,15 @@ tar_extract_blockdev(TAR *t, char *realname)
     return -1;
   }
 
-  filename = (realname ? realname : th_get_pathname(t));
+  if (realname)
+    {
+    filename = realname;
+    }
+  else
+    {
+    pathname = th_get_pathname(t);
+    filename = pathname;
+    }
   mode = th_get_mode(t);
   devmaj = th_get_devmajor(t);
   devmin = th_get_devminor(t);
@@ -504,7 +663,13 @@ tar_extract_blockdev(TAR *t, char *realname)
   buf[sizeof(buf)-1] = 0;
 
   if (mkdirhier(dirname(buf)) == -1)
+    {
+    if (pathname)
+      {
+      free(pathname);
+      }
     return -1;
+    }
 
 #ifdef DEBUG
   printf("  ==> extracting: %s (block device %ld,%ld)\n",
@@ -522,9 +687,17 @@ tar_extract_blockdev(TAR *t, char *realname)
 #ifdef DEBUG
     perror("mknod()");
 #endif
+    if (pathname)
+      {
+      free(pathname);
+      }
     return -1;
   }
 
+  if (pathname)
+    {
+    free(pathname);
+    }
   return 0;
 }
 
@@ -536,6 +709,7 @@ tar_extract_dir(TAR *t, char *realname)
   mode_t mode;
   char *filename;
   char buf[T_BLOCKSIZE];
+  char *pathname = 0;
 
   if (!TH_ISDIR(t))
   {
@@ -543,7 +717,15 @@ tar_extract_dir(TAR *t, char *realname)
     return -1;
   }
 
-  filename = (realname ? realname : th_get_pathname(t));
+  if (realname)
+    {
+    filename = realname;
+    }
+  else
+    {
+    pathname = th_get_pathname(t);
+    filename = pathname;
+    }
   mode = th_get_mode(t);
 
   /* Make a copy of the string because dirname and mkdirhier may modify the
@@ -552,7 +734,13 @@ tar_extract_dir(TAR *t, char *realname)
   buf[sizeof(buf)-1] = 0;
 
   if (mkdirhier(dirname(buf)) == -1)
+    {
+    if (pathname)
+      {
+      free(pathname);
+      }
     return -1;
+    }
 
 #ifdef DEBUG
   printf("  ==> extracting: %s (mode %04o, directory)\n", filename,
@@ -581,6 +769,10 @@ tar_extract_dir(TAR *t, char *realname)
 #ifdef DEBUG
         perror("chmod()");
 #endif
+        if (pathname)
+          {
+          free(pathname);
+          }
         return -1;
       }
       else
@@ -588,6 +780,10 @@ tar_extract_dir(TAR *t, char *realname)
 #ifdef DEBUG
         puts("  *** using existing directory");
 #endif
+        if (pathname)
+          {
+          free(pathname);
+          }
         return 1;
       }
     }
@@ -596,10 +792,18 @@ tar_extract_dir(TAR *t, char *realname)
 #ifdef DEBUG
       perror("mkdir()");
 #endif
+      if (pathname)
+        {
+        free(pathname);
+        }
       return -1;
     }
   }
 
+  if (pathname)
+    {
+    free(pathname);
+    }
   return 0;
 }
 
@@ -611,6 +815,7 @@ tar_extract_fifo(TAR *t, char *realname)
   mode_t mode;
   char *filename;
   char buf[T_BLOCKSIZE];
+  char *pathname = 0;
 
   if (!TH_ISFIFO(t))
   {
@@ -618,7 +823,15 @@ tar_extract_fifo(TAR *t, char *realname)
     return -1;
   }
 
-  filename = (realname ? realname : th_get_pathname(t));
+  if (realname)
+    {
+    filename = realname;
+    }
+  else
+    {
+    pathname = th_get_pathname(t);
+    filename = pathname;
+    }
   mode = th_get_mode(t);
 
   /* Make a copy of the string because dirname and mkdirhier may modify the
@@ -627,7 +840,13 @@ tar_extract_fifo(TAR *t, char *realname)
   buf[sizeof(buf)-1] = 0;
 
   if (mkdirhier(dirname(buf)) == -1)
+    {
+    if (pathname)
+      {
+      free(pathname);
+      }
     return -1;
+    }
 
 #ifdef DEBUG
   printf("  ==> extracting: %s (fifo)\n", filename);
@@ -641,10 +860,16 @@ tar_extract_fifo(TAR *t, char *realname)
 #ifdef DEBUG
     perror("mkfifo()");
 #endif
+    if (pathname)
+      {
+      free(pathname);
+      }
     return -1;
   }
 
+  if (pathname)
+    {
+    free(pathname);
+    }
   return 0;
 }
-
-

+ 7 - 3
Utilities/cmtar/output.c

@@ -76,6 +76,7 @@ th_print_long_ls(TAR *t)
   char groupname[_POSIX_LOGIN_NAME_MAX];
   time_t mtime;
   struct tm *mtm;
+  char *pathname = 0;
 
 #ifdef HAVE_STRFTIME
   char timebuf[18];
@@ -124,7 +125,12 @@ th_print_long_ls(TAR *t)
          mtm->tm_mday, mtm->tm_hour, mtm->tm_min, mtm->tm_year + 1900);
 #endif
 
-  printf(" %s", th_get_pathname(t));
+  pathname = th_get_pathname(t);
+  if (pathname)
+    {
+    printf(" %s", pathname);
+    free(pathname);
+    }
 
 #if !defined(_WIN32) || defined(__CYGWIN__)
   if (TH_ISSYM(t) || TH_ISLNK(t))
@@ -142,5 +148,3 @@ th_print_long_ls(TAR *t)
 
   putchar('\n');
 }
-
-

+ 39 - 2
Utilities/cmtar/wrapper.c

@@ -39,24 +39,49 @@ tar_extract_glob(TAR *t, char *globname, char *prefix)
   char *filename;
   char buf[TAR_MAXPATHLEN];
   int i;
+  char *pathname = 0;
 
   while ((i = th_read(t)) == 0)
   {
-    filename = th_get_pathname(t);
+    pathname = th_get_pathname(t);
+    filename = pathname;
+
     if (fnmatch(globname, filename, FNM_PATHNAME | FNM_PERIOD))
     {
+      if (pathname)
+        {
+        free(pathname);
+        pathname = 0;
+        }
+
       if (TH_ISREG(t) && tar_skip_regfile(t))
         return -1;
       continue;
     }
+
     if (t->options & TAR_VERBOSE)
       th_print_long_ls(t);
+
     if (prefix != NULL)
       snprintf(buf, sizeof(buf), "%s/%s", prefix, filename);
     else
       strlcpy(buf, filename, sizeof(buf));
+
     if (tar_extract_file(t, filename) != 0)
+      {
+      if (pathname)
+        {
+        free(pathname);
+        pathname = 0;
+        }
       return -1;
+      }
+
+    if (pathname)
+      {
+      free(pathname);
+      pathname = 0;
+      }
   }
 
   return (i == 1 ? 0 : -1);
@@ -69,6 +94,7 @@ tar_extract_all(TAR *t, char *prefix)
   char *filename;
   char buf[TAR_MAXPATHLEN];
   int i;
+  char *pathname = 0;
 
 #ifdef DEBUG
   printf("==> tar_extract_all(TAR *t, \"%s\")\n",
@@ -80,17 +106,28 @@ tar_extract_all(TAR *t, char *prefix)
 #ifdef DEBUG
     puts("    tar_extract_all(): calling th_get_pathname()");
 #endif
-    filename = th_get_pathname(t);
+
+    pathname = th_get_pathname(t);
+    filename = pathname;
+
     if (t->options & TAR_VERBOSE)
       th_print_long_ls(t);
     if (prefix != NULL)
       snprintf(buf, sizeof(buf), "%s/%s", prefix, filename);
     else
       strlcpy(buf, filename, sizeof(buf));
+
+    if (pathname)
+      {
+      free(pathname);
+      pathname = 0;
+      }
+
 #ifdef DEBUG
     printf("    tar_extract_all(): calling tar_extract_file(t, "
            "\"%s\")\n", buf);
 #endif
+
     if (tar_extract_file(t, buf) != 0)
       return -1;
   }