]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Properly remove leading slash letters and Windows drive letters in cpio.
authorMichihiro NAKAJIMA <ggcueroad@gmail.com>
Mon, 20 Feb 2012 07:51:40 +0000 (16:51 +0900)
committerMichihiro NAKAJIMA <ggcueroad@gmail.com>
Mon, 20 Feb 2012 20:24:51 +0000 (05:24 +0900)
cpio/cpio.c

index b3f631751acf2aeec7e39efe5f94945b1bda3d38..4f5b3f6b6328a4cec8ccb435f2e2ccf285890b5b 100644 (file)
@@ -119,6 +119,7 @@ static void mode_in(struct cpio *);
 static void    mode_list(struct cpio *);
 static void    mode_out(struct cpio *);
 static void    mode_pass(struct cpio *, const char *);
+static const char *remove_leading_slash(const char *);
 static int     restore_time(struct cpio *, struct archive_entry *,
                    const char *, int fd);
 static void    usage(void);
@@ -574,6 +575,49 @@ mode_out(struct cpio *cpio)
        archive_write_free(cpio->archive);
 }
 
+static const char *
+remove_leading_slash(const char *p)
+{
+       const char *rp;
+
+       /* Remove leading "//./" or "//?/" or "//?/UNC/"
+        * (absolute path prefixes used by Windows API) */
+       if ((p[0] == '/' || p[0] == '\\') &&
+           (p[1] == '/' || p[1] == '\\') &&
+           (p[2] == '.' || p[2] == '?') &&
+           (p[3] == '/' || p[3] == '\\'))
+       {
+               if (p[2] == '?' &&
+                   (p[4] == 'U' || p[4] == 'u') &&
+                   (p[5] == 'N' || p[5] == 'n') &&
+                   (p[6] == 'C' || p[6] == 'c') &&
+                   (p[7] == '/' || p[7] == '\\'))
+                       p += 8;
+               else
+                       p += 4;
+       }
+       do {
+               rp = p;
+               /* Remove leading drive letter from archives created
+                * on Windows. */
+               if (((p[0] >= 'a' && p[0] <= 'z') ||
+                    (p[0] >= 'A' && p[0] <= 'Z')) &&
+                        p[1] == ':') {
+                       p += 2;
+               }
+               /* Remove leading "/../", "//", etc. */
+               while (p[0] == '/' || p[0] == '\\') {
+                       if (p[1] == '.' && p[2] == '.' &&
+                               (p[3] == '/' || p[3] == '\\')) {
+                               p += 3; /* Remove "/..", leave "/"
+                                        * for next pass. */
+                       } else
+                               p += 1; /* Remove "/". */
+               }
+       } while (rp != p);
+       return (p);
+}
+
 /*
  * This is used by both out mode (to copy objects from disk into
  * an archive) and pass mode (to copy objects from disk to
@@ -585,7 +629,6 @@ file_to_archive(struct cpio *cpio, const char *srcpath)
        const char *destpath;
        struct archive_entry *entry, *spare;
        size_t len;
-       const char *p;
        int r;
 
        /*
@@ -639,10 +682,7 @@ file_to_archive(struct cpio *cpio, const char *srcpath)
                                    "Can't allocate path buffer");
                }
                strcpy(cpio->pass_destpath, cpio->destdir);
-               p = srcpath;
-               while (p[0] == '/')
-                       ++p;
-               strcat(cpio->pass_destpath, p);
+               strcat(cpio->pass_destpath, remove_leading_slash(srcpath));
                destpath = cpio->pass_destpath;
        }
        if (cpio->option_rename)