summaryrefslogtreecommitdiffstats
path: root/tools/dexpreopt/afar/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/dexpreopt/afar/main.c')
-rw-r--r--tools/dexpreopt/afar/main.c247
1 files changed, 247 insertions, 0 deletions
diff --git a/tools/dexpreopt/afar/main.c b/tools/dexpreopt/afar/main.c
new file mode 100644
index 0000000..d66d59c
--- /dev/null
+++ b/tools/dexpreopt/afar/main.c
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+
+#include <stdarg.h>
+#include <fcntl.h>
+#include <termios.h>
+
+#include <zlib.h> // for adler32()
+
+static int verbose = 0;
+
+/*
+ * Android File Archive format:
+ *
+ * magic[5]: 'A' 'F' 'A' 'R' '\n'
+ * version[4]: 0x00 0x00 0x00 0x01
+ * for each file:
+ * file magic[4]: 'F' 'I' 'L' 'E'
+ * namelen[4]: Length of file name, including NUL byte (big-endian)
+ * name[*]: NUL-terminated file name
+ * datalen[4]: Length of file (big-endian)
+ * data[*]: Unencoded file data
+ * adler32[4]: adler32 of the unencoded file data (big-endian)
+ * file end magic[4]: 'f' 'i' 'l' 'e'
+ * end magic[4]: 'E' 'N' 'D' 0x00
+ *
+ * This format is about as simple as possible; it was designed to
+ * make it easier to transfer multiple files over an stdin/stdout
+ * pipe to another process, so word-alignment wasn't necessary.
+ */
+
+static void
+die(const char *why, ...)
+{
+ va_list ap;
+
+ va_start(ap, why);
+ fprintf(stderr, "error: ");
+ vfprintf(stderr, why, ap);
+ fprintf(stderr, "\n");
+ va_end(ap);
+ exit(1);
+}
+
+static void
+write_big_endian(size_t v)
+{
+ putchar((v >> 24) & 0xff);
+ putchar((v >> 16) & 0xff);
+ putchar((v >> 8) & 0xff);
+ putchar( v & 0xff);
+}
+
+static void
+_eject(struct stat *s, char *out, int olen, char *data, size_t datasize)
+{
+ unsigned long adler;
+
+ /* File magic.
+ */
+ printf("FILE");
+
+ /* Name length includes the NUL byte.
+ */
+ write_big_endian(olen + 1);
+
+ /* File name and terminating NUL.
+ */
+ printf("%s", out);
+ putchar('\0');
+
+ /* File length.
+ */
+ write_big_endian(datasize);
+
+ /* File data.
+ */
+ if (fwrite(data, 1, datasize, stdout) != datasize) {
+ die("Error writing file data");
+ }
+
+ /* Checksum.
+ */
+ adler = adler32(0, NULL, 0);
+ adler = adler32(adler, (unsigned char *)data, datasize);
+ write_big_endian(adler);
+
+ /* File end magic.
+ */
+ printf("file");
+}
+
+static void _archive(char *in, int ilen);
+
+static void
+_archive_dir(char *in, int ilen)
+{
+ int t;
+ DIR *d;
+ struct dirent *de;
+
+ if (verbose) {
+ fprintf(stderr, "_archive_dir('%s', %d)\n", in, ilen);
+ }
+
+ d = opendir(in);
+ if (d == 0) {
+ die("cannot open directory '%s'", in);
+ }
+
+ while ((de = readdir(d)) != 0) {
+ /* xxx: feature? maybe some dotfiles are okay */
+ if (strcmp(de->d_name, ".") == 0 ||
+ strcmp(de->d_name, "..") == 0)
+ {
+ continue;
+ }
+
+ t = strlen(de->d_name);
+ in[ilen] = '/';
+ memcpy(in + ilen + 1, de->d_name, t + 1);
+
+ _archive(in, ilen + t + 1);
+
+ in[ilen] = '\0';
+ }
+}
+
+static void
+_archive(char *in, int ilen)
+{
+ struct stat s;
+
+ if (verbose) {
+ fprintf(stderr, "_archive('%s', %d)\n", in, ilen);
+ }
+
+ if (lstat(in, &s)) {
+ die("could not stat '%s'\n", in);
+ }
+
+ if (S_ISREG(s.st_mode)) {
+ char *tmp;
+ int fd;
+
+ fd = open(in, O_RDONLY);
+ if (fd < 0) {
+ die("cannot open '%s' for read", in);
+ }
+
+ tmp = (char*) malloc(s.st_size);
+ if (tmp == 0) {
+ die("cannot allocate %d bytes", s.st_size);
+ }
+
+ if (read(fd, tmp, s.st_size) != s.st_size) {
+ die("cannot read %d bytes", s.st_size);
+ }
+
+ _eject(&s, in, ilen, tmp, s.st_size);
+
+ free(tmp);
+ close(fd);
+ } else if (S_ISDIR(s.st_mode)) {
+ _archive_dir(in, ilen);
+ } else {
+ /* We don't handle links, etc. */
+ die("Unknown '%s' (mode %d)?\n", in, s.st_mode);
+ }
+}
+
+void archive(const char *start)
+{
+ char in[8192];
+
+ strcpy(in, start);
+
+ _archive_dir(in, strlen(in));
+}
+
+int
+main(int argc, char *argv[])
+{
+ struct termios old_termios;
+
+ if (argc == 1) {
+ die("usage: %s <dir-list>", argv[0]);
+ }
+ argc--;
+ argv++;
+
+ /* Force stdout into raw mode.
+ */
+ struct termios s;
+ if (tcgetattr(1, &s) < 0) {
+ die("Could not get termios for stdout");
+ }
+ old_termios = s;
+ cfmakeraw(&s);
+ if (tcsetattr(1, TCSANOW, &s) < 0) {
+ die("Could not set termios for stdout");
+ }
+
+ /* Print format magic and version.
+ */
+ printf("AFAR\n");
+ write_big_endian(1);
+
+ while (argc-- > 0) {
+ archive(*argv++);
+ }
+
+ /* Print end magic.
+ */
+ printf("END");
+ putchar('\0');
+
+ /* Restore stdout.
+ */
+ if (tcsetattr(1, TCSANOW, &old_termios) < 0) {
+ die("Could not restore termios for stdout");
+ }
+
+ return 0;
+}