source: rtems/cpukit/libmisc/untar/untar.c @ f3ad98f

4.104.114.84.95
Last change on this file since f3ad98f was f3ad98f, checked in by Ralf Corsepius <ralf.corsepius@…>, on 02/09/05 at 03:24:29

2005-02-09 Ralf Corsepius <ralf.corsepius@…>

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