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 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 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 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 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 109 static int compare(const void* a, const void* b) { 110 return strcmp(*(const char**)a, *(const char**)b); 111 } 112 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 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 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 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