source: rtems/cpukit/libmisc/untar/untar.c @ 738a9ae

4.104.114.84.95
Last change on this file since 738a9ae was 3160ff6, checked in by Joel Sherrill <joel.sherrill@…>, on 09/04/03 at 18:54:19

2003-09-04 Joel Sherrill <joel@…>

  • cpuuse/cpuuse.c, cpuuse/cpuuse.h, devnull/devnull.c, devnull/devnull.h, dummy/dummy.c, dumpbuf/dumpbuf.c, dumpbuf/dumpbuf.h, fsmount/fsmount.c, fsmount/fsmount.h, serdbg/serdbgio.c, serdbg/termios_printk.c, stackchk/check.c, stackchk/internal.h, stackchk/stackchk.h, untar/untar.c, untar/untar.h: URL for license changed.
  • Property mode set to 100644
File size: 13.0 KB
Line 
1/* FIXME:
2 *   1. Symbolic links are not created.
3 *   2. Untar_FromMemory has printfs.
4 *   3. Untar_FromMemory uses FILE *fp.
5 *   4. How to determine end of archive?
6 *
7 *  Written by: Jake Janovetz <janovetz@tempest.ece.uiuc.edu>
8 *
9 *  The license and distribution terms for this file may be
10 *  found in the file LICENSE in this distribution or at
11 *  http://www.rtems.com/license/LICENSE.
12 *
13 *  $Id$
14 */
15
16#ifdef HAVE_CONFIG_H
17#include "config.h"
18#endif
19
20#include <stdio.h>
21#include <string.h>
22#include <stdlib.h>
23#include <unistd.h>
24#include <sys/stat.h>
25#include <fcntl.h>
26#include "untar.h"
27
28
29/**************************************************************************
30 * TAR file format:
31 *
32 *   Offset   Length   Contents
33 *     0    100 bytes  File name ('\0' terminated, 99 maxmum length)
34 *   100      8 bytes  File mode (in octal ascii)
35 *   108      8 bytes  User ID (in octal ascii)
36 *   116      8 bytes  Group ID (in octal ascii)
37 *   124     12 bytes  File size (s) (in octal ascii)
38 *   136     12 bytes  Modify time (in octal ascii)
39 *   148      8 bytes  Header checksum (in octal ascii)
40 *   156      1 bytes  Link flag
41 *   157    100 bytes  Linkname ('\0' terminated, 99 maxmum length)
42 *   257      8 bytes  Magic ("ustar  \0")
43 *   265     32 bytes  User name ('\0' terminated, 31 maxmum length)
44 *   297     32 bytes  Group name ('\0' terminated, 31 maxmum length)
45 *   329      8 bytes  Major device ID (in octal ascii)
46 *   337      8 bytes  Minor device ID (in octal ascii)
47 *   345    167 bytes  Padding
48 *   512   (s+p)bytes  File contents (s+p) := (((s) + 511) & ~511),
49 *                     round up to 512 bytes
50 *
51 *   Checksum:
52 *   int i, sum;
53 *   char* header = tar_header_pointer;
54 *   sum = 0;
55 *   for(i = 0; i < 512; i++)
56 *       sum += 0xFF & header[i];
57 *************************************************************************/
58
59#define LF_OLDNORMAL  '\0'     /* Normal disk file, Unix compatible */
60#define LF_NORMAL     '0'      /* Normal disk file                  */
61#define LF_LINK       '1'      /* Link to previously dumped file    */
62#define LF_SYMLINK    '2'      /* Symbolic link                     */
63#define LF_CHR        '3'      /* Character special file            */
64#define LF_BLK        '4'      /* Block special file                */
65#define LF_DIR        '5'      /* Directory                         */
66#define LF_FIFO       '6'      /* FIFO special file                 */
67#define LF_CONFIG     '7'      /* Contiguous file                   */
68
69#define MAX_NAME_FIELD_SIZE      99
70
71#define MIN(a,b)   ((a)>(b)?(b):(a))
72
73
74/**************************************************************************
75 * This converts octal ASCII number representations into an
76 * unsigned long.  Only support 32-bit numbers for now.
77 *************************************************************************/
78static unsigned long
79octal2ulong(char *octascii, int len)
80{
81   int           i;
82   unsigned long num;
83   unsigned long mult;
84
85   num = 0;
86   mult = 1;
87   for (i=len-1; i>=0; i--)
88   {
89      if ((octascii[i] < '0') || (octascii[i] > '9'))
90      {
91         continue;
92      }
93      num  += mult*((unsigned long)(octascii[i] - '0'));
94      mult *= 8;
95   }
96   return(num);
97}
98
99
100/**************************************************************************
101 * Function: Untar_FromMemory                                             *
102 **************************************************************************
103 * Description:                                                           *
104 *                                                                        *
105 *    This is a simple subroutine used to rip links, directories, and     *
106 *    files out of a block of memory.                                     *
107 *                                                                        *
108 *                                                                        *
109 * Inputs:                                                                *
110 *                                                                        *
111 *    unsigned char *tar_buf    - Pointer to TAR buffer.                  *
112 *    unsigned long size        - Length of TAR buffer.                   *
113 *                                                                        *
114 *                                                                        *
115 * Output:                                                                *
116 *                                                                        *
117 *    int - UNTAR_SUCCESSFUL (0)    on successful completion.             *
118 *          UNTAR_INVALID_CHECKSUM  for an invalid header checksum.       *
119 *          UNTAR_INVALID_HEADER    for an invalid header.                *
120 *                                                                        *
121 **************************************************************************
122 * Change History:                                                        *
123 *  12/30/1998 - Creation (JWJ)                                           *
124 *************************************************************************/
125int
126Untar_FromMemory(unsigned char *tar_buf, unsigned long size)
127{
128   FILE           *fp;
129   char           *bufr;
130   size_t         n;
131   char           fname[100];
132   char           linkname[100];
133   int            sum;
134   int            hdr_chksum;
135   int            retval;
136   unsigned long  ptr;
137   unsigned long  i;
138   unsigned long  nblocks;
139   unsigned long  file_size;
140   unsigned char  linkflag;
141
142
143   ptr = 0;
144   while (1)
145   {
146      if (ptr + 512 > size)
147      {
148         retval = UNTAR_SUCCESSFUL;
149         break;
150      }
151
152      /* Read the header */
153      bufr = &tar_buf[ptr];
154      ptr += 512;
155      if (strncmp(&bufr[257], "ustar  ", 7))
156      {
157         retval = UNTAR_SUCCESSFUL;
158         break;
159      }
160
161      strncpy(fname, bufr, MAX_NAME_FIELD_SIZE);
162      fname[MAX_NAME_FIELD_SIZE] = '\0';
163
164      linkflag   = bufr[156];
165      file_size  = octal2ulong(&bufr[124], 12);
166
167      /******************************************************************
168       * Compute the TAR checksum and check with the value in
169       * the archive.  The checksum is computed over the entire
170       * header, but the checksum field is substituted with blanks.
171       ******************************************************************/
172      hdr_chksum = (int)octal2ulong(&bufr[148], 8);
173      sum = 0;
174      for (i=0; i<512; i++)
175      {
176         if ((i >= 148) && (i < 156))
177         {
178            sum += 0xff & ' ';
179         }
180         else
181         {
182            sum += 0xff & bufr[i];
183         }
184      }
185      if (sum != hdr_chksum)
186      {
187         retval = UNTAR_INVALID_CHECKSUM;
188         break;
189      }
190
191
192      /******************************************************************
193       * We've decoded the header, now figure out what it contains and
194       * do something with it.
195       *****************************************************************/
196      if (linkflag == LF_SYMLINK)
197      {
198         strncpy(linkname, &bufr[157], MAX_NAME_FIELD_SIZE);
199         linkname[MAX_NAME_FIELD_SIZE] = '\0';
200         /* symlink(fname, linkname); */
201      }
202      else if (linkflag == LF_NORMAL)
203      {
204         nblocks = (((file_size) + 511) & ~511) / 512;
205         if ((fp = fopen(fname, "w")) == NULL)
206         {
207            printf("Untar failed to create file %s\n", fname);
208            ptr += 512 * nblocks;
209         }
210         else
211         {
212            unsigned long sizeToGo = file_size;
213            unsigned long len;
214
215            /***************************************************************
216             * Read out the data.  There are nblocks of data where nblocks
217             * is the file_size rounded to the nearest 512-byte boundary.
218             **************************************************************/
219            for (i=0; i<nblocks; i++)
220            {
221               len = ((sizeToGo < 512L)?(sizeToGo):(512L));
222               n = fwrite(&tar_buf[ptr], 1, len, fp);
223               if (n != len)
224               {
225                  printf("Error during write\n");
226                  break;
227               }
228               ptr += 512;
229               sizeToGo -= n;
230            }
231            fclose(fp);
232         }
233      }
234      else if (linkflag == LF_DIR)
235      {
236         mkdir(fname, S_IRWXU | S_IRWXG | S_IRWXO);
237      }
238   }
239
240   return(retval);
241}
242
243
244/**************************************************************************
245 * Function: Untar_FromFile                                               *
246 **************************************************************************
247 * Description:                                                           *
248 *                                                                        *
249 *    This is a simple subroutine used to rip links, directories, and     *
250 *    files out of a TAR file.                                            *
251 *                                                                        *
252 *                                                                        *
253 * Inputs:                                                                *
254 *                                                                        *
255 *    char *tar_name   - TAR filename.                                    *
256 *                                                                        *
257 *                                                                        *
258 * Output:                                                                *
259 *                                                                        *
260 *    int - UNTAR_SUCCESSFUL (0)    on successful completion.             *
261 *          UNTAR_INVALID_CHECKSUM  for an invalid header checksum.       *
262 *          UNTAR_INVALID_HEADER    for an invalid header.                *
263 *                                                                        *
264 **************************************************************************
265 * Change History:                                                        *
266 *  12/30/1998 - Creation (JWJ)                                           *
267 *************************************************************************/
268int
269Untar_FromFile(char *tar_name)
270{
271   int            fd;
272   char           *bufr;
273   size_t         n;
274   char           fname[100];
275   char           linkname[100];
276   int            sum;
277   int            hdr_chksum;
278   int            retval;
279   unsigned long  i;
280   unsigned long  nblocks;
281   unsigned long  size;
282   unsigned char  linkflag;
283
284
285   retval = UNTAR_SUCCESSFUL;
286   bufr = (char *)malloc(512);
287   if (bufr == NULL)
288   {
289      return(UNTAR_FAIL);
290   }
291
292   fd = open(tar_name, O_RDONLY);
293   while (1)
294   {
295      /* Read the header */
296      /* If the header read fails, we just consider it the end
297         of the tarfile. */
298      if ((n = read(fd, bufr, 512)) != 512)
299      {
300         break;
301      }
302
303      if (strncmp(&bufr[257], "ustar  ", 7))
304      {
305         break;
306      }
307
308      strncpy(fname, bufr, MAX_NAME_FIELD_SIZE);
309      fname[MAX_NAME_FIELD_SIZE] = '\0';
310
311      linkflag   = bufr[156];
312      size       = octal2ulong(&bufr[124], 12);
313
314      /******************************************************************
315       * Compute the TAR checksum and check with the value in
316       * the archive.  The checksum is computed over the entire
317       * header, but the checksum field is substituted with blanks.
318       ******************************************************************/
319      hdr_chksum = (int)octal2ulong(&bufr[148], 8);
320      sum = 0;
321      for (i=0; i<512; i++)
322      {
323         if ((i >= 148) && (i < 156))
324         {
325            sum += 0xff & ' ';
326         }
327         else
328         {
329            sum += 0xff & bufr[i];
330         }
331      }
332      if (sum != hdr_chksum)
333      {
334         retval = UNTAR_INVALID_CHECKSUM;
335         break;
336      }
337
338
339      /******************************************************************
340       * We've decoded the header, now figure out what it contains and
341       * do something with it.
342       *****************************************************************/
343      if (linkflag == LF_SYMLINK)
344      {
345         strncpy(linkname, &bufr[157], MAX_NAME_FIELD_SIZE);
346         linkname[MAX_NAME_FIELD_SIZE] = '\0';
347      }
348      else if (linkflag == LF_NORMAL)
349      {
350         int out_fd;
351
352         /******************************************************************
353          * Read out the data.  There are nblocks of data where nblocks
354          * is the size rounded to the nearest 512-byte boundary.
355          *****************************************************************/
356         nblocks = (((size) + 511) & ~511) / 512;
357
358         if ((out_fd = creat(fname, 0644)) == -1)
359         {
360            for (i=0; i<nblocks; i++)
361            {
362               n = read(fd, bufr, 512);
363            }
364         }
365         else
366         {
367            for (i=0; i<nblocks; i++)
368            {
369               n = read(fd, bufr, 512);
370               n = MIN(n, size - i*512);
371               write(out_fd, bufr, n);
372            }
373            close(out_fd);
374         }
375      }
376      else if (linkflag == LF_DIR)
377      {
378         mkdir(fname, S_IRWXU | S_IRWXG | S_IRWXO);
379      }
380   }
381   free(bufr);
382   close(fd);
383
384   return(retval);
385}
386
Note: See TracBrowser for help on using the repository browser.