summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Bolte <sbolte@lavabit.com>2013-05-15 18:56:17 +0200
committerStefan Bolte <sbolte@lavabit.com>2013-05-15 18:56:17 +0200
commit1bff1080c880407262c8bd207fd35986517cb299 (patch)
tree4fd95df7f3be7c3e395b697b56a5f24e93fc5a8d
parent08f377719611c4782a165b1398aa6fb01d59eabc (diff)
downloaddwb-1bff1080c880407262c8bd207fd35986517cb299.zip
Implementing exar_cat
-rw-r--r--tools/exar/exar.c136
-rw-r--r--tools/exar/exar.h10
-rw-r--r--tools/exar/main.c53
3 files changed, 152 insertions, 47 deletions
diff --git a/tools/exar/exar.c b/tools/exar/exar.c
index b9ea9379..ca4d46a9 100644
--- a/tools/exar/exar.c
+++ b/tools/exar/exar.c
@@ -42,8 +42,9 @@
#define DIR_FLAG (100)
#define FILE_FLAG (102)
-#define LOG(level, format, ...) do { if (s_verbose & EXAR_VERBOSE_L##level) \
- fprintf(stderr, "exar-log%d: "format, level, __VA_ARGS__); } while(0)
+#define LOG(level, ...) do { if (s_verbose & EXAR_VERBOSE_L##level) \
+ fprintf(stderr, "exar-log%d: ", level); \
+ fprintf(stderr, __VA_ARGS__); } while(0)
static size_t s_offset;
static FILE *s_out;
@@ -99,14 +100,13 @@ pack(const char *fpath, const struct stat *st, int tf)
return 0;
}
-int
-exar_pack(const char *path)
+size_t
+get_offset(char *buffer, size_t n, const char *path, int *end)
{
- int ret, i=0;
- unsigned char version[SZ_VERSION] = {0};
- char buffer[512];
const char *tmp = path, *slash;
size_t len = strlen(path);
+ size_t offset = 0;
+ int i=0;
// strip trailing '/'
while (tmp[len-1] == '/')
@@ -116,11 +116,25 @@ exar_pack(const char *path)
// get base name offset
slash = strrchr(buffer, '/');
if (slash != NULL)
- s_offset = slash - buffer + 1;
-
- // construct filename
+ offset = slash - buffer + 1;
for (tmp = path + s_offset; *tmp && *tmp != '/'; i++, tmp++)
buffer[i] = *tmp;
+ if (end != NULL)
+ *end = i;
+ return offset;
+}
+
+
+int
+exar_pack(const char *path)
+{
+ int ret;
+ unsigned char version[SZ_VERSION] = {0};
+ char buffer[512];
+ int i = 0;
+
+ s_offset = get_offset(buffer, sizeof(buffer), path, &i);
+
strncpy(&buffer[i], "." EXTENSION, sizeof(buffer) - i);
LOG(3, "Opening %s for writing\n", buffer);
@@ -141,6 +155,35 @@ exar_pack(const char *path)
fclose(s_out);
return ret;
}
+static int
+check_version(FILE *f, int verbose)
+{
+ unsigned char version[SZ_VERSION] = {0}, orig_version[SZ_VERSION] = {0};
+ LOG(2, "Reading version header\n");
+ if (fread(version, 1, sizeof(version), f) != sizeof(version))
+ {
+ if (verbose)
+ fprintf(stderr, "Not an exar file?\n");
+ return -1;
+ }
+ memcpy(orig_version, VERSION, sizeof(orig_version));
+ LOG(2, "Checking filetype\n");
+ if (strncmp((char*)version, VERSION_BASE, 5))
+ {
+ if (verbose)
+ fprintf(stderr, "Not an exar file?\n");
+ return -1;
+ }
+
+ LOG(1, "Found version %s\n", version);
+ if (memcmp(version, orig_version, SZ_VERSION))
+ {
+ if (verbose)
+ fprintf(stderr, "Incompatible version number\n");
+ return -1;
+ }
+ return 0;
+}
int
exar_unpack(const char *path, const char *dest)
{
@@ -149,7 +192,6 @@ exar_unpack(const char *path, const char *dest)
size_t fs;
FILE *of, *f = NULL;
char *endptr;
- unsigned char version[SZ_VERSION] = {0}, orig_version[SZ_VERSION] = {0};
LOG(3, "Opening %s for reading\n", path);
if ((f = fopen(path, "r")) == NULL)
@@ -157,29 +199,9 @@ exar_unpack(const char *path, const char *dest)
fprintf(stderr, "Cannot open %s\n", path);
return -1;
}
- // Compare version header
- LOG(2, "Reading version header %s\n", "");
- if (fread(version, 1, sizeof(version), f) != sizeof(version))
- {
- fprintf(stderr, "Not an exar file?\n");
+ if (check_version(f, 1) != 0)
goto error_out;
- }
- memcpy(orig_version, VERSION, sizeof(orig_version));
-
- LOG(2, "Checking filetype%s", "\n");
- if (strncmp((char*)version, VERSION_BASE, 5))
- {
- fprintf(stderr, "Not an exar file?\n");
- goto error_out;
- }
-
- LOG(1, "Found version %s\n", version);
- if (memcmp(version, orig_version, SZ_VERSION))
- {
- fprintf(stderr, "Incompatible version number\n");
- goto error_out;
- }
if (dest != NULL)
{
LOG(2, "Changing to directory %s\n", dest);
@@ -250,6 +272,56 @@ error_out:
}
return ret;
}
+int
+exar_cat(const char *file1, const char *file2)
+{
+ int ret = -1;
+ size_t r;
+ FILE *f1 = NULL, *f2 = NULL;
+ char buffer[64];
+ char offset_buffer[512];
+
+ LOG(3, "Opening file %s for writing\n", file1);
+ if ((f1 = fopen(file1, "a")) == NULL)
+ {
+ perror("fopen");
+ goto error_out;
+ }
+ LOG(3, "Opening file %s for reading\n", file2);
+ if ((f2 = fopen(file2, "r")) == NULL)
+ {
+ perror("fopen");
+ goto error_out;
+ }
+ if (check_version(f2, 0) == 0)
+ {
+ LOG(1, "Concatenating archive\n");
+ while ((r = fread(buffer, 1, sizeof(buffer), f2)) > 0)
+ {
+ fwrite(buffer, 1, r, f1);
+ }
+ }
+ else
+ {
+ s_offset = get_offset(offset_buffer, sizeof(offset_buffer), file2, NULL);
+ LOG(1, "Concatenating regular files\n");
+ s_out = f1;
+ ftw(file2, pack, 64);
+ }
+ ret = 0;
+error_out:
+ if (f1 != NULL)
+ {
+ LOG(3, "Closing %s\n", file1);
+ fclose(f1);
+ }
+ if (f2 != NULL)
+ {
+ LOG(3, "Closing %s\n", file2);
+ fclose(f2);
+ }
+ return ret;
+}
void
exar_verbose(unsigned char v)
{
diff --git a/tools/exar/exar.h b/tools/exar/exar.h
index 93f73e48..26d3997b 100644
--- a/tools/exar/exar.h
+++ b/tools/exar/exar.h
@@ -61,6 +61,16 @@ exar_verbose(unsigned char v_flags);
int
exar_pack(const char *path);
+/*
+ * Concatenates two archives or an archive and a file or directory
+ * @file1: The archive to append
+ * @file2: The archive, file or directory that will be appended
+ *
+ * @returns 0 on success and -1 on error
+ * */
+int
+exar_cat(const char *file1, const char *file2);
+
/*
* Unpacks a file
* @path: Path to the extension archive
diff --git a/tools/exar/main.c b/tools/exar/main.c
index 194baf41..59333f3d 100644
--- a/tools/exar/main.c
+++ b/tools/exar/main.c
@@ -24,6 +24,7 @@ enum {
FLAG_V = 1<<0,
FLAG_P = 1<<3,
FLAG_U = 1<<4,
+ FLAG_C = 1<<5,
};
#ifndef MIN
#define MIN(X, Y) ((X) > (Y) ? (Y) : (X))
@@ -37,18 +38,22 @@ help(int ret)
printf("USAGE: \n"
" exar option [arguments]\n\n"
"OPTIONS:\n"
- " h : Print this help and exit.\n"
- " p[v] path : Pack file or directory 'path'.\n"
- " u[v] file [dir] : Pack 'file' to directory 'dir' or to \n"
- " current directory.\n"
- " v : Verbose, pass multiple times (up to 3) to \n"
- " get more verbose messages.\n\n"
+ " h : Print this help and exit.\n"
+ " c[v] archive file : Concatenates a file, directory or archive to \n"
+ " an existing archive.\n"
+ " p[v] path : Pack file or directory 'path'.\n"
+ " u[v] file [dir] : Pack 'file' to directory 'dir' or to \n"
+ " current directory.\n"
+ " v : Verbose, pass multiple times (up to 3) to \n"
+ " get more verbose messages.\n\n"
"EXAMPLES:\n"
- " exar p /tmp/foo -- pack /tmp/foo to foo.exar\n"
- " exar uvvv foo.exar -- unpack foo.exar to current directory, \n"
- " verbosity level 3\n"
- " exar vu foo.exar /tmp -- unpack foo.exar to /tmp, verbosity \n"
- " level 1\n");
+ " exar p /tmp/foo -- pack /tmp/foo to foo.exar\n"
+ " exar c foo.exar bar.txt -- Concatenates bar.txt to archive foo.exar\n"
+ " exar c foo.exar bar.exar -- Concatenates archive bar.exar to archive foo.exar\n"
+ " exar uvvv foo.exar -- unpack foo.exar to current directory, \n"
+ " verbosity level 3\n"
+ " exar vu foo.exar /tmp -- unpack foo.exar to /tmp, verbosity \n"
+ " level 1\n");
exit(ret);
}
int
@@ -70,6 +75,9 @@ main (int argc, char **argv)
case 'u' :
flag |= FLAG_U;
break;
+ case 'c' :
+ flag |= FLAG_C;
+ break;
case 'v' :
flag |= MAX(FLAG_V, MIN(EXAR_VERBOSE_MASK, ((flag & EXAR_VERBOSE_MASK) << 1)));
break;
@@ -80,15 +88,30 @@ main (int argc, char **argv)
}
options++;
}
- if ((flag & (FLAG_U | FLAG_P)) == (FLAG_U | FLAG_P))
- help(EXIT_FAILURE);
if (flag & EXAR_VERBOSE_MASK)
exar_verbose(flag);
if (flag & FLAG_U)
- exar_unpack(argv[2], argv[3]);
+ {
+ if (flag & (FLAG_P | FLAG_C))
+ help(EXIT_FAILURE);
+ else
+ exar_unpack(argv[2], argv[3]);
+ }
else if (flag & FLAG_P)
- exar_pack(argv[2]);
+ {
+ if (flag & (FLAG_U | FLAG_C))
+ help(EXIT_FAILURE);
+ else
+ exar_pack(argv[2]);
+ }
+ else if (flag & FLAG_C)
+ {
+ if (flag & (FLAG_U | FLAG_P) || argc < 4)
+ help(EXIT_FAILURE);
+ else
+ exar_cat(argv[2], argv[3]);
+ }
else
help(EXIT_SUCCESS);