source: rtems/cpukit/libmisc/untar/untar.c @ 1996aee7

4.104.114.84.95
Last change on this file since 1996aee7 was 1996aee7, checked in by Ralf Corsepius <ralf.corsepius@…>, on Feb 7, 2005 at 1:25:14 PM

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

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