mirror of
https://github.com/hsoft/collapseos.git
synced 2024-12-24 14:38:05 +11:00
tools: add blkunpack
and remove cfspack, which will not ever be used again.
This commit is contained in:
parent
5cb4a7de9a
commit
79ce88c12c
12
blk/001
12
blk/001
@ -2,3 +2,15 @@ MASTER INDEX
|
||||
|
||||
3 Usage 30 Dictionary
|
||||
70 Implementation notes 100 Block editor
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
4
blk/003
4
blk/003
@ -10,3 +10,7 @@ Contents
|
||||
4 DOES> 6 Compilation vs meta-comp.
|
||||
8 I/O 11 Chained comparisons
|
||||
14 Addressed devices 18 Signed-ness
|
||||
|
||||
|
||||
|
||||
|
||||
|
1
blk/004
1
blk/004
@ -13,3 +13,4 @@ At compile time, colon definition stops processing words when
|
||||
reaching the DOES>.
|
||||
|
||||
Example: ": CONSTANT CREATE HERE @ ! DOES> @ ;"
|
||||
|
||||
|
2
blk/009
2
blk/009
@ -12,3 +12,5 @@ new "(parse)" word.
|
||||
|
||||
This way, we have a full-featured (and extensible) parsing with
|
||||
a tiny native core.
|
||||
|
||||
|
||||
|
12
blk/016
12
blk/016
@ -2,3 +2,15 @@
|
||||
kind of ad-hoc way to have some kind of mapping function, but
|
||||
what you'll mostly want to to is to plug device drivers into
|
||||
those words.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
7
blk/018
7
blk/018
@ -7,3 +7,10 @@ support the "-" prefix, but under the hood, it's all unsigned.
|
||||
This leads to some oddities. For example, "-1 0 <" is false.
|
||||
To compare whether something is negative, use the "<0" word
|
||||
which is the equivalent to "0x7fff >".
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
5
blk/030
5
blk/030
@ -9,3 +9,8 @@ Be sure to read usage guide (B3) first.
|
||||
52 Addressed devices 54 Arithmetic / Bits
|
||||
56 Logic 58 Strings
|
||||
60 I/O 64 Disk
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
6
blk/032
6
blk/032
@ -8,3 +8,9 @@ Words between "()" are "support words" that aren't really meant
|
||||
to be used directly, but as part of another word.
|
||||
|
||||
"*I*" in description indicates an IMMEDIATE word.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
13
blk/035
13
blk/035
@ -1,3 +1,16 @@
|
||||
(cont.)
|
||||
~ - Container for native code. Usually not an executable word.
|
||||
? - Is it ...? (example: IMMED?)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
10
blk/038
10
blk/038
@ -4,3 +4,13 @@ FORGET x -- Rewind the dictionary (both CURRENT and HERE)
|
||||
PREV a -- a Return a wordref's previous entry.
|
||||
WHLEN a -- n Get word header length from wordref. That is,
|
||||
name length + 3. a is a wordref
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
1
blk/043
1
blk/043
@ -13,3 +13,4 @@ INTERPRET -- Get a line from stdin, compile it in tmp memory,
|
||||
then execute the compiled contents.
|
||||
QUIT -- Return to interpreter prompt immediately
|
||||
EXIT! -- Exit current INTERPRET loop.
|
||||
|
||||
|
5
blk/046
5
blk/046
@ -9,3 +9,8 @@ SWAP a b -- b a
|
||||
2DUP a b -- a b a b
|
||||
2OVER a b c d -- a b c d a b
|
||||
2SWAP a b c d -- c d a b
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
9
blk/048
9
blk/048
@ -5,3 +5,12 @@ R> R:n -- n Pops RS and push to PS
|
||||
I -- n Copy RS TOS to PS
|
||||
I' -- n Copy RS second item to PS
|
||||
J -- n Copy RS third item to PS
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
6
blk/052
6
blk/052
@ -8,3 +8,9 @@ A! c a -- Indirect C!
|
||||
A@* -- a Address for A@ word
|
||||
A!* -- a Address for A! word
|
||||
AMOVE src dst u -- Same as MOVE, but with A@ and A!
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
2
blk/054
2
blk/054
@ -12,3 +12,5 @@ OR a b -- c a | b -> c
|
||||
XOR a b -- c a ^ b -> c
|
||||
|
||||
Shortcuts: 1+ 2+ 1- 2-
|
||||
|
||||
|
||||
|
8
blk/056
8
blk/056
@ -6,3 +6,11 @@ Logic
|
||||
CMP n1 n2 -- n Compare n1 and n2 and set n to -1, 0, or 1.
|
||||
n=0: a1=a2. n=1: a1>a2. n=-1: a1<a2.
|
||||
NOT f -- f Push the logical opposite of f
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
6
blk/058
6
blk/058
@ -8,3 +8,9 @@ LITS a -- Write word at addr a as a atring literal.
|
||||
S= a1 a2 -- f Returns whether string a1 == a2.
|
||||
SCPY a -- Copy string at addr a into HERE.
|
||||
SLEN a -- n Push length of str at a.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
10
blk/064
10
blk/064
@ -4,3 +4,13 @@ BLK> -- a Address of the current block variable.
|
||||
LIST n -- Prints the contents of the block n on screen in the
|
||||
form of 16 lines of 64 columns.
|
||||
LOAD n -- Interprets Forth code from block n
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
10
blk/070
10
blk/070
@ -4,3 +4,13 @@ Implementation notes
|
||||
75 Stack management 77 Dictionary
|
||||
80 System variables 85 Word routines
|
||||
89 Initialization sequence
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
5
blk/071
5
blk/071
@ -9,3 +9,8 @@ it. As a general rule, we go like this:
|
||||
4. Is it a number?
|
||||
5. If yes, push that number to PS, goto 1
|
||||
6. Error: undefined word.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
2
blk/075
2
blk/075
@ -12,3 +12,5 @@ IX always points to RS' Top Of Stack (TOS)
|
||||
This return stack contain "Interpreter pointers", that is a
|
||||
pointer to the address of a word, as seen in a compiled list of
|
||||
words.
|
||||
|
||||
|
||||
|
4
blk/078
4
blk/078
@ -10,3 +10,7 @@ chain). There are also "special words", for example NUMBER,
|
||||
LIT, FBR, that have a slightly different structure. They're
|
||||
also a pointer to an executable, but as for the other fields,
|
||||
the only one they have is the "flags" field.
|
||||
|
||||
|
||||
|
||||
|
||||
|
10
blk/084
10
blk/084
@ -4,3 +4,13 @@ DRIVERS section is reserved for recipe-specific
|
||||
drivers. Here is a list of known usages:
|
||||
|
||||
* 0x70-0x78: ACIA buffer pointers in RC2014 recipes.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
10
blk/087
10
blk/087
@ -4,3 +4,13 @@ being followed by a 2 byte number, it is followed by a
|
||||
null-terminated string. Upon execution, the address of that
|
||||
null-terminated string is pushed on the PSP and IP is advanced
|
||||
to the address following the null.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
9
blk/091
9
blk/091
@ -5,3 +5,12 @@ for space with HERE: New entries to the dict will overwrite
|
||||
that code! Also, because we're barebone, we can't have
|
||||
comments. This can lead to peculiar code in this area where we
|
||||
try to "waste" space in initialization code.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
14
blk/101
14
blk/101
@ -1,2 +1,16 @@
|
||||
T ( n -- ): select line n for editing.
|
||||
P xxx(return): put typed line on selected line.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
6
blk/103
6
blk/103
@ -8,3 +8,9 @@ VARIABLE ACC
|
||||
: L BLK> @ _LIST ;
|
||||
: B BLK> @ 1- BLK> ! L ;
|
||||
: N BLK> @ 1+ BLK> ! L ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
1
tools/.gitignore
vendored
1
tools/.gitignore
vendored
@ -9,3 +9,4 @@
|
||||
/bin2c
|
||||
/exec
|
||||
/blkpack
|
||||
/blkunpack
|
||||
|
@ -9,9 +9,10 @@ STRIPFC_TGT = stripfc
|
||||
BIN2C_TGT = bin2c
|
||||
EXEC_TGT = exec
|
||||
BLKPACK_TGT = blkpack
|
||||
BLKUNPACK_TGT = blkunpack
|
||||
TARGETS = $(MEMDUMP_TGT) $(BLKDUMP_TGT) $(UPLOAD_TGT) $(FONTCOMPILE_TGT) \
|
||||
$(TTYSAFE_TGT) $(PINGPONG_TGT) $(SLATEST_TGT) $(STRIPFC_TGT) \
|
||||
$(BIN2C_TGT) $(EXEC_TGT) $(BLKPACK_TGT)
|
||||
$(BIN2C_TGT) $(EXEC_TGT) $(BLKPACK_TGT) $(BLKUNPACK_TGT)
|
||||
OBJS = common.o
|
||||
|
||||
all: $(TARGETS)
|
||||
@ -31,6 +32,7 @@ $(STRIPFC_TGT): $(STRIPFC_TGT).c
|
||||
$(BIN2C_TGT): $(BIN2C_TGT).c
|
||||
$(EXEC_TGT): $(EXEC_TGT).c
|
||||
$(BLKPACK_TGT): $(BLKPACK_TGT).c
|
||||
$(BLKUNPACK_TGT): $(BLKUNPACK_TGT).c
|
||||
$(TARGETS): $(OBJS)
|
||||
$(CC) $(CFLAGS) $@.c $(OBJS) -o $@
|
||||
|
||||
|
44
tools/blkunpack.c
Normal file
44
tools/blkunpack.c
Normal file
@ -0,0 +1,44 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
void usage()
|
||||
{
|
||||
fprintf(stderr, "Usage: blkunpack dirname\n");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char buf[1024];
|
||||
int blkid = 0;
|
||||
if (argc != 2) {
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
while (fread(buf, 1024, 1, stdin) == 1) {
|
||||
char fullpath[0x200];
|
||||
sprintf(fullpath, "%s/%03d", argv[1], blkid);
|
||||
char c = 0;
|
||||
for (int i=0; i<1024; i++) {
|
||||
c |= buf[i];
|
||||
}
|
||||
if (c) {
|
||||
// not an empty block
|
||||
printf("%s\n", fullpath);
|
||||
FILE *fp = fopen(fullpath, "w");
|
||||
for (int i=0; i<16; i++) {
|
||||
int len = strlen(&buf[i*64]);
|
||||
fwrite(&buf[i*64], len, 1, fp);
|
||||
fputc('\n', fp);
|
||||
}
|
||||
fclose(fp);
|
||||
} else {
|
||||
// empty block, delete
|
||||
unlink(fullpath);
|
||||
}
|
||||
blkid++;
|
||||
}
|
||||
return 0;
|
||||
}
|
2
tools/cfspack/.gitignore
vendored
2
tools/cfspack/.gitignore
vendored
@ -1,2 +0,0 @@
|
||||
/cfspack
|
||||
/cfsunpack
|
@ -1,16 +0,0 @@
|
||||
TARGETS = cfspack cfsunpack
|
||||
|
||||
CFSPACK_OBJS = cfspack.o libcfs.o
|
||||
|
||||
.PHONY: all
|
||||
all: $(TARGETS)
|
||||
|
||||
cfspack: $(CFSPACK_OBJS)
|
||||
$(CC) $(LDFLAGS) -o $@ $(CFSPACK_OBJS)
|
||||
|
||||
cfsunpack: cfsunpack.c
|
||||
$(CC) $(CFLAGS) -o $@ cfsunpack.c
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f $(TARGETS)
|
@ -1,33 +0,0 @@
|
||||
# cfspack
|
||||
|
||||
A tool/library to pack files into a CFS blob and unpack a CFS blob into
|
||||
a directory.
|
||||
|
||||
## Usage
|
||||
|
||||
To pack a directory into a CFS blob, run:
|
||||
|
||||
cfspack /path/to/directory
|
||||
|
||||
The blob is spit to stdout. If there are subdirectories, they will be prefixes
|
||||
to the filenames under it.
|
||||
|
||||
`cfspack` takes optional -p pattern arguments. If specified, only files
|
||||
matching at least one of the patterns ("fnmatch" style") will be included.
|
||||
|
||||
If path is a file, a CFS with a single file will be spit and its name will
|
||||
exclude the directory part of that filename.
|
||||
|
||||
The chain being spitted is always ended with a "stop block" (a zero-allocation
|
||||
block that stops the CFS chain). You can call `cfspack` with no argument to get
|
||||
only a stop block.
|
||||
|
||||
The program errors out if a file name is too long (> 26 bytes) or too big
|
||||
(> 0x10000 - 0x20 bytes).
|
||||
|
||||
To unpack a blob to a directory:
|
||||
|
||||
cfsunpack /path/to/dest < blob
|
||||
|
||||
If destination exists, files are created alongside existing ones. If a file to
|
||||
unpack already exists, it is overwritten.
|
@ -1,10 +0,0 @@
|
||||
#define BLKSIZE 0x100
|
||||
#define HEADERSIZE 0x20
|
||||
#define MAX_FN_LEN 25 // 26 - null char
|
||||
#define MAX_FILE_SIZE (BLKSIZE * 0x100) - HEADERSIZE
|
||||
|
||||
void set_spit_stream(FILE *stream);
|
||||
int is_regular_file(char *path);
|
||||
void spitempty();
|
||||
int spitblock(char *fullpath, char *fn);
|
||||
int spitdir(char *path, char *prefix, char **patterns);
|
@ -1,54 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <string.h>
|
||||
#include <fnmatch.h>
|
||||
#include <libgen.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "cfs.h"
|
||||
|
||||
void usage()
|
||||
{
|
||||
fprintf(stderr, "Usage: cfspack [-p pattern] [/path/to/dir...]\n");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int patterncount = 0;
|
||||
char **patterns = malloc(sizeof(char**));
|
||||
patterns[0] = NULL;
|
||||
while (1) {
|
||||
int c = getopt(argc, argv, "p:");
|
||||
if (c < 0) {
|
||||
break;
|
||||
}
|
||||
switch (c) {
|
||||
case 'p':
|
||||
patterns[patterncount] = optarg;
|
||||
patterncount++;
|
||||
patterns = realloc(patterns, sizeof(char**)*(patterncount+1));
|
||||
patterns[patterncount] = NULL;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
int res = 0;
|
||||
for (int i=optind; i<argc; i++) {
|
||||
if (is_regular_file(argv[i])) {
|
||||
// special case: just one file
|
||||
res = spitblock(argv[i], basename(argv[i]));
|
||||
} else {
|
||||
res = spitdir(argv[i], "", patterns);
|
||||
}
|
||||
}
|
||||
if (res == 0) {
|
||||
spitempty();
|
||||
}
|
||||
free(patterns);
|
||||
return res;
|
||||
}
|
||||
|
@ -1,93 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#define BLKSIZE 0x100
|
||||
#define HEADERSIZE 0x20
|
||||
#define MAX_FN_LEN 25 // 26 - null char
|
||||
|
||||
bool ensuredir(char *path)
|
||||
{
|
||||
char *s = path;
|
||||
while (*s != '\0') {
|
||||
if (*s == '/') {
|
||||
*s = '\0';
|
||||
struct stat path_stat;
|
||||
if (stat(path, &path_stat) != 0) {
|
||||
if (mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
*s = '/';
|
||||
}
|
||||
s++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool unpackblk(char *dstpath)
|
||||
{
|
||||
char buf[MAX_FN_LEN+1];
|
||||
if (fgets(buf, 3+1, stdin) == NULL) {
|
||||
return false;
|
||||
}
|
||||
if (strcmp(buf, "CFS") != 0) {
|
||||
return false;
|
||||
}
|
||||
int c = getchar();
|
||||
uint8_t blkcnt = c;
|
||||
if (blkcnt == 0) {
|
||||
return false;
|
||||
}
|
||||
c = getchar();
|
||||
uint16_t fsize = c & 0xff;
|
||||
c = getchar();
|
||||
fsize |= (c & 0xff) << 8;
|
||||
|
||||
if (fgets(buf, MAX_FN_LEN+1+1, stdin) == NULL) {
|
||||
return false;
|
||||
}
|
||||
char fullpath[0x1000];
|
||||
strcpy(fullpath, dstpath);
|
||||
strcat(fullpath, "/");
|
||||
strcat(fullpath, buf);
|
||||
if (!ensuredir(fullpath)) {
|
||||
return false;
|
||||
}
|
||||
int blksize = (BLKSIZE-HEADERSIZE)+(BLKSIZE*(blkcnt-1));
|
||||
int skipcount = blksize - fsize;
|
||||
FILE *fp = fopen(fullpath, "w");
|
||||
while (fsize) {
|
||||
c = getchar();
|
||||
if (c == EOF) {
|
||||
return false;
|
||||
}
|
||||
fputc(c, fp);
|
||||
fsize--;
|
||||
}
|
||||
fclose(fp);
|
||||
while (skipcount) {
|
||||
getchar();
|
||||
skipcount--;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "Usage: cfspack /path/to/dest\n");
|
||||
return 1;
|
||||
}
|
||||
char *dstpath = argv[1];
|
||||
// we fail if there isn't at least one block
|
||||
if (!unpackblk(dstpath)) {
|
||||
return 1;
|
||||
}
|
||||
while (unpackblk(dstpath));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1,152 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <string.h>
|
||||
#include <fnmatch.h>
|
||||
#include <libgen.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#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; i<MAX_FN_LEN; i++) {
|
||||
if (i < fnlen) {
|
||||
PUTC(fn[i]);
|
||||
} else {
|
||||
PUTC(0);
|
||||
}
|
||||
}
|
||||
// And the last FN char which is always null
|
||||
PUTC(0);
|
||||
char buf[MAX_FILE_SIZE] = {0};
|
||||
rewind(fp);
|
||||
fread(buf, fsize, 1, fp);
|
||||
fclose(fp);
|
||||
fwrite(buf, (blockcount * BLKSIZE) - HEADERSIZE, 1, spitstream);
|
||||
fflush(spitstream);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spitdir(char *path, char *prefix, char **patterns)
|
||||
{
|
||||
DIR *dp;
|
||||
struct dirent *ep;
|
||||
|
||||
int prefixlen = strlen(prefix);
|
||||
dp = opendir(path);
|
||||
if (dp == NULL) {
|
||||
fprintf(stderr, "Couldn't open directory.\n");
|
||||
return 1;
|
||||
}
|
||||
while ((ep = readdir(dp))) {
|
||||
if ((strcmp(ep->d_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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user