source: rtems/cpukit/libmisc/untar/untar.c @ 70810dc

4.104.114.84.95
Last change on this file since 70810dc was 2b28307, checked in by Joel Sherrill <joel.sherrill@…>, on 04/14/99 at 18:18:03

Bug report from Ralf on UNIX port where the S_IR* constants were not
defined.

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