source: rtems/cpukit/libmisc/untar/untar.c @ 5fb9e2fc

4.104.114.84.95
Last change on this file since 5fb9e2fc was 5fb9e2fc, checked in by Joel Sherrill <joel.sherrill@…>, on 09/04/07 at 19:32:54

2007-09-04 Joel Sherrill <joel.sherrill@…>

  • libmisc/untar/untar.c, libmisc/untar/untar.h: Add const to char *. Use printk.
  • Property mode set to 100644
File size: 12.4 KB
Line 
1/* FIXME:
2 *   1. Symbolic links are not created.
3 *   2. Untar_FromMemory uses FILE *fp.
4 *   3. How to determine end of archive?
5 *
6 *  Written by: Jake Janovetz <janovetz@tempest.ece.uiuc.edu>
7 *
8 *  The license and distribution terms for this file may be
9 *  found in the file LICENSE in this distribution or at
10 *  http://www.rtems.com/license/LICENSE.
11 *
12 *  $Id$
13 */
14
15#ifdef HAVE_CONFIG_H
16#include "config.h"
17#endif
18
19#include <stdio.h>
20#include <string.h>
21#include <stdlib.h>
22#include <unistd.h>
23#include <sys/stat.h>
24#include <fcntl.h>
25#include <rtems/untar.h>
26#include <rtems/bspIo.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(
70  const char *octascii,
71  size_t len
72)
73{
74   size_t        i;
75   unsigned long num;
76
77   num = 0;
78   for (i=0; i < len; i++)
79   {
80      if ((octascii[i] < '0') || (octascii[i] > '9'))
81      {
82         continue;
83      }
84      num  = num * 8 + ((unsigned long)(octascii[i] - '0'));
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 *    const 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 **************************************************************************/
112int
113Untar_FromMemory(
114  const char *tar_buf,
115  size_t size
116)
117{
118   FILE           *fp;
119   const 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            printk("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                  printk("untar: 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 *    const 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(
250  const char *tar_name
251)
252{
253   int            fd;
254   char           *bufr;
255   size_t         n;
256   char           fname[100];
257   char           linkname[100];
258   int            sum;
259   int            hdr_chksum;
260   int            retval;
261   unsigned long  i;
262   unsigned long  nblocks;
263   unsigned long  size;
264   unsigned char  linkflag;
265
266
267   retval = UNTAR_SUCCESSFUL;
268   bufr = (char *)malloc(512);
269   if (bufr == NULL)
270   {
271      return(UNTAR_FAIL);
272   }
273
274   fd = open(tar_name, O_RDONLY);
275   while (1)
276   {
277      /* Read the header */
278      /* If the header read fails, we just consider it the end
279         of the tarfile. */
280      if ((n = read(fd, bufr, 512)) != 512)
281      {
282         break;
283      }
284
285      if (strncmp(&bufr[257], "ustar  ", 7))
286      {
287         break;
288      }
289
290      strncpy(fname, bufr, MAX_NAME_FIELD_SIZE);
291      fname[MAX_NAME_FIELD_SIZE] = '\0';
292
293      linkflag   = bufr[156];
294      size       = _rtems_octal2ulong(&bufr[124], 12);
295
296      /******************************************************************
297       * Compute the TAR checksum and check with the value in
298       * the archive.  The checksum is computed over the entire
299       * header, but the checksum field is substituted with blanks.
300       ******************************************************************/
301      hdr_chksum = _rtems_octal2ulong(&bufr[148], 8);
302      sum = _rtems_tar_header_checksum(bufr);
303
304      if (sum != hdr_chksum)
305      {
306         retval = UNTAR_INVALID_CHECKSUM;
307         break;
308      }
309
310      /******************************************************************
311       * We've decoded the header, now figure out what it contains and
312       * do something with it.
313       *****************************************************************/
314      if (linkflag == SYMTYPE)
315      {
316         strncpy(linkname, &bufr[157], MAX_NAME_FIELD_SIZE);
317         linkname[MAX_NAME_FIELD_SIZE] = '\0';
318         symlink(linkname,fname);
319      }
320      else if (linkflag == REGTYPE)
321      {
322         int out_fd;
323
324         /******************************************************************
325          * Read out the data.  There are nblocks of data where nblocks
326          * is the size rounded to the nearest 512-byte boundary.
327          *****************************************************************/
328         nblocks = (((size) + 511) & ~511) / 512;
329
330         if ((out_fd = creat(fname, 0644)) == -1)
331         {
332            for (i=0; i<nblocks; i++)
333            {
334               n = read(fd, bufr, 512);
335            }
336         }
337         else
338         {
339            for (i=0; i<nblocks; i++)
340            {
341               n = read(fd, bufr, 512);
342               n = MIN(n, size - i*512);
343               write(out_fd, bufr, n);
344            }
345            close(out_fd);
346         }
347      }
348      else if (linkflag == DIRTYPE)
349      {
350         mkdir(fname, S_IRWXU | S_IRWXG | S_IRWXO);
351      }
352   }
353   free(bufr);
354   close(fd);
355
356   return(retval);
357}
358
359/************************************************************************
360 * Compute the TAR checksum and check with the value in
361 * the archive.  The checksum is computed over the entire
362 * header, but the checksum field is substituted with blanks.
363 ************************************************************************/
364int
365_rtems_tar_header_checksum(
366  const char *bufr
367)
368{
369   int  i, sum;
370
371   sum = 0;
372   for (i=0; i<512; i++)
373   {
374      if ((i >= 148) && (i < 156))
375         sum += 0xff & ' ';
376      else
377         sum += 0xff & bufr[i];
378   }
379   return(sum);
380}
Note: See TracBrowser for help on using the repository browser.