• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <unistd.h>
5 #include <string.h>
6 
7 #include <sys/types.h>
8 #include <sys/stat.h>
9 #include <dirent.h>
10 
11 #include <stdarg.h>
12 #include <fcntl.h>
13 
14 #include <private/android_filesystem_config.h>
15 
16 /* NOTES
17 **
18 ** - see buffer-format.txt from the linux kernel docs for
19 **   an explanation of this file format
20 ** - dotfiles are ignored
21 ** - directories named 'root' are ignored
22 ** - device notes, pipes, etc are not supported (error)
23 */
24 
die(const char * why,...)25 void die(const char *why, ...)
26 {
27     va_list ap;
28 
29     va_start(ap, why);
30     fprintf(stderr,"error: ");
31     vfprintf(stderr, why, ap);
32     fprintf(stderr,"\n");
33     va_end(ap);
34     exit(1);
35 }
36 
37 static int verbose = 0;
38 static int total_size = 0;
39 
fix_stat(const char * path,struct stat * s)40 static void fix_stat(const char *path, struct stat *s)
41 {
42     fs_config(path, S_ISDIR(s->st_mode), &s->st_uid, &s->st_gid, &s->st_mode);
43 }
44 
_eject(struct stat * s,char * out,int olen,char * data,unsigned datasize)45 static void _eject(struct stat *s, char *out, int olen, char *data, unsigned datasize)
46 {
47     // Nothing is special about this value, just picked something in the
48     // approximate range that was being used already, and avoiding small
49     // values which may be special.
50     static unsigned next_inode = 300000;
51 
52     while(total_size & 3) {
53         total_size++;
54         putchar(0);
55     }
56 
57     fix_stat(out, s);
58 //    fprintf(stderr, "_eject %s: mode=0%o\n", out, s->st_mode);
59 
60     printf("%06x%08x%08x%08x%08x%08x%08x"
61            "%08x%08x%08x%08x%08x%08x%08x%s%c",
62            0x070701,
63            next_inode++,  //  s.st_ino,
64            s->st_mode,
65            0, // s.st_uid,
66            0, // s.st_gid,
67            1, // s.st_nlink,
68            0, // s.st_mtime,
69            datasize,
70            0, // volmajor
71            0, // volminor
72            0, // devmajor
73            0, // devminor,
74            olen + 1,
75            0,
76            out,
77            0
78            );
79 
80     total_size += 6 + 8*13 + olen + 1;
81 
82     if(strlen(out) != olen) die("ACK!");
83 
84     while(total_size & 3) {
85         total_size++;
86         putchar(0);
87     }
88 
89     if(datasize) {
90         fwrite(data, datasize, 1, stdout);
91         total_size += datasize;
92     }
93 }
94 
_eject_trailer()95 static void _eject_trailer()
96 {
97     struct stat s;
98     memset(&s, 0, sizeof(s));
99     _eject(&s, "TRAILER!!!", 10, 0, 0);
100 
101     while(total_size & 0xff) {
102         total_size++;
103         putchar(0);
104     }
105 }
106 
107 static void _archive(char *in, char *out, int ilen, int olen);
108 
compare(const void * a,const void * b)109 static int compare(const void* a, const void* b) {
110   return strcmp(*(const char**)a, *(const char**)b);
111 }
112 
_archive_dir(char * in,char * out,int ilen,int olen)113 static void _archive_dir(char *in, char *out, int ilen, int olen)
114 {
115     int i, t;
116     DIR *d;
117     struct dirent *de;
118 
119     if(verbose) {
120         fprintf(stderr,"_archive_dir('%s','%s',%d,%d)\n",
121                 in, out, ilen, olen);
122     }
123 
124     d = opendir(in);
125     if(d == 0) die("cannot open directory '%s'", in);
126 
127     int size = 32;
128     int entries = 0;
129     char** names = malloc(size * sizeof(char*));
130     if (names == NULL) {
131       fprintf(stderr, "failed to allocate dir names array (size %d)\n", size);
132       exit(1);
133     }
134 
135     while((de = readdir(d)) != 0){
136             /* xxx: feature? maybe some dotfiles are okay */
137         if(de->d_name[0] == '.') continue;
138 
139             /* xxx: hack. use a real exclude list */
140         if(!strcmp(de->d_name, "root")) continue;
141 
142         if (entries >= size) {
143           size *= 2;
144           names = realloc(names, size * sizeof(char*));
145           if (names == NULL) {
146             fprintf(stderr, "failed to reallocate dir names array (size %d)\n",
147                     size);
148             exit(1);
149           }
150         }
151         names[entries] = strdup(de->d_name);
152         if (names[entries] == NULL) {
153           fprintf(stderr, "failed to strdup name \"%s\"\n",
154                   de->d_name);
155           exit(1);
156         }
157         ++entries;
158     }
159 
160     qsort(names, entries, sizeof(char*), compare);
161 
162     for (i = 0; i < entries; ++i) {
163         t = strlen(names[i]);
164         in[ilen] = '/';
165         memcpy(in + ilen + 1, names[i], t + 1);
166 
167         if(olen > 0) {
168             out[olen] = '/';
169             memcpy(out + olen + 1, names[i], t + 1);
170             _archive(in, out, ilen + t + 1, olen + t + 1);
171         } else {
172             memcpy(out, names[i], t + 1);
173             _archive(in, out, ilen + t + 1, t);
174         }
175 
176         in[ilen] = 0;
177         out[olen] = 0;
178 
179         free(names[i]);
180     }
181     free(names);
182 }
183 
_archive(char * in,char * out,int ilen,int olen)184 static void _archive(char *in, char *out, int ilen, int olen)
185 {
186     struct stat s;
187 
188     if(verbose) {
189         fprintf(stderr,"_archive('%s','%s',%d,%d)\n",
190                 in, out, ilen, olen);
191     }
192 
193     if(lstat(in, &s)) die("could not stat '%s'\n", in);
194 
195     if(S_ISREG(s.st_mode)){
196         char *tmp;
197         int fd;
198 
199         fd = open(in, O_RDONLY);
200         if(fd < 0) die("cannot open '%s' for read", in);
201 
202         tmp = (char*) malloc(s.st_size);
203         if(tmp == 0) die("cannot allocate %d bytes", s.st_size);
204 
205         if(read(fd, tmp, s.st_size) != s.st_size) {
206             die("cannot read %d bytes", s.st_size);
207         }
208 
209         _eject(&s, out, olen, tmp, s.st_size);
210 
211         free(tmp);
212         close(fd);
213     } else if(S_ISDIR(s.st_mode)) {
214         _eject(&s, out, olen, 0, 0);
215         _archive_dir(in, out, ilen, olen);
216     } else if(S_ISLNK(s.st_mode)) {
217         char buf[1024];
218         int size;
219         size = readlink(in, buf, 1024);
220         if(size < 0) die("cannot read symlink '%s'", in);
221         _eject(&s, out, olen, buf, size);
222     } else {
223         die("Unknown '%s' (mode %d)?\n", in, s.st_mode);
224     }
225 }
226 
archive(const char * start,const char * prefix)227 void archive(const char *start, const char *prefix)
228 {
229     char in[8192];
230     char out[8192];
231 
232     strcpy(in, start);
233     strcpy(out, prefix);
234 
235     _archive_dir(in, out, strlen(in), strlen(out));
236 }
237 
main(int argc,char * argv[])238 int main(int argc, char *argv[])
239 {
240     argc--;
241     argv++;
242 
243     if(argc == 0) die("no directories to process?!");
244 
245     while(argc-- > 0){
246         char *x = strchr(*argv, '=');
247         if(x != 0) {
248             *x++ = 0;
249         } else {
250             x = "";
251         }
252 
253         archive(*argv, x);
254 
255         argv++;
256     }
257 
258     _eject_trailer();
259 
260     return 0;
261 }
262