]> git.zerfleddert.de Git - rsbs2/blobdiff - src/filesystem.c
move source files to own subdirectory
[rsbs2] / src / filesystem.c
diff --git a/src/filesystem.c b/src/filesystem.c
new file mode 100644 (file)
index 0000000..d644679
--- /dev/null
@@ -0,0 +1,232 @@
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <libgen.h>
+#include "rsb-lz.h"
+#include "filesystem.h"
+
+struct file_entry* get_next_file(unsigned char *fw, int len)
+{
+       static unsigned char *pos;
+       static unsigned char *start;
+       static unsigned char *end;
+       static struct file_entry fent;
+       int name_length;
+
+       if (fw != NULL && len != 0) {
+               pos = fw + 0x28;
+
+#if 0
+               printf("Start of filesystem: 0x%08x\n", *((unsigned int*)pos));
+#endif
+               start = fw;
+               pos = fw + *((unsigned int*)pos);
+               end = fw + len;
+       }
+
+       fent.unknown = *pos;
+       pos++;
+
+       if (fent.unknown == 0x00) {
+               /* EOF */
+               int fill = (4 - ((pos - start) % 4)) % 4;
+               int i;
+
+               for (i = 0; i < fill; i++) {
+                       if (*pos != 0xff) {
+                               fprintf(stderr, "Wrong fill byte after EOF: 0x%02x, aborting!\n", *pos);
+                               exit(1);
+                       }
+                       pos++;
+               }
+
+               if (pos != end) {
+                       fprintf(stderr, "EOF marker not at end-of-file %p <-> %p, aborting!\n", pos, end);
+                       exit(1);
+               }
+
+               return NULL;
+       }
+
+
+       name_length = *((unsigned int*)pos);
+       pos += 4;
+
+       fent.length = *((unsigned int*)pos);
+       pos += 4;
+
+       if ((fent.length > (end - pos)) ||
+           (name_length > (end - pos))) {
+               printf("EOF reached without hitting EOF marker, aborting "
+                       "(unknown: 0x%02x, namelen: 0x%08x, contentlen: 0x%08x!\n",
+                       fent.unknown, name_length, fent.length);
+               exit(1);
+       }
+
+       fent.name = (char*)pos;
+       pos += name_length;
+
+       fent.start = pos;
+       pos += fent.length;
+
+       return &fent;
+}
+
+void extract_files(unsigned char *fw, int len)
+{
+       struct file_entry *fent;
+
+       fent = get_next_file(fw, len);
+       
+       while (fent) {
+               printf("%s: unknown: 0x%02x, length: %d, ",
+                       fent->name, fent->unknown, fent->length);
+
+               if (fent->length > 0) {
+                       write_file(extracted_file(fent->name), fent->start, fent->length);
+                       if (*((unsigned int*)fent->start) == LZ_MAGIC) {
+                               char *lzname;
+                               unsigned char *outbuf;
+                               unsigned int outlen;
+
+                               if ((lzname = strdup(fent->name)) == NULL) {
+                                       perror("strdup");
+                                       exit(1);
+                               }
+
+                               if (!strcmp(lzname + strlen(lzname) - 4 , ".lz")) {
+                                       fprintf(stderr, "Ugh, can't derive filename...\n");
+                                       exit(1);
+                               }
+                               lzname[strlen(lzname) - 3] = 0x00;
+
+                               printf("%s: packed file found, ", lzname);
+
+                               outbuf = extract_lz_file(fent->start, &outlen, 0);
+                               write_file(extracted_file((char*)lzname), outbuf, outlen);
+
+                               free(outbuf);
+                               free(lzname);
+                       } else if (!strcmp(fent->name, "firmware")) {
+                               unsigned char *lzpos;
+                               char lzname[128];
+
+                               bzero(lzname, sizeof(lzname));
+                               strcpy(lzname, "firmware.");
+
+                               lzpos = fent->start + *((unsigned int*)(fent->start + 0x20));
+                               memcpy(lzname + strlen(lzname), lzpos - 4, 4);
+                               lzpos += 4;
+                               if (*((unsigned int*)(lzpos)) == LZ_MAGIC) {
+                                       unsigned char *outbuf;
+                                       unsigned int outlen;
+
+                                       printf("%s: compressed firmware part found", lzname);
+                                       outbuf = extract_lz_file(lzpos, &outlen, 1);
+                                       printf(", ");
+                                       write_file(extracted_file((char*)lzname), outbuf, outlen);
+
+                                       free(outbuf);
+                               }
+                       }
+               } else {
+                       printf(", ignoring...\n");
+               }
+               fent = get_next_file(NULL, 0);
+       }
+}
+
+void replace_add_file(unsigned char *fw, int len, char *fwname, char *lname)
+{
+       fprintf(stderr, "%s: Implement me!\n", __func__);
+       exit(1);
+}
+
+void list_files(unsigned char *fw, int len)
+{
+       struct file_entry *fent;
+
+       for (fent = get_next_file(fw, len); fent != NULL; fent = get_next_file(NULL, 0)) {
+               printf("0x%x %8d %s\n", fent->unknown, fent->length, fent->name);
+       }
+
+}
+
+void mkdir_p(char *dir)
+{
+       char *copy, *parent;
+
+       if ((dir == NULL) || (!strcmp(dir, ".")))
+               return;
+
+       if ((copy = strdup(dir)) == NULL) {
+               perror("strdup");
+               exit(1);
+       }
+       parent = dirname(copy);
+       mkdir_p(parent);
+
+       errno = 0;
+       if (mkdir(dir, 0755) == -1) {
+               if (errno != EEXIST) {
+                       fprintf(stderr, "%s: ", dir);
+                       perror("mkdir");
+                       exit(1);
+               }
+       }
+       free(copy);
+}
+
+void write_file(char *fname, unsigned char *buf, int len)
+{
+       char *filename_c, *dirn;
+       int fd;
+       int remaining;
+       int ret;
+
+       if ((filename_c = strdup(fname)) == NULL) {
+               perror("strdup");
+               exit(1);
+       }
+       dirn = dirname(filename_c);
+       mkdir_p(dirn);
+       free(filename_c);
+
+       if ((fd = open(fname, O_WRONLY|O_CREAT, 0644)) == -1) {
+               fprintf(stderr, "%s: ", fname);
+               perror("open");
+               exit(1);
+       }
+
+       remaining = len;
+
+       while(remaining) {
+               ret = write(fd, buf + (len - remaining), remaining);
+               if (ret < 0) {
+                       perror("write");
+                       exit(1);
+               }
+               remaining -= ret;
+       }
+
+       printf("%s written.\n", fname);
+
+       close(fd);
+}
+
+char *extracted_file(char *fname)
+{
+       static char filename[PATH_MAX];
+
+       strcpy(filename, "extracted/");
+       strcat(filename, fname);
+
+       return filename;
+}
Impressum, Datenschutz