source: rtems/c/src/libmisc/untar/untar.c @ b08d3ed9

4.104.114.84.9
Last change on this file since b08d3ed9 was b08d3ed9, checked in by Joel Sherrill <joel.sherrill@…>, on Apr 6, 1999 at 9:45:06 PM

Untar support submitted by Jake Janovetz <janovetz@…>.

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