#include #include #include #include #include #include #include #include #include "cfs.h" #define PUTC(c) putc(c, spitstream) static FILE *spitstream = NULL; void set_spit_stream(FILE *stream) { spitstream = stream; } int is_regular_file(char *path) { struct stat path_stat; stat(path, &path_stat); return S_ISREG(path_stat.st_mode); } void spitempty() { if (spitstream == NULL) spitstream = stdout; PUTC('C'); PUTC('F'); PUTC('S'); for (int i=0; i<0x20-3; i++) { PUTC(0); } } int spitblock(char *fullpath, char *fn) { if (spitstream == NULL) spitstream = stdout; FILE *fp = fopen(fullpath, "r"); fseek(fp, 0, SEEK_END); long fsize = ftell(fp); if (fsize > MAX_FILE_SIZE) { fclose(fp); fprintf(stderr, "File too big: %s %ld\n", fullpath, fsize); return 1; } /* Compute block count. * We always have at least one, which contains 0x100 bytes - 0x20, which is * metadata. The rest of the blocks have a steady 0x100. */ unsigned char blockcount = 1; int fsize2 = fsize - (BLKSIZE - HEADERSIZE); if (fsize2 > 0) { blockcount += (fsize2 / BLKSIZE); } if (blockcount * BLKSIZE < fsize + HEADERSIZE) { blockcount++; } PUTC('C'); PUTC('F'); PUTC('S'); PUTC(blockcount); // file size is little endian PUTC(fsize & 0xff); PUTC((fsize >> 8) & 0xff); int fnlen = strlen(fn); for (int i=0; id_name, ".") == 0) || strcmp(ep->d_name, "..") == 0) { continue; } if (ep->d_type != DT_DIR && ep->d_type != DT_REG) { fprintf(stderr, "Only regular file or directories are supported\n"); return 1; } int slen = strlen(ep->d_name); if (prefixlen + slen> MAX_FN_LEN) { fprintf(stderr, "Filename too long: %s/%s\n", prefix, ep->d_name); return 1; } char fullpath[0x1000]; strcpy(fullpath, path); strcat(fullpath, "/"); strcat(fullpath, ep->d_name); char newprefix[MAX_FN_LEN]; strcpy(newprefix, prefix); if (prefixlen > 0) { strcat(newprefix, "/"); } strcat(newprefix, ep->d_name); if (ep->d_type == DT_DIR) { int r = spitdir(fullpath, newprefix, patterns); if (r != 0) { return r; } } else { char **p = patterns; // if we have no pattern, we match all if (p && *p) { int matches = 0; while (*p) { if (fnmatch(*p, ep->d_name, 0) == 0) { matches = 1; break; } p++; } if (!matches) { continue; } } int r = spitblock(fullpath, newprefix); if (r != 0) { return r; } } } closedir(dp); return 0; }