806 lines
20 KiB
C
806 lines
20 KiB
C
|
/* tikidisk.c V1.1
|
|||
|
*
|
|||
|
* CP/M-2.2 filsystem som jobber mot TIKI-100 diskettfiler
|
|||
|
*
|
|||
|
* Burde fungere med alle CP/M-2.2 diskettfiler, bare riktige diskparametre oppgis.
|
|||
|
* Forel<EFBFBD>pig kjenner programmet bare igjen TIKI-100 diskettfiler.
|
|||
|
*
|
|||
|
* Copyright (c) Asbj<EFBFBD>rn Djupdal 2001
|
|||
|
*/
|
|||
|
|
|||
|
#include <stdio.h>
|
|||
|
#include <ctype.h>
|
|||
|
#include <string.h>
|
|||
|
#include <stdlib.h>
|
|||
|
|
|||
|
typedef unsigned char byte;
|
|||
|
typedef unsigned short word;
|
|||
|
typedef short boolean;
|
|||
|
|
|||
|
#ifndef TRUE
|
|||
|
#define TRUE ~0
|
|||
|
#endif
|
|||
|
#ifndef FALSE
|
|||
|
#define FALSE 0
|
|||
|
#endif
|
|||
|
#ifndef NULL
|
|||
|
#define NULL 0
|
|||
|
#endif
|
|||
|
|
|||
|
#define DISK90K 1*40*18*128
|
|||
|
#define DISK200K 1*40*10*512
|
|||
|
#define DISK400K 2*40*10*512
|
|||
|
#define DISK800K 2*80*10*512
|
|||
|
|
|||
|
/* protos */
|
|||
|
int main (int argc, char *argv[]);
|
|||
|
|
|||
|
void saveFile (byte *entry);
|
|||
|
void addFile (char *efn, byte user);
|
|||
|
void delFile (char *ffn, byte user);
|
|||
|
|
|||
|
byte *getEntry (int entryNumber);
|
|||
|
byte *getExtent (byte *entry, int extentNumber);
|
|||
|
byte *getMatch (char *ffn, byte user);
|
|||
|
byte *getSector (int sectorNumber);
|
|||
|
|
|||
|
int getExtentNumber (byte *entry);
|
|||
|
void setExtentNumber (byte *entry, int extentNumber);
|
|||
|
int getBytesInEntry (byte *entry);
|
|||
|
void setBytesInEntry (byte *entry, int bytesInExtent);
|
|||
|
int getBlockNumber (byte *entry, int alNumber);
|
|||
|
void setBlockNumber (byte *entry, int alNumber, int blockNumber);
|
|||
|
|
|||
|
void getFilename (char *filename, byte *entry);
|
|||
|
int getFilesize (byte *entry);
|
|||
|
byte getUsernumber (byte *entry);
|
|||
|
void getAttribs (char *attribs, byte *entry);
|
|||
|
void setNameAndUser (byte *ffnEntry, char *ffn, byte user);
|
|||
|
|
|||
|
void buildBAM (void);
|
|||
|
int allocateBlock (void);
|
|||
|
|
|||
|
boolean entryNotDeleted (byte *entry);
|
|||
|
void deleteEntry (byte *entry);
|
|||
|
boolean entryEquals (byte *ffnEntry, byte *entry);
|
|||
|
char legalChar (char c);
|
|||
|
char *stripPath (char *ffn);
|
|||
|
|
|||
|
/* globals */
|
|||
|
byte diskImage[DISK800K]; /* her legges diskettfil */
|
|||
|
boolean *bam = NULL; /* Block Availability Map */
|
|||
|
|
|||
|
int numberOfEntries; /* antall kataloginnganger */
|
|||
|
int systemSectors; /* antall sektorer med bootkode */
|
|||
|
int sectorSize; /* bytes pr. sektor */
|
|||
|
int *convertSectorNumber; /* tabell som mapper sektornummer */
|
|||
|
int sectorsPerTrack; /* antall sektorer pr. spor */
|
|||
|
int exm; /* antall bytes pr. AL */
|
|||
|
int bytesPerAL; /* blokkst<73>rrelse */
|
|||
|
int blockSize; /* bytes pr. blokk */
|
|||
|
int sectorsPerBlock; /* sektorer pr. blokk */
|
|||
|
int numberOfBlocks; /* antall blokker (untatt systemsektorer) */
|
|||
|
int directoryBlocks; /* antall blokker brukt av kataloginnganger */
|
|||
|
int numberOfALs; /* antall ALs pr. kataloginngang */
|
|||
|
|
|||
|
int convertSectorNumber18[18] = {0, 5, 10, 15, 2, 7, 12, 17, 4, 9, 14, 1, 6, 11, 16, 3, 8, 13};
|
|||
|
int convertSectorNumber10[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
|||
|
|
|||
|
/* functions */
|
|||
|
int main (int argc, char *argv[]) {
|
|||
|
int size;
|
|||
|
byte user;
|
|||
|
|
|||
|
if (argc < 4) {
|
|||
|
fprintf (stderr, "tikidisk V1.1 Copyright (c) Asbj<62>rn Djupdal 2001\n"
|
|||
|
"\n"
|
|||
|
"Brukes: tikidisk <diskfil> {lxad}[brukernummer] <filnavn...>\n"
|
|||
|
" l = list filer\n"
|
|||
|
" x = hent ut filer\n"
|
|||
|
" a = legg til filer\n"
|
|||
|
" d = slett filer\n"
|
|||
|
"\n");
|
|||
|
exit (1);
|
|||
|
}
|
|||
|
|
|||
|
{ /* les diskfil */
|
|||
|
FILE *diskImageFp;
|
|||
|
|
|||
|
if (!(diskImageFp = fopen (argv[1], "rb"))) {
|
|||
|
fprintf (stderr, "Kan ikke <20>pne diskfil %s\n", argv[1]);
|
|||
|
exit (1);
|
|||
|
}
|
|||
|
size = fread (diskImage, 1, DISK800K, diskImageFp);
|
|||
|
fclose (diskImageFp);
|
|||
|
}
|
|||
|
|
|||
|
/* sett diskparametre */
|
|||
|
switch (size) {
|
|||
|
case DISK90K:
|
|||
|
convertSectorNumber = convertSectorNumber18;
|
|||
|
numberOfEntries = 32;
|
|||
|
systemSectors = 3 * 18;
|
|||
|
sectorSize = 128;
|
|||
|
sectorsPerTrack = 18;
|
|||
|
exm = 0;
|
|||
|
bytesPerAL = 1;
|
|||
|
blockSize = 1024;
|
|||
|
numberOfBlocks = 83;
|
|||
|
directoryBlocks = 1;
|
|||
|
break;
|
|||
|
case DISK200K:
|
|||
|
convertSectorNumber = convertSectorNumber10;
|
|||
|
numberOfEntries = 64;
|
|||
|
systemSectors = 20;
|
|||
|
sectorSize = 512;
|
|||
|
sectorsPerTrack = 10;
|
|||
|
exm = 0;
|
|||
|
bytesPerAL = 1;
|
|||
|
blockSize = 1024;
|
|||
|
numberOfBlocks = 190;
|
|||
|
directoryBlocks = 2;
|
|||
|
break;
|
|||
|
case DISK400K:
|
|||
|
convertSectorNumber = convertSectorNumber10;
|
|||
|
numberOfEntries = 128;
|
|||
|
systemSectors = 20;
|
|||
|
sectorSize = 512;
|
|||
|
sectorsPerTrack = 10;
|
|||
|
exm = 1;
|
|||
|
bytesPerAL = 1;
|
|||
|
blockSize = 2048;
|
|||
|
numberOfBlocks = 195;
|
|||
|
directoryBlocks = 2;
|
|||
|
break;
|
|||
|
case DISK800K:
|
|||
|
convertSectorNumber = convertSectorNumber10;
|
|||
|
numberOfEntries = 128;
|
|||
|
systemSectors = 20;
|
|||
|
sectorSize = 512;
|
|||
|
sectorsPerTrack = 10;
|
|||
|
exm = 0;
|
|||
|
bytesPerAL = 2;
|
|||
|
blockSize = 2048;
|
|||
|
numberOfBlocks = 395;
|
|||
|
directoryBlocks = 2;
|
|||
|
break;
|
|||
|
default:
|
|||
|
fprintf (stderr, "Ikke en gyldig diskfil\n");
|
|||
|
exit (1);
|
|||
|
}
|
|||
|
sectorsPerBlock = blockSize / sectorSize;
|
|||
|
numberOfALs = 16 / bytesPerAL;
|
|||
|
|
|||
|
{ /* finn brukernummer */
|
|||
|
char *ptr;
|
|||
|
|
|||
|
user = (byte)strtol (argv[2] + 1, &ptr, 10);
|
|||
|
if (ptr == argv[2] + 1) { /* brukernummer ikke angitt */
|
|||
|
user = (byte)'?';
|
|||
|
} else if (user > 15) {
|
|||
|
fprintf (stderr, "Ulovlig brukernummer\n");
|
|||
|
exit (1);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* utf<74>r kommando */
|
|||
|
switch (*argv[2]) {
|
|||
|
case 'l': {
|
|||
|
/* list filer */
|
|||
|
int files = 0;
|
|||
|
int bytes = 0;
|
|||
|
byte *entry;
|
|||
|
|
|||
|
if ((entry = getMatch (argv[3], user))) {
|
|||
|
do {
|
|||
|
char filename[13];
|
|||
|
char attribs[4];
|
|||
|
int filesize = getFilesize (entry);
|
|||
|
|
|||
|
getFilename (filename, entry);
|
|||
|
getAttribs (attribs, entry);
|
|||
|
printf (" %6d %s %02d: %s\n", filesize, attribs, getUsernumber (entry), filename);
|
|||
|
files++;
|
|||
|
bytes += filesize;
|
|||
|
} while ((entry = getMatch (NULL, 0)));
|
|||
|
}
|
|||
|
printf ("%d filer, %d bytes\n", files, bytes);
|
|||
|
break;
|
|||
|
}
|
|||
|
case 'x': {
|
|||
|
/* lagre filer */
|
|||
|
int i = 3;
|
|||
|
|
|||
|
while (argv[i]) {
|
|||
|
byte *entry;
|
|||
|
|
|||
|
if ((entry = getMatch (argv[i], user))) {
|
|||
|
do {
|
|||
|
saveFile (entry);
|
|||
|
} while ((entry = getMatch (NULL, 0)));
|
|||
|
}
|
|||
|
i++;
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
case 'a': {
|
|||
|
/* legg til filer */
|
|||
|
int i = 3;
|
|||
|
|
|||
|
if (user == (byte)'?') {
|
|||
|
user = 0;
|
|||
|
}
|
|||
|
|
|||
|
while (argv[i]) {
|
|||
|
addFile (argv[i], user);
|
|||
|
i++;
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
case 'd': {
|
|||
|
/* slett filer */
|
|||
|
int i = 3;
|
|||
|
|
|||
|
while (argv[i]) {
|
|||
|
delFile (argv[i], user);
|
|||
|
i++;
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
default:
|
|||
|
fprintf (stderr, "Ulovlig kommando\n");
|
|||
|
exit (1);
|
|||
|
}
|
|||
|
|
|||
|
/* lagre diskfil */
|
|||
|
if ((*argv[2] == 'a') || (*argv[2] == 'd')) {
|
|||
|
FILE *diskImageFp;
|
|||
|
|
|||
|
if ((diskImageFp = fopen (argv[1], "wb"))) {
|
|||
|
fwrite (diskImage, 1, size, diskImageFp);
|
|||
|
fclose (diskImageFp);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
free (bam);
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
/* Trekker ut fil fra diskettfil og lagrer p<> disk
|
|||
|
*
|
|||
|
* entry: en ekstent til filen som skal lagres
|
|||
|
*/
|
|||
|
void saveFile (byte *entry) {
|
|||
|
char filename[13];
|
|||
|
FILE *fp;
|
|||
|
|
|||
|
getFilename (filename, entry);
|
|||
|
|
|||
|
if ((fp = fopen (filename, "wb"))) {
|
|||
|
int extentNumber = 0;
|
|||
|
|
|||
|
printf ("Henter ut %02d:%s...\n", getUsernumber (entry), filename);
|
|||
|
|
|||
|
/* g<> gjennom alle extenter */
|
|||
|
while ((entry = getExtent (entry, extentNumber++))) {
|
|||
|
boolean done = FALSE;
|
|||
|
int blockNumber;
|
|||
|
int alNumber = 0;
|
|||
|
int bytesRemaining = getBytesInEntry (entry);
|
|||
|
|
|||
|
/* g<> gjennom alle blokker */
|
|||
|
while (!done && (alNumber < numberOfALs)) {
|
|||
|
if ((blockNumber = getBlockNumber (entry, alNumber))) {
|
|||
|
int i;
|
|||
|
|
|||
|
/* lagre sektorer i blokk */
|
|||
|
for (i = 0; i < sectorsPerBlock; i++) {
|
|||
|
int sectorNumber = ((blockNumber * blockSize) / sectorSize) + systemSectors + i;
|
|||
|
|
|||
|
if (bytesRemaining) {
|
|||
|
int bytesToWrite = (bytesRemaining < sectorSize ? bytesRemaining : sectorSize);
|
|||
|
|
|||
|
fwrite (getSector (sectorNumber), 1, bytesToWrite, fp);
|
|||
|
bytesRemaining -= bytesToWrite;
|
|||
|
} else {
|
|||
|
done = TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
alNumber++;
|
|||
|
}
|
|||
|
}
|
|||
|
fclose (fp);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Henter inn fil fra disk og legger inn i diskettfil
|
|||
|
*
|
|||
|
* efn: entydig filnavn til fil som skal legges til
|
|||
|
* user: entydig brukernummer som fil skal lagres under
|
|||
|
*/
|
|||
|
void addFile (char *efn, byte user) {
|
|||
|
FILE *fp;
|
|||
|
byte *entry = NULL;
|
|||
|
int extentNumber = 0;
|
|||
|
int alNumber = 0;
|
|||
|
int sectorNumber = 0;
|
|||
|
int bytesInExtent = 0;
|
|||
|
byte *sectorData;
|
|||
|
boolean done = FALSE;
|
|||
|
|
|||
|
if (!(fp = fopen (efn, "rb"))) {
|
|||
|
fprintf (stderr, "Kan ikke <20>pne %s\n", efn);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
if (!(sectorData = malloc (sectorSize))) {
|
|||
|
fprintf (stderr, "Ikke nok minne\n");
|
|||
|
free (bam);
|
|||
|
exit (1);
|
|||
|
}
|
|||
|
|
|||
|
delFile (stripPath (efn), user);
|
|||
|
|
|||
|
buildBAM();
|
|||
|
|
|||
|
printf ("Legger til %02d:%s...\n", user, efn);
|
|||
|
|
|||
|
while (!done) {
|
|||
|
int bytesRead = fread (sectorData, 1, sectorSize, fp);
|
|||
|
|
|||
|
if (bytesRead) {
|
|||
|
|
|||
|
/* finn ledig kataloginngang */
|
|||
|
if (!(bytesInExtent % (numberOfALs * blockSize))) {
|
|||
|
int entryNumber = 0;
|
|||
|
|
|||
|
if (entry) setBytesInEntry (entry, bytesInExtent);
|
|||
|
|
|||
|
do {
|
|||
|
if (entryNumber >= numberOfEntries) {
|
|||
|
fprintf (stderr, "Ikke nok ledige kataloginnganger\n");
|
|||
|
free (sectorData);
|
|||
|
free (bam);
|
|||
|
exit (1);
|
|||
|
}
|
|||
|
entry = getEntry (entryNumber);
|
|||
|
entryNumber++;
|
|||
|
} while (entryNotDeleted (entry));
|
|||
|
|
|||
|
memset (entry, 0, 32);
|
|||
|
setNameAndUser (entry, stripPath (efn), user);
|
|||
|
setExtentNumber (entry, extentNumber++);
|
|||
|
alNumber = 0;
|
|||
|
bytesInExtent = 0;
|
|||
|
}
|
|||
|
|
|||
|
/* finn ledig blokk */
|
|||
|
if (!(bytesInExtent % blockSize)) {
|
|||
|
int blockNumber;
|
|||
|
|
|||
|
if (!(blockNumber = allocateBlock())) {
|
|||
|
fprintf (stderr, "Ikke nok ledige blokker\n");
|
|||
|
free (sectorData);
|
|||
|
free (bam);
|
|||
|
exit (1);
|
|||
|
}
|
|||
|
setBlockNumber (entry, alNumber++, blockNumber);
|
|||
|
sectorNumber = ((blockNumber * blockSize) / sectorSize) + systemSectors;
|
|||
|
}
|
|||
|
|
|||
|
/* skriv til sektor */
|
|||
|
memcpy (getSector (sectorNumber++), sectorData, sectorSize);
|
|||
|
bytesInExtent += bytesRead;
|
|||
|
|
|||
|
} else {
|
|||
|
done = TRUE;
|
|||
|
setBytesInEntry (entry, bytesInExtent);
|
|||
|
}
|
|||
|
}
|
|||
|
free (sectorData);
|
|||
|
}
|
|||
|
|
|||
|
/* Sletter filer fra diskettfil
|
|||
|
*
|
|||
|
* ffn: flertydig filnavn til filer som skal slettes
|
|||
|
* user: flertydig brukernummer til filer som skal slettes
|
|||
|
*/
|
|||
|
void delFile (char *ffn, byte user) {
|
|||
|
byte *entry;
|
|||
|
|
|||
|
if ((entry = getMatch (ffn, user))) {
|
|||
|
/* g<> gjennom alle entries (filer) */
|
|||
|
do {
|
|||
|
int extentNumber = 0;
|
|||
|
byte *extent;
|
|||
|
char filename[13];
|
|||
|
|
|||
|
getFilename (filename, entry);
|
|||
|
|
|||
|
printf ("Sletter %02d:%s...\n", getUsernumber (entry), filename);
|
|||
|
|
|||
|
/* slett alle extenter til filen */
|
|||
|
while ((extent = getExtent (entry, extentNumber++))) {
|
|||
|
deleteEntry (extent);
|
|||
|
}
|
|||
|
} while ((entry = getMatch (NULL, 0)));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Gir peker til entry i diskettfil
|
|||
|
*
|
|||
|
* entryNumber: nummer p<EFBFBD> entry som skal returneres
|
|||
|
*/
|
|||
|
byte *getEntry (int entryNumber) {
|
|||
|
int dirSector = systemSectors + ((entryNumber * 32) / sectorSize);
|
|||
|
int offsetInSector = (entryNumber * 32) % sectorSize;
|
|||
|
|
|||
|
return getSector (dirSector) + offsetInSector;
|
|||
|
}
|
|||
|
|
|||
|
/* Gir peker til extent i diskettfil, eller NULL derom ikke funnet
|
|||
|
*
|
|||
|
* entry: en allerede kjent extent
|
|||
|
* extentNumber: nummer til <EFBFBD>nsket extent
|
|||
|
*/
|
|||
|
byte *getExtent (byte *entry, int extentNumber) {
|
|||
|
int entryNumber;
|
|||
|
|
|||
|
for (entryNumber = 0; entryNumber < numberOfEntries; entryNumber++) {
|
|||
|
byte *curEntry = getEntry (entryNumber);
|
|||
|
|
|||
|
if (entryNotDeleted (curEntry) && entryEquals (entry, curEntry) &&
|
|||
|
(getExtentNumber (curEntry) == extentNumber)) {
|
|||
|
return curEntry;
|
|||
|
}
|
|||
|
}
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
/* Gir peker til neste fil (extent 0) som passer, eller NULL dersom ikke flere passer
|
|||
|
*
|
|||
|
* ffn: flertydig filnavn til filer som skal finnes
|
|||
|
* Angi ffn kun f<EFBFBD>rste gang funksjonen kalles. For <EFBFBD> finne de resterende filer
|
|||
|
* som passer, kall funksjonen med ffn = NULL
|
|||
|
* user: flertydig brukernummer til filer som skal finnes
|
|||
|
*/
|
|||
|
byte *getMatch (char *ffn, byte user) {
|
|||
|
static byte ffnEntry[12];
|
|||
|
static int entryNumber;
|
|||
|
|
|||
|
if (ffn != NULL) {
|
|||
|
entryNumber = 0;
|
|||
|
setNameAndUser (ffnEntry, ffn, user);
|
|||
|
}
|
|||
|
|
|||
|
while (entryNumber < numberOfEntries) {
|
|||
|
byte *entry = getEntry (entryNumber);
|
|||
|
entryNumber++;
|
|||
|
if (entryNotDeleted (entry) && entryEquals (ffnEntry, entry) && (getExtentNumber (entry) == 0)) {
|
|||
|
return entry;
|
|||
|
}
|
|||
|
}
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
/* Gir peker til stedet der data for angitt sektor befinner seg
|
|||
|
*
|
|||
|
* sectorNumber: nummer p<EFBFBD> sektor som <EFBFBD>nskes
|
|||
|
*/
|
|||
|
byte *getSector (int sectorNumber) {
|
|||
|
int realSectorNumber = (sectorNumber / sectorsPerTrack) * sectorsPerTrack +
|
|||
|
convertSectorNumber[sectorNumber % sectorsPerTrack];
|
|||
|
return diskImage + realSectorNumber * sectorSize;
|
|||
|
}
|
|||
|
|
|||
|
/* Gir nummeret p<> extent (fra EX og S2 feltene)
|
|||
|
*
|
|||
|
* entry: kataloginngang man <EFBFBD>nsker extentnummeret til
|
|||
|
*/
|
|||
|
int getExtentNumber (byte *entry) {
|
|||
|
return (*(entry + 14) * 32 + *(entry + 12)) / (exm + 1);
|
|||
|
}
|
|||
|
|
|||
|
/* Setter nummer p<> extent (til EX og S2 feltene)
|
|||
|
*
|
|||
|
* entry: kataloginngang man skal sette extentnummeret til
|
|||
|
* extentNumber: extentnummeret som skal settes
|
|||
|
*/
|
|||
|
void setExtentNumber (byte *entry, int extentNumber) {
|
|||
|
*(entry + 14) = extentNumber / 32;
|
|||
|
*(entry + 12) = ((extentNumber % 32) * (exm + 1));
|
|||
|
}
|
|||
|
|
|||
|
/* Gir antall bytes lagret i extent (fra RC og EX feltene)
|
|||
|
*
|
|||
|
* entry: extent man <EFBFBD>nsker st<EFBFBD>rrelsen til
|
|||
|
*/
|
|||
|
int getBytesInEntry (byte *entry) {
|
|||
|
return ((*(entry + 12) & exm) * 128 + *(entry + 15)) * 128;
|
|||
|
}
|
|||
|
|
|||
|
/* Setter antall bytes lagret i extent (til RC og EX feltene)
|
|||
|
*
|
|||
|
* entry: kataloginngang man skal sette st<EFBFBD>rrelsen til
|
|||
|
* bytesInExtent: antall bytes som skal settes
|
|||
|
*/
|
|||
|
void setBytesInEntry (byte *entry, int bytesInExtent) {
|
|||
|
int recordsInExtent = bytesInExtent / 128;
|
|||
|
|
|||
|
if (bytesInExtent % 128) recordsInExtent++;
|
|||
|
|
|||
|
if (recordsInExtent % 0x80) {
|
|||
|
*(entry + 15) = recordsInExtent % 0x80;
|
|||
|
} else {
|
|||
|
*(entry + 15) = 0x80;
|
|||
|
}
|
|||
|
if (recordsInExtent > 0x80) {
|
|||
|
*(entry + 12) += (recordsInExtent / 0x80);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Gir nummeret p<> blokken som befinner seg i en AL
|
|||
|
*
|
|||
|
* entry: kataloginngang
|
|||
|
* alNumber: nummer p<EFBFBD> AL man <EFBFBD>nsker blokknummeret til
|
|||
|
*/
|
|||
|
int getBlockNumber (byte *entry, int alNumber) {
|
|||
|
int al1 = *(entry + 16 + (alNumber * bytesPerAL));
|
|||
|
int al2 = *(entry + 16 + (alNumber * bytesPerAL) + 1);
|
|||
|
|
|||
|
return (bytesPerAL == 1 ? al1 : al1 + (al2 * 256));
|
|||
|
}
|
|||
|
|
|||
|
/* Setter nummer p<> blokk i an AL
|
|||
|
*
|
|||
|
* entry: kataloginngang
|
|||
|
* alNumber: nummer p<EFBFBD> AL
|
|||
|
* blockNumber: nummer p<EFBFBD> blokk
|
|||
|
*/
|
|||
|
void setBlockNumber (byte *entry, int alNumber, int blockNumber) {
|
|||
|
if (bytesPerAL < 2) {
|
|||
|
*(entry + 16 + alNumber) = blockNumber;
|
|||
|
} else {
|
|||
|
*(entry + 16 + (alNumber * 2)) = blockNumber;
|
|||
|
*(entry + 16 + (alNumber * 2) + 1) = blockNumber / 256;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Kopierer filnavn fra en kataloginngang til en streng
|
|||
|
*
|
|||
|
* filename: streng som filnavn skal kopieres til
|
|||
|
* entry: kataloginngang man <EFBFBD>nsker filnavnet til
|
|||
|
*/
|
|||
|
void getFilename (char *filename, byte *entry) {
|
|||
|
int i = 0, j = 0;
|
|||
|
|
|||
|
entry++;
|
|||
|
/* kopier filnavn */
|
|||
|
while ((i < 8) && (*entry != ' ')) {
|
|||
|
filename[i++] = legalChar (*entry++);
|
|||
|
}
|
|||
|
entry += 8 - i;
|
|||
|
filename[i++] = '.';
|
|||
|
/* kopier filtype */
|
|||
|
while ((j++ < 3) && (*entry != ' ')) {
|
|||
|
filename[i++] = legalChar ((*entry++) & 0x7f);
|
|||
|
}
|
|||
|
filename[i] = '\0';
|
|||
|
}
|
|||
|
|
|||
|
/* Gir st<73>rrelsen p<> en fil
|
|||
|
*
|
|||
|
* entry: en extent til fila man <EFBFBD>nsker st<EFBFBD>rrelsen til
|
|||
|
*/
|
|||
|
int getFilesize (byte *entry) {
|
|||
|
int filesize = 0;
|
|||
|
boolean done = FALSE;
|
|||
|
int extentNumber = 0;
|
|||
|
|
|||
|
while (!done) {
|
|||
|
if (!(entry = getExtent (entry, extentNumber++))) {
|
|||
|
done = TRUE;
|
|||
|
} else {
|
|||
|
filesize += getBytesInEntry (entry);
|
|||
|
}
|
|||
|
}
|
|||
|
return filesize;
|
|||
|
}
|
|||
|
|
|||
|
/* Gir brukernummeret til en kataloginngang
|
|||
|
*
|
|||
|
* entry: kataloginngang man <EFBFBD>nsker brukernummeret til
|
|||
|
*/
|
|||
|
byte getUsernumber (byte *entry) {
|
|||
|
return *entry;
|
|||
|
}
|
|||
|
|
|||
|
/* Lager en streng som representerer attributtene til en kataloginngang
|
|||
|
*
|
|||
|
* attribs: streng som attributtinfo skal skrives til
|
|||
|
* entry: kataloginngang man <EFBFBD>nsker attributtinfo til
|
|||
|
*/
|
|||
|
void getAttribs (char *attribs, byte *entry) {
|
|||
|
*(attribs + 0) = (*(entry + 9)) & 0x80 ? 'l' : '-';
|
|||
|
*(attribs + 1) = (*(entry + 10)) & 0x80 ? 's' : '-';
|
|||
|
*(attribs + 2) = (*(entry + 11)) & 0x80 ? 'a' : '-';
|
|||
|
*(attribs + 3) = '\0';
|
|||
|
}
|
|||
|
|
|||
|
/* Kopierer filnavn og brukernummer inn i en kataloginngang
|
|||
|
*
|
|||
|
* ffnEntry: kataloginngang man skal skrive til
|
|||
|
* ffn: flertydig filnavn som skal skrives fra
|
|||
|
* user: flertydig brukernummer som skal skrives fra
|
|||
|
*/
|
|||
|
void setNameAndUser (byte *ffnEntry, char *ffn, byte user) {
|
|||
|
int i;
|
|||
|
|
|||
|
/* kopier brukernummer */
|
|||
|
*ffnEntry++ = user;
|
|||
|
|
|||
|
/* kopier filnavn */
|
|||
|
for (i = 0; i < 8; i++, ffnEntry++) {
|
|||
|
if (*ffn == '*') {
|
|||
|
*ffnEntry = (byte)'?';
|
|||
|
} else if (*ffn == '?') {
|
|||
|
*ffnEntry = (byte)'?';
|
|||
|
ffn++;
|
|||
|
} else if (*ffn == '.') {
|
|||
|
*ffnEntry = (byte)' ';
|
|||
|
} else if (*ffn == '\0') {
|
|||
|
*ffnEntry = (byte)' ';
|
|||
|
} else {
|
|||
|
*ffnEntry = (byte)legalChar (*ffn);
|
|||
|
ffn++;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* finn filtype */
|
|||
|
if (strchr (ffn, '.')) {
|
|||
|
ffn = strchr (ffn, '.') + 1;
|
|||
|
|
|||
|
/* kopier filtype */
|
|||
|
for (i = 0; i < 3; i++) {
|
|||
|
if (*ffn == '*') {
|
|||
|
*ffnEntry++ = (byte)'?';
|
|||
|
} else if (*ffn == '?') {
|
|||
|
*ffnEntry++ = (byte)'?';
|
|||
|
ffn++;
|
|||
|
} else if (*ffn == '.') {
|
|||
|
ffn++;
|
|||
|
} else if (*ffn == '\0') {
|
|||
|
*ffnEntry++ = (byte)' ';
|
|||
|
} else {
|
|||
|
*ffnEntry++ = (byte)legalChar (*ffn);
|
|||
|
ffn++;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Bygger Block Availability Map for diskettfil
|
|||
|
*/
|
|||
|
void buildBAM (void) {
|
|||
|
int entryNumber;
|
|||
|
|
|||
|
free (bam);
|
|||
|
if (!(bam = malloc (sizeof (boolean) * numberOfBlocks))) {
|
|||
|
fprintf (stderr, "Ikke nok minne\n");
|
|||
|
exit (1);
|
|||
|
}
|
|||
|
|
|||
|
memset (bam, 0, sizeof (boolean) * numberOfBlocks);
|
|||
|
|
|||
|
{ /* merk katalogblokker som opptatte */
|
|||
|
int blockNumber;
|
|||
|
|
|||
|
for (blockNumber = 0; blockNumber < directoryBlocks; blockNumber++) {
|
|||
|
*(bam + blockNumber) = TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* g<> gjennom alle kataloginnganger */
|
|||
|
for (entryNumber = 0; entryNumber < numberOfEntries; entryNumber++) {
|
|||
|
byte *entry = getEntry (entryNumber);
|
|||
|
|
|||
|
if (entryNotDeleted (entry)) {
|
|||
|
int blockNumber;
|
|||
|
int alNumber = 0;
|
|||
|
|
|||
|
/* merk alle blokker som denne kataloginngangen bruker som opptatt */
|
|||
|
while ((alNumber < numberOfALs) && (blockNumber = getBlockNumber (entry, alNumber))) {
|
|||
|
*(bam + blockNumber) = TRUE;
|
|||
|
alNumber++;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Allokerer en blokk og gir nummeret p<> den nye blokken
|
|||
|
*/
|
|||
|
int allocateBlock (void) {
|
|||
|
int blockNumber;
|
|||
|
|
|||
|
for (blockNumber = 0; blockNumber < numberOfBlocks; blockNumber++) {
|
|||
|
if (!*(bam + blockNumber)) {
|
|||
|
*(bam + blockNumber) = TRUE;
|
|||
|
return blockNumber;
|
|||
|
}
|
|||
|
}
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
/* Gir slettet-status til en kataloginngang
|
|||
|
* entry: kataloginngang
|
|||
|
*/
|
|||
|
boolean entryNotDeleted (byte *entry) {
|
|||
|
return (*entry < 32);
|
|||
|
}
|
|||
|
|
|||
|
/* Sletter en kataloginngang
|
|||
|
* entry: kataloginngang
|
|||
|
*/
|
|||
|
void deleteEntry (byte *entry) {
|
|||
|
*entry = 0xe5;
|
|||
|
}
|
|||
|
|
|||
|
/* Sjekker om to kataloginnganger har samme navn og brukernummer
|
|||
|
*
|
|||
|
* ffnEntry: kataloginngang med flertydig navn og brukernummer
|
|||
|
* entry: kataloginngang som ffnEntry skal sjekkes mot
|
|||
|
*/
|
|||
|
boolean entryEquals (byte *ffnEntry, byte *entry) {
|
|||
|
if (((*(ffnEntry + 0) == '?') || (*(ffnEntry + 0) == *(entry + 0))) &&
|
|||
|
|
|||
|
((*(ffnEntry + 1) == '?') || (*(ffnEntry + 1) == *(entry + 1))) &&
|
|||
|
((*(ffnEntry + 2) == '?') || (*(ffnEntry + 2) == *(entry + 2))) &&
|
|||
|
((*(ffnEntry + 3) == '?') || (*(ffnEntry + 3) == *(entry + 3))) &&
|
|||
|
((*(ffnEntry + 4) == '?') || (*(ffnEntry + 4) == *(entry + 4))) &&
|
|||
|
((*(ffnEntry + 5) == '?') || (*(ffnEntry + 5) == *(entry + 5))) &&
|
|||
|
((*(ffnEntry + 6) == '?') || (*(ffnEntry + 6) == *(entry + 6))) &&
|
|||
|
((*(ffnEntry + 7) == '?') || (*(ffnEntry + 7) == *(entry + 7))) &&
|
|||
|
((*(ffnEntry + 8) == '?') || (*(ffnEntry + 8) == *(entry + 8))) &&
|
|||
|
|
|||
|
((*(ffnEntry + 9) == '?') || (*(ffnEntry + 9) == *(entry + 9))) &&
|
|||
|
((*(ffnEntry + 10) == '?') || (*(ffnEntry + 10) == *(entry + 10))) &&
|
|||
|
((*(ffnEntry + 11) == '?') || (*(ffnEntry + 11) == *(entry + 11)))) {
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
/* Konverterer et tegn til et tegn som kan brukes i alle filnavn p<> s<> godt
|
|||
|
* som alle operativsystem
|
|||
|
*
|
|||
|
* c: tegn som skal konverteres
|
|||
|
*/
|
|||
|
char legalChar (char c) {
|
|||
|
const char *legalChars = "_^$~!#&-{}@'";
|
|||
|
|
|||
|
if (!strchr (legalChars, c)) {
|
|||
|
if ((c < 48) || (c > 57 && c < 65) || (c > 90 && c < 97) || (c >122)) {
|
|||
|
return '#';
|
|||
|
}
|
|||
|
}
|
|||
|
return toupper (c);
|
|||
|
}
|
|||
|
|
|||
|
/* Gir en peker til f<>rste tegn i filnavnet (etter evt. sti)
|
|||
|
*
|
|||
|
* ffn: filnavn med evt. sti
|
|||
|
*/
|
|||
|
char *stripPath (char *ffn) {
|
|||
|
char *ptr;
|
|||
|
|
|||
|
if (!(ptr = strrchr (ffn, '/'))) {
|
|||
|
if (!(ptr = strrchr (ffn, '\\'))) {
|
|||
|
if (!(ptr = strrchr (ffn, ':'))) {
|
|||
|
ptr = ffn - 1;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
return ptr + 1;
|
|||
|
}
|