Fixed time command segfault with no arguments
[busybox4maemo] / archival / libunarchive / get_header_ar.c
1 /* vi: set sw=4 ts=4: */
2 /* Copyright 2001 Glenn McGrath.
3  *
4  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
5  */
6
7 #include "libbb.h"
8 #include "unarchive.h"
9
10 char get_header_ar(archive_handle_t *archive_handle)
11 {
12         int err;
13         file_header_t *typed = archive_handle->file_header;
14         union {
15                 char raw[60];
16                 struct {
17                         char name[16];
18                         char date[12];
19                         char uid[6];
20                         char gid[6];
21                         char mode[8];
22                         char size[10];
23                         char magic[2];
24                 } formatted;
25         } ar;
26 #if ENABLE_FEATURE_AR_LONG_FILENAMES
27         static char *ar_long_names;
28         static unsigned ar_long_name_size;
29 #endif
30
31         /* dont use xread as we want to handle the error ourself */
32         if (read(archive_handle->src_fd, ar.raw, 60) != 60) {
33                 /* End Of File */
34                 return EXIT_FAILURE;
35         }
36
37         /* ar header starts on an even byte (2 byte aligned)
38          * '\n' is used for padding
39          */
40         if (ar.raw[0] == '\n') {
41                 /* fix up the header, we started reading 1 byte too early */
42                 memmove(ar.raw, &ar.raw[1], 59);
43                 ar.raw[59] = xread_char(archive_handle->src_fd);
44                 archive_handle->offset++;
45         }
46         archive_handle->offset += 60;
47
48         /* align the headers based on the header magic */
49         if (ar.formatted.magic[0] != '`' || ar.formatted.magic[1] != '\n')
50                 bb_error_msg_and_die("invalid ar header");
51
52         /* FIXME: more thorough routine would be in order here */
53         /* (we have something like that in tar) */
54         /* but for now we are lax. This code works because */
55         /* on misformatted numbers bb_strtou returns all-ones */
56         typed->mode = err = bb_strtou(ar.formatted.mode, NULL, 8);
57         if (err == -1) bb_error_msg_and_die("invalid ar header");
58         typed->mtime = err = bb_strtou(ar.formatted.date, NULL, 10);
59         if (err == -1) bb_error_msg_and_die("invalid ar header");
60         typed->uid = err = bb_strtou(ar.formatted.uid, NULL, 10);
61         if (err == -1) bb_error_msg_and_die("invalid ar header");
62         typed->gid = err = bb_strtou(ar.formatted.gid, NULL, 10);
63         if (err == -1) bb_error_msg_and_die("invalid ar header");
64         typed->size = err = bb_strtou(ar.formatted.size, NULL, 10);
65         if (err == -1) bb_error_msg_and_die("invalid ar header");
66
67         /* long filenames have '/' as the first character */
68         if (ar.formatted.name[0] == '/') {
69 #if ENABLE_FEATURE_AR_LONG_FILENAMES
70                 unsigned long_offset;
71
72                 if (ar.formatted.name[1] == '/') {
73                         /* If the second char is a '/' then this entries data section
74                          * stores long filename for multiple entries, they are stored
75                          * in static variable long_names for use in future entries */
76                         ar_long_name_size = typed->size;
77                         ar_long_names = xmalloc(ar_long_name_size);
78                         xread(archive_handle->src_fd, ar_long_names, ar_long_name_size);
79                         archive_handle->offset += ar_long_name_size;
80                         /* This ar entries data section only contained filenames for other records
81                          * they are stored in the static ar_long_names for future reference */
82                         return get_header_ar(archive_handle); /* Return next header */
83                 }
84
85                 if (ar.formatted.name[1] == ' ') {
86                         /* This is the index of symbols in the file for compilers */
87                         data_skip(archive_handle);
88                         archive_handle->offset += typed->size;
89                         return get_header_ar(archive_handle); /* Return next header */
90                 }
91
92                 /* The number after the '/' indicates the offset in the ar data section
93                  * (saved in variable long_name) that conatains the real filename */
94                 long_offset = atoi(&ar.formatted.name[1]);
95                 if (long_offset >= ar_long_name_size) {
96                         bb_error_msg_and_die("can't resolve long filename");
97                 }
98                 typed->name = xstrdup(ar_long_names + long_offset);
99 #else
100                 bb_error_msg_and_die("long filenames not supported");
101 #endif
102         } else {
103                 /* short filenames */
104                 typed->name = xstrndup(ar.formatted.name, 16);
105         }
106
107         typed->name[strcspn(typed->name, " /")] = '\0';
108
109         if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) {
110                 archive_handle->action_header(typed);
111                 if (archive_handle->sub_archive) {
112                         while (archive_handle->action_data_subarchive(archive_handle->sub_archive) == EXIT_SUCCESS)
113                                 /* repeat */;
114                 } else {
115                         archive_handle->action_data(archive_handle);
116                 }
117         } else {
118                 data_skip(archive_handle);
119         }
120
121         archive_handle->offset += typed->size;
122         /* Set the file pointer to the correct spot, we may have been reading a compressed file */
123         lseek(archive_handle->src_fd, archive_handle->offset, SEEK_SET);
124
125         return EXIT_SUCCESS;
126 }