source: rtems/cpukit/libmisc/untar/untar.c @ 09220c8

4.11
Last change on this file since 09220c8 was 09220c8, checked in by Joel Sherrill <joel.sherrill@…>, on Dec 14, 2014 at 11:30:23 PM

untar.c: Coverity ID 26151 and reformat

The Coverity issue was an ignored return value from a read()
in a loop which should have been a seek() since the data
read was ignored.

The file itself needed reformatting to conform to RTEMS style.

  • Property mode set to 100644
File size: 8.5 KB
Line 
1/**
2 * @file
3
4 * @brief Untar an Image
5 * @ingroup libmisc_untar_img Untar Image
6
7 * FIXME:
8 *   1. Symbolic links are not created.
9 *   2. Untar_FromMemory uses FILE *fp.
10 *   3. How to determine end of archive?
11
12 */
13
14/*
15 *  Written by: Jake Janovetz <janovetz@tempest.ece.uiuc.edu>
16
17 *  The license and distribution terms for this file may be
18 *  found in the file LICENSE in this distribution or at
19 *  http://www.rtems.org/license/LICENSE.
20 */
21
22#ifdef HAVE_CONFIG_H
23#include "config.h"
24#endif
25
26#include <sys/param.h>
27#include <stdio.h>
28#include <string.h>
29#include <stdlib.h>
30#include <unistd.h>
31#include <sys/stat.h>
32#include <fcntl.h>
33#include <rtems/untar.h>
34#include <rtems/bspIo.h>
35
36
37/*
38 * TAR file format:
39
40 *   Offset   Length   Contents
41 *     0    100 bytes  File name ('\0' terminated, 99 maxmum length)
42 *   100      8 bytes  File mode (in octal ascii)
43 *   108      8 bytes  User ID (in octal ascii)
44 *   116      8 bytes  Group ID (in octal ascii)
45 *   124     12 bytes  File size (s) (in octal ascii)
46 *   136     12 bytes  Modify time (in octal ascii)
47 *   148      8 bytes  Header checksum (in octal ascii)
48 *   156      1 bytes  Link flag
49 *   157    100 bytes  Linkname ('\0' terminated, 99 maxmum length)
50 *   257      8 bytes  Magic PAX ("ustar\0" + 2 bytes padding)
51 *   257      8 bytes  Magic GNU tar ("ustar  \0")
52 *   265     32 bytes  User name ('\0' terminated, 31 maxmum length)
53 *   297     32 bytes  Group name ('\0' terminated, 31 maxmum length)
54 *   329      8 bytes  Major device ID (in octal ascii)
55 *   337      8 bytes  Minor device ID (in octal ascii)
56 *   345    155 bytes  Prefix
57 *   512   (s+p)bytes  File contents (s+p) := (((s) + 511) & ~511),
58 *                     round up to 512 bytes
59 *
60 *   Checksum:
61 *   int i, sum;
62 *   char* header = tar_header_pointer;
63 *   sum = 0;
64 *   for(i = 0; i < 512; i++)
65 *       sum += 0xFF & header[i];
66 */ 
67
68#define MAX_NAME_FIELD_SIZE      99
69
70/*
71 * This converts octal ASCII number representations into an
72 * unsigned long.  Only support 32-bit numbers for now.
73 */ 
74unsigned long
75_rtems_octal2ulong(
76  const char *octascii,
77  size_t len
78)
79{
80  size_t        i;
81  unsigned long num;
82
83  num = 0;
84  for (i=0; i < len; i++) {
85    if ((octascii[i] < '0') || (octascii[i] > '9')) {
86      continue;
87    }
88    num  = num * 8 + ((unsigned long)(octascii[i] - '0'));
89  }
90  return(num);
91}
92
93/*
94 * Function: Untar_FromMemory
95 *
96 * Description:
97 *
98 *    This is a simple subroutine used to rip links, directories, and
99 *    files out of a block of memory.
100 *
101 *
102 * Inputs:
103 *
104 *    void *  tar_buf    - Pointer to TAR buffer.
105 *    size_t  size       - Length of TAR buffer.
106 *
107 *
108 * Output:
109 *
110 *    int - UNTAR_SUCCESSFUL (0)    on successful completion.
111 *          UNTAR_INVALID_CHECKSUM  for an invalid header checksum.
112 *          UNTAR_INVALID_HEADER    for an invalid header.
113 *
114 */
115int
116Untar_FromMemory(
117  void   *tar_buf,
118  size_t  size
119)
120{
121  FILE           *fp;
122  const char     *tar_ptr = (const char *)tar_buf;
123  const char     *bufr;
124  size_t         n;
125  char           fname[100];
126  char           linkname[100];
127  int            sum;
128  int            hdr_chksum;
129  int            retval;
130  unsigned long  ptr;
131  unsigned long  i;
132  unsigned long  nblocks;
133  unsigned long  file_size;
134  unsigned char  linkflag;
135
136  ptr = 0;
137  while (1) {
138    if (ptr + 512 > size) {
139      retval = UNTAR_SUCCESSFUL;
140      break;
141    }
142
143    /* Read the header */
144    bufr = &tar_ptr[ptr];
145    ptr += 512;
146    if (strncmp(&bufr[257], "ustar", 5)) {
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      retval = UNTAR_INVALID_CHECKSUM;
167      break;
168    }
169
170    /*
171     * We've decoded the header, now figure out what it contains and
172     * do something with it.
173     */
174    if (linkflag == SYMTYPE) {
175      strncpy(linkname, &bufr[157], MAX_NAME_FIELD_SIZE);
176      linkname[MAX_NAME_FIELD_SIZE] = '\0';
177      symlink(linkname, fname);
178    } else if (linkflag == REGTYPE) {
179      nblocks = (((file_size) + 511) & ~511) / 512;
180      if ((fp = fopen(fname, "w")) == NULL) {
181        printk("Untar: failed to create file %s\n", fname);
182        ptr += 512 * nblocks;
183      } else {
184        unsigned long sizeToGo = file_size;
185        size_t len;
186
187        /*
188         * Read out the data.  There are nblocks of data where nblocks
189         * is the file_size rounded to the nearest 512-byte boundary.
190         */
191        for (i=0; i<nblocks; i++) {
192          len = ((sizeToGo < 512L)?(sizeToGo):(512L));
193          n = fwrite(&tar_ptr[ptr], 1, len, fp);
194          if (n != len) {
195            printk("untar: Error during write\n");
196            retval  = UNTAR_FAIL;
197            break;
198          }
199          ptr += 512;
200          sizeToGo -= n;
201        }
202        fclose(fp);
203      }
204    } else if (linkflag == DIRTYPE) {
205      if ( mkdir(fname, S_IRWXU | S_IRWXG | S_IRWXO) != 0 ) {
206        printk("Untar: failed to create directory %s\n", fname);
207        retval = UNTAR_FAIL;
208        break;
209      }
210    }
211  }
212
213  return(retval);
214}
215
216/*
217 * Function: Untar_FromFile
218 *
219 * Description:
220 *
221 *    This is a simple subroutine used to rip links, directories, and
222 *    files out of a TAR file.
223 *
224 * Inputs:
225 *
226 *    const char *tar_name   - TAR filename.
227 *
228 * Output:
229 *
230 *    int - UNTAR_SUCCESSFUL (0)    on successful completion.
231 *          UNTAR_INVALID_CHECKSUM  for an invalid header checksum.
232 *          UNTAR_INVALID_HEADER    for an invalid header.
233 */
234int
235Untar_FromFile(
236  const char *tar_name
237)
238{
239  int            fd;
240  char           *bufr;
241  ssize_t        n;
242  char           fname[100];
243  char           linkname[100];
244  int            sum;
245  int            hdr_chksum;
246  int            retval;
247  unsigned long  i;
248  unsigned long  nblocks;
249  unsigned long  size;
250  unsigned char  linkflag;
251
252  retval = UNTAR_SUCCESSFUL;
253
254  if ((fd = open(tar_name, O_RDONLY)) < 0) {
255    return UNTAR_FAIL;
256  }
257
258  bufr = (char *)malloc(512);
259  if (bufr == NULL) {
260    close(fd);
261    return(UNTAR_FAIL);
262  }
263
264  while (1) {
265    /* Read the header */
266    /* If the header read fails, we just consider it the end of the tarfile. */
267    if ((n = read(fd, bufr, 512)) != 512) {
268      break;
269    }
270
271    if (strncmp(&bufr[257], "ustar", 5)) {
272      break;
273    }
274
275    strncpy(fname, bufr, MAX_NAME_FIELD_SIZE);
276    fname[MAX_NAME_FIELD_SIZE] = '\0';
277
278    linkflag   = bufr[156];
279    size       = _rtems_octal2ulong(&bufr[124], 12);
280
281    /*
282     * Compute the TAR checksum and check with the value in
283     * the archive.  The checksum is computed over the entire
284     * header, but the checksum field is substituted with blanks.
285     */
286    hdr_chksum = _rtems_octal2ulong(&bufr[148], 8);
287    sum = _rtems_tar_header_checksum(bufr);
288
289    if (sum != hdr_chksum) {
290      retval = UNTAR_INVALID_CHECKSUM;
291      break;
292    }
293
294    /*
295     * We've decoded the header, now figure out what it contains and
296     * do something with it.
297     */
298    if (linkflag == SYMTYPE) {
299      strncpy(linkname, &bufr[157], MAX_NAME_FIELD_SIZE);
300      linkname[MAX_NAME_FIELD_SIZE] = '\0';
301      symlink(linkname,fname);
302    } else if (linkflag == REGTYPE) {
303      int out_fd;
304
305      /*
306       * Read out the data.  There are nblocks of data where nblocks
307       * is the size rounded to the nearest 512-byte boundary.
308       */
309      nblocks = (((size) + 511) & ~511) / 512;
310
311      if ((out_fd = creat(fname, 0644)) == -1) {
312        (void) lseek(fd, SEEK_CUR, 512 * nblocks);
313      } else {
314        for (i=0; i<nblocks; i++) {
315          n = read(fd, bufr, 512);
316          n = MIN(n, size - i*512);
317          (void) write(out_fd, bufr, n);
318        }
319        close(out_fd);
320      }
321    } else if (linkflag == DIRTYPE) {
322      (void) mkdir(fname, S_IRWXU | S_IRWXG | S_IRWXO);
323    }
324  }
325  free(bufr);
326  close(fd);
327
328  return(retval);
329}
330
331/*
332 * Compute the TAR checksum and check with the value in
333 * the archive.  The checksum is computed over the entire
334 * header, but the checksum field is substituted with blanks.
335 */
336int
337_rtems_tar_header_checksum(
338  const char *bufr
339)
340{
341  int  i, sum;
342
343  sum = 0;
344  for (i=0; i<512; i++) {
345    if ((i >= 148) && (i < 156))
346      sum += 0xff & ' ';
347    else
348     sum += 0xff & bufr[i];
349  }
350  return(sum);
351}
Note: See TracBrowser for help on using the repository browser.