Magellan Linux

Diff of /trunk/mkinitrd-magellan/busybox/archival/libunarchive/get_header_tar.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 983 by niro, Fri Apr 24 18:33:46 2009 UTC revision 984 by niro, Sun May 30 11:32:42 2010 UTC
# Line 14  Line 14 
14  #include "libbb.h"  #include "libbb.h"
15  #include "unarchive.h"  #include "unarchive.h"
16    
17    /*
18     * GNU tar uses "base-256 encoding" for very large numbers (>8 billion).
19     * Encoding is binary, with highest bit always set as a marker
20     * and sign in next-highest bit:
21     * 80 00 .. 00 - zero
22     * bf ff .. ff - largest positive number
23     * ff ff .. ff - minus 1
24     * c0 00 .. 00 - smallest negative number
25     *
26     * We expect it only in size field, where negative numbers don't make sense.
27     */
28    static off_t getBase256_len12(const char *str)
29    {
30     off_t value;
31     int len;
32    
33     /* if (*str & 0x40) error; - caller prevents this */
34    
35     if (sizeof(off_t) >= 12) {
36     /* Probably 128-bit (16 byte) off_t. Can be optimized. */
37     len = 12;
38     value = *str++ & 0x3f;
39     while (--len)
40     value = (value << 8) + (unsigned char) *str++;
41     return value;
42     }
43    
44    #ifdef CHECK_FOR_OVERFLOW
45     /* Can be optimized to eat 32-bit chunks */
46     char c = *str++ & 0x3f;
47     len = 12;
48     while (1) {
49     if (c)
50     bb_error_msg_and_die("overflow in base-256 encoded file size");
51     if (--len == sizeof(off_t))
52     break;
53     c = *str++;
54     }
55    #else
56     str += (12 - sizeof(off_t));
57    #endif
58    
59    /* Now str points to sizeof(off_t) least significant bytes.
60     *
61     * Example of tar file with 8914993153 (0x213600001) byte file.
62     * Field starts at offset 7c:
63     * 00070  30 30 30 00 30 30 30 30  30 30 30 00 80 00 00 00  |000.0000000.....|
64     * 00080  00 00 00 02 13 60 00 01  31 31 31 32 30 33 33 36  |.....`..11120336|
65     *
66     * str is at offset 80 or 84 now (64-bit or 32-bit off_t).
67     * We (ab)use the fact that value happens to be aligned,
68     * and fetch it in one go:
69     */
70     if (sizeof(off_t) == 8) {
71     value = *(off_t*)str;
72     value = SWAP_BE64(value);
73     } else if (sizeof(off_t) == 4) {
74     value = *(off_t*)str;
75     value = SWAP_BE32(value);
76     } else {
77     value = 0;
78     len = sizeof(off_t);
79     while (--len)
80     value = (value << 8) + (unsigned char) *str++;
81     }
82     return value;
83    }
84    
85  /* NB: _DESTROYS_ str[len] character! */  /* NB: _DESTROYS_ str[len] character! */
86  static unsigned long long getOctal(char *str, int len)  static unsigned long long getOctal(char *str, int len)
87  {  {
88   unsigned long long v;   unsigned long long v;
89   /* NB: leading spaces are allowed. Using strtoull to handle that.   /* NB: leading spaces are allowed. Using strtoull to handle that.
90   * The downside is that we accept e.g. "-123" too :)   * The downside is that we accept e.g. "-123" too :(
91   */   */
92   str[len] = '\0';   str[len] = '\0';
93   v = strtoull(str, &str, 8);   v = strtoull(str, &str, 8);
94   if (*str && (!ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY || *str != ' '))   /* std: "Each numeric field is terminated by one or more
95     * <space> or NUL characters". We must support ' '! */
96     if (*str != '\0' && *str != ' ')
97   bb_error_msg_and_die("corrupted octal value in tar header");   bb_error_msg_and_die("corrupted octal value in tar header");
98   return v;   return v;
99  }  }
# Line 65  char FAST_FUNC get_header_tar(archive_ha Line 135  char FAST_FUNC get_header_tar(archive_ha
135   int parse_names;   int parse_names;
136    
137   /* Our "private data" */   /* Our "private data" */
 #define p_end (*(smallint *)(&archive_handle->ah_priv[0]))  
