mirror of
https://github.com/bobbimanners/GNO-Extras.git
synced 2024-12-22 02:30:17 +00:00
Added recursive mode to sortdir
This commit is contained in:
parent
219fa311f9
commit
8d8511f331
@ -1,8 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Bobbi January-February 2020
|
* Bobbi January-February 2020
|
||||||
*
|
*
|
||||||
* TODO: Fix bug where some file blocks reported as free
|
* TODO: Whole volume mode - check all unused blocks are free
|
||||||
* TODO: Recursive / whole volume mode - check all unused blocks are free
|
|
||||||
* TODO: Check no disk blocks are used more than once
|
* TODO: Check no disk blocks are used more than once
|
||||||
* TODO: Fix mode
|
* TODO: Fix mode
|
||||||
* TODO: Tool for 'extending' volume dir to more than 4 blocks
|
* TODO: Tool for 'extending' volume dir to more than 4 blocks
|
||||||
@ -105,19 +104,30 @@ struct fileent {
|
|||||||
uchar entrynum; /* Entry within the block */
|
uchar entrynum; /* Entry within the block */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Entry for list of directory keyblocks to check
|
||||||
|
*/
|
||||||
|
struct dirblk {
|
||||||
|
uint blocknum;
|
||||||
|
struct dirblk *next;
|
||||||
|
};
|
||||||
|
|
||||||
/* Globals */
|
/* Globals */
|
||||||
static uchar freelist[8096]; /* 1 bit for each of 64K blocks */
|
static uchar freelist[8096]; /* 1 bit for each of 64K blocks */
|
||||||
static uchar flloaded = 0;
|
static uchar flloaded = 0;
|
||||||
static struct block *blocks = NULL;
|
static struct block *blocks = NULL;
|
||||||
|
static struct dirblk *dirs = NULL;
|
||||||
static struct fileent filelist[MAXFILES];
|
static struct fileent filelist[MAXFILES];
|
||||||
static uint numfiles = 0;
|
static uint numfiles;
|
||||||
static uchar entsz; /* Bytes per file entry */
|
static uchar entsz; /* Bytes per file entry */
|
||||||
static uchar entperblk; /* Number of entries per block */
|
static uchar entperblk; /* Number of entries per block */
|
||||||
static char buf[BLKSZ]; /* General purpose scratch buffer */
|
static char buf[BLKSZ]; /* General purpose scratch buffer */
|
||||||
static char buf2[BLKSZ]; /* General purpose scratch buffer */
|
static char buf2[BLKSZ]; /* General purpose scratch buffer */
|
||||||
static char buf3[BLKSZ]; /* General purpose scratch buffer */
|
static char buf3[BLKSZ]; /* General purpose scratch buffer */
|
||||||
|
static uchar dorecurse = 0;
|
||||||
static uchar dowrite = 0;
|
static uchar dowrite = 0;
|
||||||
static uchar doverbose = 0;
|
static uchar doverbose = 0;
|
||||||
|
static uchar dodebug = 0;
|
||||||
static char sortopts[5] = "";
|
static char sortopts[5] = "";
|
||||||
|
|
||||||
/* Prototypes */
|
/* Prototypes */
|
||||||
@ -132,6 +142,7 @@ int treeblocks(uchar device, uint keyblk, uint *blkcnt);
|
|||||||
int forkblocks(uchar device, uint keyblk, uint *blkcnt);
|
int forkblocks(uchar device, uint keyblk, uint *blkcnt);
|
||||||
int subdirblocks(uchar device, uint keyblk, struct pd_dirent *ent,
|
int subdirblocks(uchar device, uint keyblk, struct pd_dirent *ent,
|
||||||
uint blocknum, uint blkentries, uint *blkcnt);
|
uint blocknum, uint blkentries, uint *blkcnt);
|
||||||
|
void enqueuesubdir(uint blocknum);
|
||||||
int readdir(uint device, uint blocknum);
|
int readdir(uint device, uint blocknum);
|
||||||
int cmp_name_asc(const void *a, const void *b);
|
int cmp_name_asc(const void *a, const void *b);
|
||||||
int cmp_name_desc(const void *a, const void *b);
|
int cmp_name_desc(const void *a, const void *b);
|
||||||
@ -141,11 +152,14 @@ int cmp_dir_beg(const void *a, const void *b);
|
|||||||
int cmp_dir_end(const void *a, const void *b);
|
int cmp_dir_end(const void *a, const void *b);
|
||||||
void sortlist(char s);
|
void sortlist(char s);
|
||||||
void printlist(void);
|
void printlist(void);
|
||||||
|
uint blockidxtoblocknum(uint idx);
|
||||||
void copyent(uint srcblk, uint srcent, uint dstblk, uint dstent, uint device);
|
void copyent(uint srcblk, uint srcent, uint dstblk, uint dstent, uint device);
|
||||||
void sortblocks(uint device);
|
void sortblocks(uint device);
|
||||||
int writedir(uchar device);
|
int writedir(uchar device);
|
||||||
void freeblocks(void);
|
void freeblocks(void);
|
||||||
|
void freedirs(void);
|
||||||
void usage(void);
|
void usage(void);
|
||||||
|
void processonedir(uint device, uint blocknum);
|
||||||
|
|
||||||
/* Print error string to stderr */
|
/* Print error string to stderr */
|
||||||
void prerr(char *s) {
|
void prerr(char *s) {
|
||||||
@ -507,6 +521,26 @@ int subdirblocks(uchar device, uint keyblk, struct pd_dirent *ent,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Record the keyblock of a subdirectory to be processed subsequently
|
||||||
|
*/
|
||||||
|
void enqueuesubdir(uint blocknum) {
|
||||||
|
struct dirblk *p = (struct dirblk*)malloc(sizeof(struct dirblk));
|
||||||
|
if (!p) {
|
||||||
|
puts("** Unable to allocate memory **");
|
||||||
|
exit(3);
|
||||||
|
}
|
||||||
|
p->blocknum = blocknum;
|
||||||
|
p->next = NULL;
|
||||||
|
static struct dirblk *end;
|
||||||
|
if (!dirs)
|
||||||
|
end = dirs = p;
|
||||||
|
else {
|
||||||
|
end->next = p;
|
||||||
|
end = p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read a directory, store the raw directory blocks in a linked list
|
* Read a directory, store the raw directory blocks in a linked list
|
||||||
* and build filelist[] in preparation for sorting.
|
* and build filelist[] in preparation for sorting.
|
||||||
@ -517,10 +551,12 @@ int readdir(uint device, uint blocknum) {
|
|||||||
uint blkcnt = 1;
|
uint blkcnt = 1;
|
||||||
uint hdrblknum = blocknum;
|
uint hdrblknum = blocknum;
|
||||||
|
|
||||||
|
numfiles = 0;
|
||||||
|
|
||||||
blocks = (struct block*)malloc(sizeof(struct block));
|
blocks = (struct block*)malloc(sizeof(struct block));
|
||||||
if (!blocks) {
|
if (!blocks) {
|
||||||
puts("Unable to allocate memory");
|
puts("** Unable to allocate memory **");
|
||||||
return 1;
|
exit(3);
|
||||||
}
|
}
|
||||||
struct block *curblk = blocks;
|
struct block *curblk = blocks;
|
||||||
curblk->next = NULL;
|
curblk->next = NULL;
|
||||||
@ -617,6 +653,7 @@ int readdir(uint device, uint blocknum) {
|
|||||||
switch (ent->typ_len & 0xf0) {
|
switch (ent->typ_len & 0xf0) {
|
||||||
case 0xd0:
|
case 0xd0:
|
||||||
/* Subdirectory */
|
/* Subdirectory */
|
||||||
|
enqueuesubdir(keyblk);
|
||||||
subdirblocks(device, keyblk, ent,
|
subdirblocks(device, keyblk, ent,
|
||||||
blocknum, blkentries, &count);
|
blocknum, blkentries, &count);
|
||||||
break;
|
break;
|
||||||
@ -672,7 +709,7 @@ int readdir(uint device, uint blocknum) {
|
|||||||
(struct block*)malloc(sizeof(struct block));
|
(struct block*)malloc(sizeof(struct block));
|
||||||
if (!curblk->next) {
|
if (!curblk->next) {
|
||||||
puts("** Unable to allocate memory **");
|
puts("** Unable to allocate memory **");
|
||||||
return 1;
|
exit(3);
|
||||||
}
|
}
|
||||||
curblk = curblk->next;
|
curblk = curblk->next;
|
||||||
curblk->next = NULL;
|
curblk->next = NULL;
|
||||||
@ -818,17 +855,39 @@ void printlist(void) {
|
|||||||
puts("---------------------------------------------------------");
|
puts("---------------------------------------------------------");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert block index to block number
|
||||||
|
* Block index is 1-based (1,2,3 ...)
|
||||||
|
*/
|
||||||
|
uint blockidxtoblocknum(uint idx) {
|
||||||
|
struct block *p = blocks;
|
||||||
|
for (uint i=1; i<idx; ++i)
|
||||||
|
if (p)
|
||||||
|
p = p->next;
|
||||||
|
else {
|
||||||
|
puts("** Internal error **");
|
||||||
|
exit(3);
|
||||||
|
}
|
||||||
|
if (!p) {
|
||||||
|
puts("** Internal error **");
|
||||||
|
exit(3);
|
||||||
|
}
|
||||||
|
return p->blocknum;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copy a file entry from one srcblk, srcent to dstblk, dstent
|
* Copy a file entry from one srcblk, srcent to dstblk, dstent
|
||||||
* All indices are 1-based.
|
* All indices are 1-based.
|
||||||
*/
|
*/
|
||||||
void copyent(uint srcblk, uint srcent, uint dstblk, uint dstent, uint device) {
|
void copyent(uint srcblk, uint srcent, uint dstblk, uint dstent, uint device) {
|
||||||
|
|
||||||
if (doverbose) {
|
if (dodebug) {
|
||||||
printf(" from dirblk %03u entry %02u\n", srcblk, srcent);
|
printf(" from dirblk %03u entry %02u\n", srcblk, srcent);
|
||||||
printf(" to dirblk %03u entry %02u\n", dstblk, dstent);
|
printf(" to dirblk %03u entry %02u\n", dstblk, dstent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint parentblk = blockidxtoblocknum(dstblk);
|
||||||
|
|
||||||
struct block *source = blocks;
|
struct block *source = blocks;
|
||||||
struct block *dest = blocks;
|
struct block *dest = blocks;
|
||||||
while (--srcblk > 0)
|
while (--srcblk > 0)
|
||||||
@ -848,6 +907,8 @@ void copyent(uint srcblk, uint srcent, uint dstblk, uint dstent, uint device) {
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
struct pd_dirhdr *hdr = (struct pd_dirhdr*)(buf + PTRSZ);
|
struct pd_dirhdr *hdr = (struct pd_dirhdr*)(buf + PTRSZ);
|
||||||
|
hdr->parptr[0] = parentblk & 0xff;
|
||||||
|
hdr->parptr[1] = (parentblk >> 8) & 0xff;
|
||||||
hdr->parentry = dstent;
|
hdr->parentry = dstent;
|
||||||
if (dowrite) {
|
if (dowrite) {
|
||||||
if (writediskblock(device, block, buf) == -1) {
|
if (writediskblock(device, block, buf) == -1) {
|
||||||
@ -869,6 +930,7 @@ void sortblocks(uint device) {
|
|||||||
uchar destblk = 1;
|
uchar destblk = 1;
|
||||||
uchar destentry = 2; /* Skip header on first block */
|
uchar destentry = 2; /* Skip header on first block */
|
||||||
for(uint i=0; i<numfiles; ++i) {
|
for(uint i=0; i<numfiles; ++i) {
|
||||||
|
if (dodebug)
|
||||||
puts(filelist[i].name);
|
puts(filelist[i].name);
|
||||||
copyent(filelist[i].blockidx, filelist[i].entrynum,
|
copyent(filelist[i].blockidx, filelist[i].entrynum,
|
||||||
destblk, destentry, device);
|
destblk, destentry, device);
|
||||||
@ -904,13 +966,26 @@ void freeblocks(void) {
|
|||||||
free(i);
|
free(i);
|
||||||
i = j;
|
i = j;
|
||||||
}
|
}
|
||||||
|
blocks = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void freedirs(void) {
|
||||||
|
struct dirblk *i = dirs, *j;
|
||||||
|
while (i) {
|
||||||
|
j = i->next;
|
||||||
|
free(i);
|
||||||
|
i = j;
|
||||||
|
}
|
||||||
|
dirs = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void usage(void) {
|
void usage(void) {
|
||||||
prerr("usage: sortdir [-s xxx] [-rwv] path\n");
|
prerr("usage: sortdir [-s xxx] [-rwv] path\n");
|
||||||
prerr(" Options: -s xxx Directory sort options");
|
prerr(" Options: -s xxx Directory sort options");
|
||||||
|
prerr(" -r Recursive descent");
|
||||||
prerr(" -w Enable writing to disk");
|
prerr(" -w Enable writing to disk");
|
||||||
prerr(" -v Verbose output");
|
prerr(" -v Verbose output");
|
||||||
|
prerr(" -V Verbose debugging output");
|
||||||
prerr(" -h This help");
|
prerr(" -h This help");
|
||||||
prerr("");
|
prerr("");
|
||||||
prerr("Directory sort options xxx, is a list of fields on which to");
|
prerr("Directory sort options xxx, is a list of fields on which to");
|
||||||
@ -929,14 +1004,52 @@ void usage(void) {
|
|||||||
exit(2);
|
exit(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Performs all actions for a single directory
|
||||||
|
* blocknum is the keyblock of the directory to process
|
||||||
|
*/
|
||||||
|
void processonedir(uint device, uint blocknum) {
|
||||||
|
uchar err = readdir(device, blocknum);
|
||||||
|
if (doverbose) {
|
||||||
|
printlist();
|
||||||
|
}
|
||||||
|
if (err) {
|
||||||
|
puts("Error scanning directory, will not sort");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (strlen(sortopts) > 0) {
|
||||||
|
for (uchar i=0; i<strlen(sortopts); ++i) {
|
||||||
|
if (doverbose) {
|
||||||
|
printf("Sorting - order '%c' ...\n",
|
||||||
|
sortopts[i]);
|
||||||
|
}
|
||||||
|
sortlist(sortopts[i]);
|
||||||
|
}
|
||||||
|
sortblocks(device);
|
||||||
|
if (doverbose) {
|
||||||
|
puts("After sorting ...");
|
||||||
|
printlist();
|
||||||
|
}
|
||||||
|
if (dowrite)
|
||||||
|
err = writedir(device);
|
||||||
|
else if (doverbose)
|
||||||
|
puts("Not writing to disk without -w");
|
||||||
|
}
|
||||||
|
done:
|
||||||
|
freeblocks();
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
usage();
|
usage();
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
int opt;
|
int opt;
|
||||||
while ((opt = getopt(argc, argv, "hwvs:")) != -1) {
|
while ((opt = getopt(argc, argv, "rhwvVs:")) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
|
case 'r':
|
||||||
|
dorecurse = 1;
|
||||||
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
strncpy(sortopts, optarg, 5);
|
strncpy(sortopts, optarg, 5);
|
||||||
break;
|
break;
|
||||||
@ -946,13 +1059,16 @@ int main(int argc, char *argv[]) {
|
|||||||
case 'v':
|
case 'v':
|
||||||
doverbose = 1;
|
doverbose = 1;
|
||||||
break;
|
break;
|
||||||
|
case 'V':
|
||||||
|
dodebug = 1;
|
||||||
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
default:
|
default:
|
||||||
usage();
|
usage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (optind >= argc)
|
if (optind != argc - 1)
|
||||||
usage();
|
usage();
|
||||||
|
|
||||||
uchar dev;
|
uchar dev;
|
||||||
@ -961,24 +1077,15 @@ int main(int argc, char *argv[]) {
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
readfreelist(dev);
|
readfreelist(dev);
|
||||||
uchar err = readdir(dev, blk);
|
processonedir(dev, blk);
|
||||||
if (!err) {
|
if (dorecurse) {
|
||||||
if (doverbose)
|
struct dirblk *d = dirs;
|
||||||
printlist();
|
while (d) {
|
||||||
if (strlen(sortopts) > 0) {
|
processonedir(dev, d->blocknum);
|
||||||
for (uchar i=0; i<strlen(sortopts); ++i)
|
d = d->next;
|
||||||
sortlist(sortopts[i]);
|
|
||||||
sortblocks(dev);
|
|
||||||
if (doverbose)
|
|
||||||
printlist();
|
|
||||||
if (dowrite)
|
|
||||||
err = writedir(dev);
|
|
||||||
else
|
|
||||||
if (doverbose)
|
|
||||||
puts("Not writing to disk");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
freeblocks();
|
freedirs();
|
||||||
return err;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user