138  #if ENABLE_FEATURE_TAR_GNU_EXTENSIONS  #if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
139  #define p_longname (*(char* *)(&archive_handle->ah_priv[1]))  # define p_longname (archive_handle->tar__longname)
140  #define p_linkname (*(char* *)(&archive_handle->ah_priv[2]))  # define p_linkname (archive_handle->tar__linkname)
141  #else  #else
142  #define p_longname 0  # define p_longname 0
143  #define p_linkname 0  # define p_linkname 0
144  #endif  #endif
 // if (!archive_handle->ah_priv_inited) {  
 // archive_handle->ah_priv_inited = 1;  
 // p_end = 0;  
 // USE_FEATURE_TAR_GNU_EXTENSIONS(p_longname = NULL;)  
 // USE_FEATURE_TAR_GNU_EXTENSIONS(p_linkname = NULL;)  
 // }  
145    
146   if (sizeof(tar) != 512)   if (sizeof(tar) != 512)
147   BUG_tar_header_size();   BUG_tar_header_size();
# Line 108  char FAST_FUNC get_header_tar(archive_ha Line 171  char FAST_FUNC get_header_tar(archive_ha
171   bb_error_msg_and_die("short read");   bb_error_msg_and_die("short read");
172   }   }
173   if (i != 512) {   if (i != 512) {
174   USE_FEATURE_TAR_AUTODETECT(goto autodetect;)   IF_FEATURE_TAR_AUTODETECT(goto autodetect;)
175   goto short_read;   goto short_read;
176   }   }
177    
# Line 120  char FAST_FUNC get_header_tar(archive_ha Line 183  char FAST_FUNC get_header_tar(archive_ha
183    
184   /* If there is no filename its an empty header */   /* If there is no filename its an empty header */
185   if (tar.name[0] == 0 && tar.prefix[0] == 0) {   if (tar.name[0] == 0 && tar.prefix[0] == 0) {
186   if (p_end) {   if (archive_handle->tar__end) {
187   /* Second consecutive empty header - end of archive.   /* Second consecutive empty header - end of archive.
188   * Read until the end to empty the pipe from gz or bz2   * Read until the end to empty the pipe from gz or bz2
189   */   */
# Line 128  char FAST_FUNC get_header_tar(archive_ha Line 191  char FAST_FUNC get_header_tar(archive_ha
191   continue;   continue;
192   return EXIT_FAILURE;   return EXIT_FAILURE;
193   }   }
194   p_end = 1;   archive_handle->tar__end = 1;
195   return EXIT_SUCCESS;   return EXIT_SUCCESS;
196   }   }
197   p_end = 0;   archive_handle->tar__end = 0;
198    
199   /* Check header has valid magic, "ustar" is for the proper tar,   /* Check header has valid magic, "ustar" is for the proper tar,
200   * five NULs are for the old tar format  */   * five NULs are for the old tar format  */
# Line 194  char FAST_FUNC get_header_tar(archive_ha Line 257  char FAST_FUNC get_header_tar(archive_ha
257   sum_s += ((signed char*)&tar)[i];   sum_s += ((signed char*)&tar)[i];
258  #endif  #endif
259   }   }
 #if ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY  
  sum = strtoul(tar.chksum, &cp, 8);  
  if ((*cp && *cp != ' ')  
  || (sum_u != sum USE_FEATURE_TAR_OLDSUN_COMPATIBILITY(&& sum_s != sum))  
  ) {  
  bb_error_msg_and_die("invalid tar header checksum");  
  }  
 #else  
260   /* This field does not need special treatment (getOctal) */   /* This field does not need special treatment (getOctal) */
261   sum = xstrtoul(tar.chksum, 8);   {
262   if (sum_u != sum USE_FEATURE_TAR_OLDSUN_COMPATIBILITY(&& sum_s != sum)) {   char *endp; /* gcc likes temp var for &endp */
263     sum = strtoul(tar.chksum, &endp, 8);
264     if ((*endp != '\0' && *endp != ' ')
265     || (sum_u != sum IF_FEATURE_TAR_OLDSUN_COMPATIBILITY(&& sum_s != sum))
266     ) {
267     bb_error_msg_and_die("invalid tar header checksum");
268     }
269     }
270     /* don't use xstrtoul, tar.chksum may have leading spaces */
271     sum = strtoul(tar.chksum, NULL, 8);
272     if (sum_u != sum IF_FEATURE_TAR_OLDSUN_COMPATIBILITY(&& sum_s != sum)) {
273   bb_error_msg_and_die("invalid tar header checksum");   bb_error_msg_and_die("invalid tar header checksum");
274   }   }
 #endif  
275    
276   /* 0 is reserved for high perf file, treat as normal file */   /* 0 is reserved for high perf file, treat as normal file */
277   if (!tar.typeflag) tar.typeflag = '0';   if (!tar.typeflag) tar.typeflag = '0';
# Line 230  char FAST_FUNC get_header_tar(archive_ha Line 294  char FAST_FUNC get_header_tar(archive_ha
294   /* Will link_target be free()ed? */   /* Will link_target be free()ed? */
295   }   }
296  #if ENABLE_FEATURE_TAR_UNAME_GNAME  #if ENABLE_FEATURE_TAR_UNAME_GNAME
297   file_header->uname = tar.uname[0] ? xstrndup(tar.uname, sizeof(tar.uname)) : NULL;   file_header->tar__uname = tar.uname[0] ? xstrndup(tar.uname, sizeof(tar.uname)) : NULL;
298   file_header->gname = tar.gname[0] ? xstrndup(tar.gname, sizeof(tar.gname)) : NULL;   file_header->tar__gname = tar.gname[0] ? xstrndup(tar.gname, sizeof(tar.gname)) : NULL;
299  #endif  #endif
300   file_header->mtime = GET_OCTAL(tar.mtime);   /* mtime: rudimentally handle GNU tar's "base256 encoding"
301   file_header->size = GET_OCTAL(tar.size);   * People report tarballs with NEGATIVE unix times encoded that way */
302     file_header->mtime = (tar.mtime[0] & 0x80) /* base256? */
303     ? 0 /* bogus */
304     : GET_OCTAL(tar.mtime);
305     /* size: handle GNU tar's "base256 encoding" */
306     file_header->size = (tar.size[0] & 0xc0) == 0x80 /* positive base256? */
307     ? getBase256_len12(tar.size)
308     : GET_OCTAL(tar.size);
309   file_header->gid = GET_OCTAL(tar.gid);   file_header->gid = GET_OCTAL(tar.gid);
310   file_header->uid = GET_OCTAL(tar.uid);   file_header->uid = GET_OCTAL(tar.uid);
311   /* Set bits 0-11 of the files mode */   /* Set bits 0-11 of the files mode */
# Line 285  char FAST_FUNC get_header_tar(archive_ha Line 356  char FAST_FUNC get_header_tar(archive_ha
356   file_header->mode |= S_IFBLK;   file_header->mode |= S_IFBLK;
357   goto size0;   goto size0;
358   case '5':   case '5':
359   USE_FEATURE_TAR_OLDGNU_COMPATIBILITY(set_dir:)   IF_FEATURE_TAR_OLDGNU_COMPATIBILITY(set_dir:)
360   file_header->mode |= S_IFDIR;   file_header->mode |= S_IFDIR;
361   goto size0;   goto size0;
362   case '6':   case '6':
# Line 371  char FAST_FUNC get_header_tar(archive_ha Line 442  char FAST_FUNC get_header_tar(archive_ha
442   free(file_header->link_target);   free(file_header->link_target);
443   /* Do not free(file_header->name)! (why?) */   /* Do not free(file_header->name)! (why?) */
444  #if ENABLE_FEATURE_TAR_UNAME_GNAME  #if ENABLE_FEATURE_TAR_UNAME_GNAME
445   free(file_header->uname);   free(file_header->tar__uname);
446   free(file_header->gname);   free(file_header->tar__gname);
447  #endif  #endif
448   return EXIT_SUCCESS;   return EXIT_SUCCESS;
449  }  }

Legend:
Removed from v.983  
changed lines
  Added in v.984