Mercurial > sos > sos
changeset 91:8479bfdeb375
merge
author | Jonathan Pevarnek <pevarnj@gmail.com> |
---|---|
date | Thu, 12 May 2011 13:25:58 -0400 |
parents | 5e5bc76f0cdc (diff) f9ae64d35e81 (current diff) |
children | effa07f3c157 |
files | |
diffstat | 23 files changed, 1509 insertions(+), 37 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgignore Thu May 12 13:23:21 2011 -0400 +++ b/.hgignore Thu May 12 13:25:58 2011 -0400 @@ -3,6 +3,12 @@ \.rto$ ^ipl/ipl_ccws\.S$ ^sarpn$ +^dynamic$ +^testFS$ ^loader\.bin$ ^cscope\.out$ \.swp$ + +^hercules/curDisk\.img$ + +^changes
--- a/Makefile Thu May 12 13:23:21 2011 -0400 +++ b/Makefile Thu May 12 13:25:58 2011 -0400 @@ -11,9 +11,11 @@ CXXFLAGS=$(CFLAGS) LDFLAGS=-m elf64_s390 -BINS=sarpn +BINS=sarpn dynamic testFS -sarpn_OBJS=src/init.o arch/arch.a +sarpn_OBJS=src/sarpn.o src/std.o src/stack.o src/operations.o src/math.o arch/arch.a +dynamic_OBJS=src/dynamic.o src/std.o src/stack.o arch/arch.a +testFS_OBJS=src/testFS.o src/std.o src/fs.o arch/arch.a ARCH_OBJS=arch/io.o arch/cons.o arch/ebcdic.o arch/fba.o arch/ioint.o \ arch/svc.o arch/svcint.o @@ -26,15 +28,22 @@ clean: rm -f $(sarpn_OBJS) + rm -f $(dynamic_OBJS) + rm -f $(testFS_OBJS) rm -f $(ARCH_OBJS) rm -f $(BINS) rm -f loader.bin ipl/*.o ipl/*.rto ipl/ipl_ccws.S cscope.out tags: cscope -R -b + ctags -R sarpn: $(sarpn_OBJS) $(LD) $(LDFLAGS) -T scripts/linker.script -o $@ $^ +dynamic: $(dynamic_OBJS) + $(LD) $(LDFLAGS) -T scripts/linker.script -o $@ $^ +testFS: $(testFS_OBJS) + $(LD) $(LDFLAGS) -T scripts/linker.script -o $@ $^ arch/arch.a: $(ARCH_OBJS) $(AR) rc $@ $^ @@ -79,3 +88,19 @@ ipl/%.o: ipl/%.S $(AS) -m64 -o $@ $< + +depend: + makedepend -I include src/*.c + +# DO NOT DELETE + +src/dynamic.o: include/std.h include/die.h include/operations.h +src/dynamic.o: include/stack.h +src/fs.o: include/fs.h include/std.h include/die.h include/error.h +src/fs.o: include/tod.h +src/operations.o: include/operations.h include/std.h include/die.h +src/operations.o: include/stack.h include/math.h +src/sarpn.o: include/std.h include/die.h include/operations.h include/stack.h +src/stack.o: include/stack.h include/std.h include/die.h +src/std.o: include/std.h include/die.h +src/testFS.o: include/std.h include/die.h include/fs.h include/error.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hercules/dynamic.cnf Thu May 12 13:25:58 2011 -0400 @@ -0,0 +1,20 @@ +CPUSERIAL 314359 # CPU serial number +CPUMODEL 2097 # CPU model number +MAINSIZE 128 # Main storage size in megabytes +XPNDSIZE 0 # Expanded storage size in megabytes +CNSLPORT 3270 # TCP port number to which consoles connect +NUMCPU 1 # Number of CPUs +#OSTAILOR QUIET # OS tailoring +OSTAILOR NULL # OS tailoring +PANRATE SLOW # Panel refresh rate + +# .-----------------------Device number +# | .-----------------Device type +# | | .---------File name and parameters +# | | | +# V V V +#--- ---- -------------------- +0009 3215 +000C 3505 ../loader.bin ../dynamic ebcdic multifile eof + +0100 9336 disk.img
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hercules/fs.cnf Thu May 12 13:25:58 2011 -0400 @@ -0,0 +1,20 @@ +CPUSERIAL 314359 # CPU serial number +CPUMODEL 2097 # CPU model number +MAINSIZE 128 # Main storage size in megabytes +XPNDSIZE 0 # Expanded storage size in megabytes +CNSLPORT 3270 # TCP port number to which consoles connect +NUMCPU 1 # Number of CPUs +#OSTAILOR QUIET # OS tailoring +OSTAILOR NULL # OS tailoring +PANRATE SLOW # Panel refresh rate + +# .-----------------------Device number +# | .-----------------Device type +# | | .---------File name and parameters +# | | | +# V V V +#--- ---- -------------------- +0009 3215 +000C 3505 ../loader.bin ../testFS ebcdic multifile eof + +0100 9336 curDisk.img
--- a/hercules/herc.cnf Thu May 12 13:23:21 2011 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,20 +0,0 @@ -CPUSERIAL 314359 # CPU serial number -CPUMODEL 2097 # CPU model number -MAINSIZE 128 # Main storage size in megabytes -XPNDSIZE 0 # Expanded storage size in megabytes -CNSLPORT 3270 # TCP port number to which consoles connect -NUMCPU 1 # Number of CPUs -#OSTAILOR QUIET # OS tailoring -OSTAILOR NULL # OS tailoring -PANRATE SLOW # Panel refresh rate - -# .-----------------------Device number -# | .-----------------Device type -# | | .---------File name and parameters -# | | | -# V V V -#--- ---- -------------------- -0009 3215 -000C 3505 ../loader.bin ../sarpn ebcdic multifile eof - -0100 9336 disk.img
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hercules/sarpn.cnf Thu May 12 13:25:58 2011 -0400 @@ -0,0 +1,20 @@ +CPUSERIAL 314359 # CPU serial number +CPUMODEL 2097 # CPU model number +MAINSIZE 128 # Main storage size in megabytes +XPNDSIZE 0 # Expanded storage size in megabytes +CNSLPORT 3270 # TCP port number to which consoles connect +NUMCPU 1 # Number of CPUs +#OSTAILOR QUIET # OS tailoring +OSTAILOR NULL # OS tailoring +PANRATE SLOW # Panel refresh rate + +# .-----------------------Device number +# | .-----------------Device type +# | | .---------File name and parameters +# | | | +# V V V +#--- ---- -------------------- +0009 3215 +000C 3505 ../loader.bin ../sarpn ebcdic multifile eof + +0100 9336 disk.img
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/include/error.h Thu May 12 13:25:58 2011 -0400 @@ -0,0 +1,40 @@ +#ifndef __ERROR_H +#define __ERROR_H + +#define mkError(mod,code,sev) (((mod) << 12) | ((code) << 2) | (sev)) +#define isError(code) (((code) & 3) == ERROR) +#define errCode(code) (((code) >> 2) & 1023) +#define makeWarn(code) (isError(code)?((((code) >> 2) << 2) | WARN):code) //convert an error into a warning + +//Severities +#define INFO 0 +#define WARN 1 +#define ERROR 2 + +//Modules +#define MODFS 1 //stuff in the file system +#define MODTOD 2 //Time of date + +#define NOERROR 0 //General error code for not an error + +//Codes: filesystem +#define ALLOCFAIL 1 //a general code for a malloc failing +#define OUTOFRANGE 2 // +#define MUGGLE 3 //The magic code in the superblock was not set correctly +#define BLKREADFAIL 4 //failure for reading a filesystem block +#define NOTFILE 5 +#define BLKWRITEFAIL 6 //failure to write a filesystem block +#define SIZETOOLARGE 7 //the user requested a size that is too large to be set for a file +#define NOTINCACHE 8 +#define DISKFULL 9 //every block on the disk is currently set to be in use +#define EXISTS 10 //the user tried to create a file that already exists + +//Codes: Time of date +#define UPTIME 1 //the actual time of date was not set in the system +#define INVALID 2 + + +typedef u32 ErrCode; + +#endif //__ERROR_H +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/include/fs.h Thu May 12 13:25:58 2011 -0400 @@ -0,0 +1,66 @@ +#include <std.h> +#include <error.h> + +#ifndef __FS_H +#define __FS_H + +#define CACHESPACE 1 //percentage of heap to use for the FS Cache +#define FNAMELEN 28 //How long the filenames are +#define FSBLKSIZE 1024 +#define DSKBLKSIZE 512 +#define MAXBLOCKS 248 +#define FSMAGICNUM 0x42420374 +#define DEPBLK (FSBLKSIZE / sizeof(Direntry)) //director entries per block + +#define ERR_FSBLKREADFAIL mkError(MODFS, BLKREADFAIL, ERROR) + +struct SUPERBLOCK { + u32 magic; // == 0x42420374 + u32 root_inode; // the disk block containing the root inode + u32 nblocks; // number of block on the disk + u32 _pad[253]; // unused (should be '\0' filled) +}; +typedef struct SUPERBLOCK Superblock; + +struct INODE { + u32 size; // file length in bytes + u32 _pad0; // unused (should be 0) + u64 ctime; // creation time stamp + u64 mtime; // last modification time stamp + u16 nblocks; // number of data blocks in this file + u16 _pad1; // unused (should be 0) + u32 _pad2; // unused (should be 0) + u32 blocks[MAXBLOCKS]; // file block ptrs +}; +typedef struct INODE Inode; + +struct FSBLK { + u8 blocks[FSBLKSIZE]; +}; +typedef struct FSBLK FSBlk; + +struct DSKBLK { + u8 blocks[DSKBLKSIZE]; +}; +typedef struct DSKBLK DskBlk; + +struct DIRENTRY { //32 bytes + char fname[FNAMELEN]; + u32 inode; +}; +typedef struct DIRENTRY Direntry; + +ErrCode init_fs(u32 devnum, u64 __memsize); +ErrCode getFInfo(u32 n, void* de); +ErrCode lookupFile(char *fname, u32 *fid); +ErrCode makeFile(char *fname, u32 *fid); +ErrCode deleteFile(u32 fid); +ErrCode fileAppend(u32 fid, void *data, u32 length); +ErrCode fileWrite(u32 fid, void *data, u32 length, u32 offset); +ErrCode getFileSize(u32 fid, u32 *size); +ErrCode getFileData(u32 fid, void *ptr); +void printFname(char *name); +void getFname(char *fname); +int fnameCmp(const char *a, const char *b); + +#endif //__FS_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/include/math.h Thu May 12 13:25:58 2011 -0400 @@ -0,0 +1,14 @@ +#ifndef __MATH_H +#define __MATH_H + +double iPow(double base, int exponent); +double exp(double exp); +double log(double num); +double pow(double base, double exponent); + +double math_add(double first, double sec); +double math_sub(double first, double sec); +double math_mult(double first, double sec); +double math_div(double first, double sec); + +#endif //__MATH_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/include/operations.h Thu May 12 13:25:58 2011 -0400 @@ -0,0 +1,26 @@ +#ifndef __OPERATIONS_H +#define __OPERATIONS_H + +#include <std.h> +#include <stack.h> + +enum Operation {PRINT, ADD, SUB, MULT, DIV, POW, DUP, DROP, LOG, EXP, SWAP, MAXOP}; +extern const char operationNames[MAXOP][10]; +extern void (*operation[MAXOP])(Stack*); + +void op_math1(Stack *stack, eltType (*mathop)(eltType)); +void op_math2(Stack *stack, eltType (*mathop)(eltType, eltType)); + +void op_print(Stack *stack); +void op_add(Stack *stack); +void op_sub(Stack *stack); +void op_mult(Stack *stack); +void op_div(Stack *stack); +void op_pow(Stack *stack); +void op_dup(Stack *stack); +void op_drop(Stack *stack); +void op_log(Stack *stack); +void op_exp(Stack *stack); +void op_swap(Stack *stack); + +#endif //__OPERATIONS_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/include/stack.h Thu May 12 13:25:58 2011 -0400 @@ -0,0 +1,25 @@ +#ifndef __STACK_H +#define __STACK_H + +typedef double eltType; + +struct STACKELT { + eltType elt; + struct STACKELT *next; +}; +typedef struct STACKELT StackElt; + +struct STACK { + StackElt* top; + unsigned int size; +}; +typedef struct STACK Stack; + +short pop(Stack *stack, eltType *value); +//pop returns 0 on success and -1 on failure. If the function call is +//successful, *value will be the value removed from the stack +void push(Stack *stack, eltType val); +Stack* stack_init(); +void stack_destroy(Stack *stack); + +#endif //__STACK_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/include/std.h Thu May 12 13:25:58 2011 -0400 @@ -0,0 +1,52 @@ +#include <die.h> + +#ifndef __STD_H +#define __STD_H + +#define assert(x) do { if(!(x)) die(); } while (0) + +//min and max function definitions +#define __fxn(TYPE) \ + static inline TYPE Max_##TYPE(TYPE a, TYPE b) { return (a>b) ? a : b; } \ + static inline TYPE Min_##TYPE(TYPE a, TYPE b) { return (a>b) ? b : a; } + __fxn(int) + __fxn(u64) + __fxn(u32) +#undef __fxn + +void init_all(u64 __memsize); + +double abs(double num); + +char* ftoa(double x, char *a, unsigned int prec); +char* itoa(long long n, char *a, unsigned short base); +s64 atoi(char *a); +double atof(char *a); + +void sPrint(char *a); +char* sGet(char *a, unsigned int n); + +void strcpy(char *dest, const char *src); +int strcmp(const char *a, const char *b); + +char* append(char *dest, char *src); + +void* memcpy(void *destination, const void *source, size_t num); + +//MALLOC CODE + +struct header{ + struct header *next; + size_t size; +}; +typedef struct header Header; + +typedef Header blockUnit; + +void malloc_init(size_t memSize); +void* malloc(size_t size); +void free(void *ptr); +void printHeader(Header* head); +void printMem(); + +#endif
--- a/include/system.h Thu May 12 13:23:21 2011 -0400 +++ b/include/system.h Thu May 12 13:25:58 2011 -0400 @@ -5,6 +5,14 @@ #define CON_DEV 0x0009 #define NULL ((void*) 0) +#define CON_LEN 132 +#define HEAP_START 0x200000 + +#define INF __builtin_inff() +#define NAN __builtin_nanf("") + +typedef unsigned long long size_t; +typedef unsigned long long intptr_t; typedef unsigned long long u64; typedef signed long long s64;
--- a/include/tod.h Thu May 12 13:23:21 2011 -0400 +++ b/include/tod.h Thu May 12 13:25:58 2011 -0400 @@ -56,9 +56,10 @@ * *tod == 0 is the instant the system powered on * 2 or 3 on failure, value of *tod is unpredictable */ -static inline int get_tod(u64 *tod) +static inline ErrCode get_tod(u64 *tod) { int cc; + ErrCode ret = 0; asm volatile( "stck %0\n" @@ -71,8 +72,20 @@ : /* clobber */ "cc" ); + switch(cc) { + case 0: + ret = 0; + break; + case 1: + ret = mkError(MODTOD, UPTIME, WARN); + break; + case 2: + case 3: + ret = mkError(MODTOD, INVALID, ERROR); + break; + } - return cc; + return ret; } #endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/dynamic.c Thu May 12 13:25:58 2011 -0400 @@ -0,0 +1,74 @@ +/* + * This is where everything starts + */ + +#include <std.h> +#include <operations.h> +#include <stack.h> + +void dumpBuffer(char *a, int b) +{ + int i; + for(i = 0; i < b; i++) { + int foo = (int) a[i]; + char c[10]; + itoa(foo, c, 16); + sPrint(c); + sPrint(" "); + if(!((i + 1)%20)) sPrint("\n"); + } +} + +void start(u64 __memsize) +{ + init_all(__memsize); + size_t n; + char *buffer; + char input[30]; + + while(0) { + sPrint("How long do you want the string? "); + n = atoi(sGet(input, 30)); + buffer = (char*) malloc(n); + if (!buffer) { //allocation failed, too large + sPrint("ERROR\n"); + break; + } +// size_t i; +// for (i = 0; i < n - 1; i++) +// buffer[i]='a'; //I need to make rand... +// buffer[n - 1]='\0'; +// sPrint(buffer), sPrint("\n"); +// dumpBuffer(buffer, n); + sPrint(append(itoa((unsigned long)buffer, input, 16), "\n")); + free(buffer); + } + + printMem(); + + Stack *stack = stack_init(); + + for(n = 0; n < 1000; n++) { + push(stack, n); + } + stack_destroy(stack); + + + printMem(); + void *a = malloc(1223); + void *b = malloc(352); + void *c = malloc(3539); + void *d = malloc(325); + printMem(); + free(b); + printMem(); + b = malloc(400); + printMem(); + sPrint("DONE\n"); + free(a); + free(c); + free(d); + + for(;;) + sGet(input, 0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/fs.c Thu May 12 13:25:58 2011 -0400 @@ -0,0 +1,425 @@ +#include <fs.h> +#include <std.h> +#include <tod.h> +#include <error.h> + +static void* readFSBlock(u32 blkno); +static ErrCode writeFSBlock(u32 blkno, void *ptr); +static ErrCode sync(u32 blkno); +static ErrCode getBlockData(u32 blkno, void* ptr); +static ErrCode setFileSize(u32 fid, size_t size); +static ErrCode isBlockAt(u32 block, short *b); +static ErrCode setBlockAt(u32 block, short isBlock); +static ErrCode nextFreeBlock(u32 start, u32 *loc); +static u32 getCacheLoc(u32 blkno); +static u32 cacheAdd(u32 blkno); +static ErrCode setTod(Inode *inPtr); + +static u32 DevID; +static u32 CacheCap; //how many blocks the cache can hold +static u32 CacheSize; //the current number of items in the cache +static FSBlk *FS_Cache = NULL; //A pointer to the actual cache +static u32 *CacheLocs; //what location each block points to +static u32 CacheNext; //the next location to toss a cached block into +static u32 rootLoc; +static u32 MaxBlocks; + +ErrCode init_fs(u32 devnum, u64 __memsize) +{ + //Create the cache + CacheCap = ((__memsize/100)/FSBLKSIZE)*CACHESPACE; + //number of blocks to store in the cache + FS_Cache = malloc(CacheCap*FSBLKSIZE); + if(!FS_Cache) return mkError(MODFS, ALLOCFAIL, ERROR); + CacheLocs = malloc(CacheCap); + if(!CacheLocs) return mkError(MODFS, ALLOCFAIL, ERROR); + CacheSize = 0; + CacheNext = 0; + + DevID = find_dev(0x100); + Superblock *sb; + sb = readFSBlock(1); + if(!sb) return ERR_FSBLKREADFAIL; + if(sb->magic != FSMAGICNUM) return mkError(MODFS, MUGGLE, ERROR); + MaxBlocks = sb->nblocks; + rootLoc = sb->root_inode; + + return 0; +} + +ErrCode getFInfo(u32 n, void* de) +{ + Inode *root = readFSBlock(rootLoc); + if(!root) return ERR_FSBLKREADFAIL; + if(n >= root->size/DEPBLK) return mkError(MODFS, OUTOFRANGE, WARN); + Direntry *dp = readFSBlock(root->blocks[n/DEPBLK]); + if(!dp) return ERR_FSBLKREADFAIL; + memcpy(de, dp + n%DEPBLK, sizeof(Direntry)); + return 0; +} + +//This sets *fid to be equal to the fileid of the file with name fname +ErrCode lookupFile(char *fname, u32 *fid) +{ + size_t i; + for(i = 0; 1; i++) { + Direntry de; + ErrCode err = getFInfo(i, &de); + if(err == mkError(MODFS, OUTOFRANGE, WARN)) break; //have iterated through all files + else if(isError(err)) return err; //propogate error + if(!fnameCmp(fname, de.fname)) { + *fid = de.inode; + return 0; + } + } + return mkError(MODFS, NOTFILE, ERROR); +} + +//makes an empty file with name fname, sets fid to the fid for the new file +//If the file already exists, an error is returned but fid will be set to the +//fid of that file +ErrCode makeFile(char *fname, u32 *fid) +{ + ErrCode err; + if(!isError(err = lookupFile(fname, fid))) + return mkError(MODFS, EXISTS, ERROR); //the file should not exist + if(err != mkError(MODFS, NOTFILE, ERROR)) return err; + if(isError(err = nextFreeBlock(0, fid))) return err; + + Inode nin; + nin.size = 0; + nin.nblocks = 0; + if(isError(err = setTod(&nin))) return err; + nin.ctime = nin.mtime; + nin._pad0 = nin._pad1 = nin._pad2 = 0; //I am not sure if this is needed... + if(isError(err = writeFSBlock(*fid, &nin))) return err; + + Direntry de; + de.inode = *fid; + memcpy(de.fname, fname, FNAMELEN); + if(isError(err = fileAppend(rootLoc, &de, sizeof(Direntry)))) return err; + + return 0; +} + +ErrCode deleteFile(u32 fid) +{ + ErrCode err; + if(isError(err = setFileSize(fid, 0))) return err; + Direntry de; + u32 fileNo; + for(fileNo = 0; 1; fileNo++) { + if(isError(err = getFInfo(fileNo, &de))) return err; + else if(err == mkError(MODFS, OUTOFRANGE, WARN)) return mkError(MODFS, NOTFILE, ERROR); + if(de.inode == fid) break; + } + Inode *root = readFSBlock(rootLoc); + if(!root) return ERR_FSBLKREADFAIL; + u32 rootSize = root->size; + u32 numDE = rootSize/sizeof(Direntry); + u32 toBlkNo = root->blocks[fileNo/DEPBLK]; //block that the DE used to occupy + u32 endBlkNo = root->blocks[numDE/DEPBLK]; //block for the last DE + Direntry *td = readFSBlock(root->blocks[fileNo/DEPBLK]); + if(!td) return ERR_FSBLKREADFAIL; + td += fileNo%DEPBLK; + Direntry *end = readFSBlock(endBlkNo); + //this will fail if there is only space for one item in cache and the 2 DEs + //are in different blocks. There will be no indication of failure + if(!end) return ERR_FSBLKREADFAIL; + end += numDE%DEPBLK; + *td = *end; + if(isError(err = setFileSize(rootLoc, rootSize - sizeof(Direntry)))) return err; + if(isError(err = sync(toBlkNo))) return err; //end does not need to be synchronized + return 0; +} + +ErrCode fileAppend(u32 fid, void *data, u32 length) +{ + ErrCode err; + u32 fileSize; + if(isError(err = getFileSize(fid, &fileSize))) return err; + if(isError(err = fileWrite(fid, data, length, fileSize))) return err; + return 0; +} + +ErrCode fileWrite(u32 fid, void *data, u32 length, u32 offset) +{ + ErrCode err, ret = 0; + Inode *iptr = readFSBlock(fid); + if(!iptr) return ERR_FSBLKREADFAIL; + u32 oldSize = iptr->size; + u32 dataStop = offset + length; + if(dataStop > oldSize) { + if(isError(err = setFileSize(fid, dataStop))) return err; + } + + Inode in; + if(isError(err = getBlockData(fid, &in))) return err; + + u32 currPos = offset; + while(currPos < dataStop) { + u32 currBlock = in.blocks[currPos/FSBLKSIZE]; + void *ptr = readFSBlock(currBlock); + if(!ptr) return ERR_FSBLKREADFAIL; + u32 tcOS = currPos%FSBLKSIZE; //the current offset for the block + u32 tcSize = Min_u32(dataStop - currPos, FSBLKSIZE); //assume 0 offset + tcSize = (tcSize + tcOS > FSBLKSIZE)?FSBLKSIZE - tcOS:tcSize; //take into account the offset + memcpy(ptr + tcOS, data, tcSize); + if(isError(err = sync(currBlock))) return err; + data += tcSize; + currPos += tcSize; + } + + if(isError(err = setTod(&in))) ret = makeWarn(err); + if(isError(err = writeFSBlock(fid, &in))) return err; + return ret; +} + +//PRECON: fid is a valid file id +//This sets *size equal to the size of the file +ErrCode getFileSize(u32 fid, u32 *size) +{ + Inode *ptr = readFSBlock(fid); + if(!ptr) return ERR_FSBLKREADFAIL; + *size = ptr->size; + return 0; +} + +//PRECON: ptr points to a large enough location to hold all the data in file +// fid +ErrCode getFileData(u32 fid, void *ptr) +{ + ErrCode ret = 0, err; + int i; + Inode in; + if(isError(err = getBlockData(fid, &in))) { + ret = err; + goto end; + } + + u32 size = in.size; + for(i = 0; i < in.nblocks; i++) { + Inode *filePtr = readFSBlock(in.blocks[i]); + if(!filePtr) { + ret = ERR_FSBLKREADFAIL; + goto end; + } + memcpy(ptr, filePtr, Min_u32(size, FSBLKSIZE)); + ptr += FSBLKSIZE; + size -= FSBLKSIZE; + } + +end: + return ret; +} + +void printFname(char *name) +{ + putline(name, 28); +} + +//PRECON: fname points to a location 28 characters long +//Sets fname to contain a filename entered by the user +void getFname(char *fname) +{ + int chars = getline(fname, FNAMELEN); + for(;chars < FNAMELEN; chars++) { + fname[chars] = ' '; + } +} + +//Checks whether two file names are equal +int fnameCmp(const char *a, const char *b) +{ + int i; + for(i = 0; i < FNAMELEN; i++, a++, b++) { + if(*a - *b) return *a - *b; + } + return 0; +} + +//XXX HELPER FUNCTIONS XXX + +//returns a pointer pointing to a location where the data from blkno will be +//stored +static void* readFSBlock(u32 blkno) +{ + u32 cacheLoc = getCacheLoc(blkno); //Do not reload if in cache + if(cacheLoc == CacheCap) { //It was not found in the cache + cacheLoc = cacheAdd(blkno); + FSBlk *nextFSB = FS_Cache + cacheLoc; + DskBlk *nextDSKB = (DskBlk *) nextFSB; //block to put data in + if(fba_read_blk(DevID, blkno*2, nextDSKB)) return NULL; + if(fba_read_blk(DevID, blkno*2 + 1, nextDSKB + 1)) return NULL; + } + return (void *)(FS_Cache + cacheLoc); +} + +//Writes 1024 bytes from *ptr to data block blkno +static ErrCode writeFSBlock(u32 blkno, void *ptr) +{ + u32 cacheLoc = getCacheLoc(blkno); + ErrCode err; + if(cacheLoc == CacheCap) + cacheLoc = cacheAdd(blkno); //need room in cache for data + FSBlk *nextFSB = FS_Cache + cacheLoc; //TODO abstraction levels? + memcpy(nextFSB, ptr, FSBLKSIZE); //copy the data to the cache + DskBlk *nextDSKB = (DskBlk *) nextFSB; //where to get the data from + if(isError(err = fba_write_blk(DevID, blkno*2, nextDSKB))) return err; + //load from the cache to the disk + if(isError(err = fba_write_blk(DevID, blkno*2 + 1, nextDSKB + 1))) return err; + short ib; + if(isError(err = isBlockAt(blkno, &ib))) return err; + if(!ib) { + if(isError(err = setBlockAt(blkno, 1))) return makeWarn(err); + } + return 0; +} + +//updates the data in block blkno based upon the data in the cache. If block +//blkno is not in the cache, returns non-zero +static ErrCode sync(u32 blkno) +{ + u32 cacheLoc = getCacheLoc(blkno); + if(cacheLoc == CacheCap) return mkError(MODFS, NOTINCACHE, ERROR); + FSBlk *nextFSB = FS_Cache + cacheLoc; + DskBlk *nextDSKB = (DskBlk *) nextFSB; //where to get the data from + if(fba_write_blk(DevID, blkno*2, nextDSKB)) return mkError(MODFS, BLKWRITEFAIL, ERROR); + if(fba_write_blk(DevID, blkno*2 + 1, nextDSKB + 1)) return mkError(MODFS, BLKWRITEFAIL, ERROR); + return 0; +} + +static ErrCode getBlockData(u32 blkno, void* ptr) +{ + Inode *temp = readFSBlock(blkno); + if(!temp) return ERR_FSBLKREADFAIL; + memcpy(ptr, temp, FSBLKSIZE); + return 0; +} + +//sets the file to have a size equal to size. The data will be preserved if +//the file is currently larger than that or will be jibberish if the file is +//currently smaller +static ErrCode setFileSize(u32 fid, size_t size) //TODO clean +{ + ErrCode ret = 0, err; + unsigned int i; + u16 neededBlocks = (size + FSBLKSIZE - 1)/FSBLKSIZE; + if(neededBlocks > MAXBLOCKS) { + ret = mkError(MODFS, SIZETOOLARGE, ERROR); + goto end; + } + Inode in; + if(isError(err = getBlockData(fid, &in))) { + ret = err; + goto end; + } + + if(in.nblocks >= neededBlocks) { //get rid of some blocks + for(i = neededBlocks; i < in.nblocks; i++) { //if it is equal, will skip this loop + if(isError(err = setBlockAt(in.blocks[i], 0))) { + ret = err; + goto end; + } + } + } else { //there are fewer blocks + for(i = in.nblocks; i < neededBlocks; i++) { + u32 prevLoc = (i)?in.blocks[i - 1]:fid; + if(isError(err = nextFreeBlock(prevLoc, &in.blocks[i]))) { + ret = err; + goto end; + } + if(isError(err = setBlockAt(in.blocks[i], 1))) { + ret = err; + goto end; + } + } + } + in.nblocks = neededBlocks; + in.size = size; + if(isError(err = setTod(&in))) { + ret = makeWarn(err); + } + if(isError(err = writeFSBlock(fid, &in))) { + ret = err; + goto end; + } + +end: + return ret; +} + +static ErrCode isBlockAt(u32 block, short *b) +{ + u32 inBlock = block/(8*FSBLKSIZE) + 2; //which block the bit is in + u32 blockSpot = (block%(8*FSBLKSIZE))/8; //which u8 the bit is in + u32 spotSpot = 7 - block%8; //which bit the bit is + u8 *ptr = readFSBlock(inBlock); + if(!ptr) return ERR_FSBLKREADFAIL; + *b = (ptr[blockSpot] >> spotSpot) & 1; + return 0; +} + +//sets the block table to indicate whether there is a block at block +static ErrCode setBlockAt(u32 block, short isBlock) +{ + u32 inBlock = block/(8*FSBLKSIZE) + 2; //which block the bit is in + u32 blockSpot = (block%(8*FSBLKSIZE))/8; //which u8 the bit is in + u32 spotSpot = 7 - block%8; //which bit the bit is + u8 *ptr = readFSBlock(inBlock); + if(!ptr) return ERR_FSBLKREADFAIL; + if(isBlock) ptr[blockSpot] |= 1 << spotSpot; + else ptr[blockSpot] &= ~(1 << spotSpot); + ErrCode err; + if(isError(err = sync(inBlock))) return err; + return 0; +} + +static ErrCode nextFreeBlock(u32 start, u32 *loc) +{ + u32 i; + ErrCode err; + for(i = start; i < MaxBlocks; i++) { + short ib; + if(isError(err = isBlockAt(i, &ib))) return err; + if(!ib) { + *loc = i; + return 0; + } + } + return mkError(MODFS, DISKFULL, ERROR); +} + +//TODO ErrCode? +static u32 getCacheLoc(u32 blkno) +{ + int i; + for(i = 0; i < CacheSize; i++) { + if(CacheLocs[i] == blkno) return i; + } + return CacheCap; +} + +//PRECON: block blkno is not already in the cache +//Returns the location in the cache where the data is +//sets aside space in the cache for some item. NOTE: this does not read the +//current contents of the disk to the cache +static u32 cacheAdd(u32 blkno) +{ + u32 ret = CacheNext; + CacheLocs[CacheNext] = blkno; + if(CacheSize != CacheCap) CacheSize += 1; + if(CacheNext != CacheCap - 1) CacheNext += 1; + else CacheNext = 0; + return ret; +} + +//TODO consider what to do in other places if this returns a warning/error +static ErrCode setTod(Inode *inPtr) +{ + u64 tod; + ErrCode ret; + ret = get_tod(&tod); + inPtr->mtime = tod >> 12; + return ret; +}
--- a/src/init.c Thu May 12 13:23:21 2011 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,13 +0,0 @@ -/* - * This is where everything starts - */ -void start(u64 __memsize) -{ - init_io_int(); - init_console(); - - putline("Hello\n", 6); - - for(;;) - ; -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/math.c Thu May 12 13:25:58 2011 -0400 @@ -0,0 +1,84 @@ +double iPow(double base, int exponent) +{ + double ans = 1; + short isNeg = 0; + if(exponent < 0) { + isNeg = 1; + exponent *= -1; + } + while(exponent > 0) { + if(exponent%2) { + exponent -= 1; + ans *= base; + } else { + exponent /= 2; + base *= base; + } + } + return isNeg ? 1/ans : ans; +} + +double exp(double exp) +{ + unsigned int i; //a counter for the loop + double ans = 1; + double prev = -1; + double term = 1; + short isNeg = 0; + if(exp < 0) { + isNeg = 1; + exp *= -1; + } + for(i = 1; ans - prev; i++) { + prev = ans; + term *= exp/i; + ans += term; + } + return isNeg ? 1/ans : ans; +} + +double log(double num) +{ + unsigned int denom = 1; + double euler = 2.71828182845904; + double ans = 0; + double prev = -1; + double term = -1; + while(num <= -1 || num >= 1) { + num /= euler; + ans += 1; + } + for(; ans - prev; denom++) { + prev = ans; + term *= (-1*(num - 1)); + ans += term/denom; + } + return ans; +} + +double pow(double base, double exponent) +{ + if(exponent == (int) exponent) + return iPow(base, (int) exponent); + return exp(exponent*log(base)); +} + +double math_add(double first, double sec) +{ + return first + sec; +} + +double math_sub(double first, double sec) +{ + return first - sec; +} + +double math_mult(double first, double sec) +{ + return first*sec; +} + +double math_div(double first, double sec) +{ + return first/sec; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/operations.c Thu May 12 13:25:58 2011 -0400 @@ -0,0 +1,113 @@ +#include <operations.h> +#include <std.h> +#include <stack.h> +#include <math.h> + +const char operationNames[MAXOP][10] = {".", "+", "-", "*", "/", "**", "dup", "drop", "log", "exp", "swap"}; +void (*operation[MAXOP])(Stack*) = {op_print, op_add, op_sub, op_mult, + op_div, op_pow, op_dup, op_drop, op_log, op_exp, op_swap}; + +static void error_unk() +{ + sPrint("ERROR: CAUSE UNKNOWN\n"); +} + +static void error_small() +{ + sPrint("ERROR: STACK TOO SMALL\n"); +} + +void op_math1(Stack *stack, eltType (*mathop)(eltType)) +{ + if(stack->size >= 1) { + eltType val; + if(pop(stack, &val)) error_unk(); + else push(stack, mathop(val)); + } else error_small(); +} + +void op_math2(Stack *stack, eltType (*mathop)(eltType, eltType)) +{ + if(stack->size >= 2) { + eltType val1, val2; + if(pop(stack, &val2) || pop(stack, &val1)) error_unk(); + else push(stack, mathop(val1, val2)); + } else error_small(); +} + +void op_print(Stack *stack) +{ + if(stack->size >= 1) { + char output[30]; + eltType val; + if(pop(stack, &val)) error_unk(); + else sPrint(append(ftoa(val, output, 10), "\n")); + } else error_small(); +} + +void op_add(Stack *stack) +{ + op_math2(stack, math_add); +} + +void op_sub(Stack *stack) +{ + op_math2(stack, math_sub); +} + +void op_mult(Stack *stack) +{ + op_math2(stack, math_mult); +} + +void op_div(Stack *stack) +{ + op_math2(stack, math_div); +} + +void op_pow(Stack *stack) +{ + op_math2(stack, pow); +} + +void op_dup(Stack *stack) +{ + if(stack->size >= 1) { + eltType val; + if(pop(stack, &val)) error_unk(); + else { + push(stack, val); + push(stack, val); + } + } else error_small(); +} + +void op_drop(Stack *stack) +{ + if(stack->size >= 1) { + eltType val; + pop(stack, &val); + } else error_small(); +} + +void op_log(Stack *stack) +{ + op_math1(stack, log); +} + +void op_exp(Stack *stack) +{ + op_math1(stack, exp); +} + +void op_swap(Stack *stack) +{ + if(stack->size >= 2) { + eltType val1, val2; + if(pop(stack, &val2) || pop(stack, &val1)) error_unk(); + else { + push(stack, val2); + push(stack, val1); + } + } else error_small(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/sarpn.c Thu May 12 13:25:58 2011 -0400 @@ -0,0 +1,37 @@ +/* + * This is where everything starts + */ + +#include <std.h> +#include <operations.h> +#include <stack.h> + +int arrayLookup(char *text, const char array[][10], int last) +{ + int i; + for(i = 0; i < last; i++) + if(!strcmp(array[i], text)) return i; + return last; +} + +void start(u64 __memsize) +{ + init_all(__memsize); + + Stack *stack = stack_init(); + while(1) { + int opVal; + char input[30]; + sPrint("Please enter an operation or value: "); + opVal = arrayLookup(sGet(input, 30), operationNames, MAXOP); + if(opVal != MAXOP) { + (*operation[opVal]) (stack); //call the function array + } else { + push(stack, atof(input)); + } + } + stack_destroy(stack); + + for(;;) + ; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/stack.c Thu May 12 13:25:58 2011 -0400 @@ -0,0 +1,40 @@ +#include <stack.h> +#include <std.h> + +short pop(Stack *stack, eltType *value) +{ + if(stack->top == NULL) { + return -1; //failure + } else { + StackElt *tip = stack->top; + *value = tip->elt; + stack->top = tip->next; + free(tip); + stack->size--; + return 0; //success + } +} + +void push(Stack *stack, eltType val) +{ + StackElt *new = malloc(sizeof(StackElt)); + new->elt = val; + new->next = stack->top; + stack->top = new; + stack->size++; +} + +Stack* stack_init() +{ + Stack *new = malloc(sizeof(Stack)); + new->top = NULL; + return new; +} + +void stack_destroy(Stack *stack) +{ + eltType *val = malloc(sizeof(eltType)); + while(stack->top) pop(stack, val); + free(stack); + free(val); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/std.c Thu May 12 13:25:58 2011 -0400 @@ -0,0 +1,253 @@ +#include <std.h> + +void init_all(u64 __memsize) +{ + init_io_int(); + init_console(); + malloc_init(__memsize - HEAP_START); +} + +double abs(double num) +{ + if(num < 0) return num*-1; + else return num; +} + +char* itoa(s64 n, char *a, unsigned short base) +{ + char *ret = a; + if(n < 0) { + *a++ = '-'; + n *= -1; + } + char *b = a; + if(!n) *b++ = '0'; + for(; n; b++) { + int temp = n%base; + if(temp < 10) *b = '0' + temp; + else *b = 'a' + temp - 10; + n = n/base; + } + *b-- = '\0'; + for(; a < b; a++, b--) { //reverse + char temp = *b; + *b = *a; + *a = temp; + } + return ret; +} + +char* ftoa(double x, char *a, unsigned int prec) +{ + char *ret = a; + if(x == INF || x == -INF) { + strcpy(a, "INF"); + } else if(x != x) { //NAN != NAN + strcpy(a, "NAN"); + } else { + s64 n = (s64) x; //integer part + double d = abs(x - (double) n); //fractional part; + itoa(n, a, 10); + if(prec) { //only do the decimal part if decimal parts were asked for + while(*a && *++a); //get to the null character from itoa + int i; //counter variable for the for loop + *a++ = '.'; //put the decimal in place + for(i = 0; i < prec; i++) { + d *= 10; //the integer part is the decimal digit + *a++ = ((int) d) + '0'; //add the integer part of d to the string + d -= (int) d; //chop off the integer part + } a--; //move back to the last digit + while(*a != '.') { + if(*a == '0') { + a--; + continue; + } else if(*a > '0' && *a <= '9') { + a++; + break; + } else { + sPrint("ERROR: SOMETHING IS VERY WRONG\n"); + break; + } + } + *a = '\0'; + } + } + return ret; +} + +s64 atoi(char *a) +{ + short neg = 0; + s64 n = 0; + if(*a == '-') { + neg = 1; + a++; + } else if(*a == '+') a++; + while(*a >= '0' && *a <= '9') + n = n*10 + (*a++ - '0'); + if(neg) n *= -1; + return n; +} + +double atof(char *a) +{ + s64 n = atoi(a); + double x = 0; + double dec = .1; + short neg = 0; + if(*a == '-') { + neg = 1; + a++; + } + while(*a != '.') { + if(!(*a >= '0' && *a <= '9') && *a != '-') return n; + a++; + } a++; //a will be immediately after the decimal point + while(*a >= '0' && *a <= '9') { //goes through the decimal part + x += (*a - '0')*dec; + dec *= .1; + a++; + } + if(neg) x*=-1; + return n + x; +} + +void sPrint(char *a) +{ + char *b = a; + while(*b && *++b); + do { + putline(a, (b - a > CON_LEN)?CON_LEN:(b - a)); + a += CON_LEN; + } while(a < b); +} + +void strcpy(char *dest, const char *src) +{ + while((*dest++ = *src++)); +} + +int strcmp(const char *a, const char *b) +{ + while(1) { + if(*a - *b) return *a - *b; + if(*a == '\0') return 0; + a++; + b++; + } + return -1; +} + +char* sGet(char *a, unsigned int n) +{ + int length = getline(a, n); + a[(length < n)?length:n - 1] = '\0'; + return a; +} + +char* append(char *dest, char *src) +{ + char *ret = dest; + while(*dest&& *++dest); //get to null in first string + while((*dest++ = *src++)); + return ret; +} + +void* memcpy(void *destination, const void *source, size_t num) +{ + int i; + const u8 *from = source; + u8 *to = destination; + for(i = 0; i < num; i++) + to[i] = from[i]; + return destination; +} + + + +//DYNAMIC MEMORY + +static Header base; +static Header *allocp = NULL; //the location of the last known free block + +void malloc_init(size_t memSize) +{ + allocp = &base; + allocp->size = 0; + allocp->next = (void*)HEAP_START; + allocp->next->next = &base; + allocp->next->size = memSize/sizeof(blockUnit); + if((sizeof(blockUnit)%sizeof(u64))) { + sPrint("WARNING: MEMORY NOT 8-BYTE ALIGNED\n"); + char foo[40]; + sPrint(append("MEMORY BLOCK SIZE IS: ", append(itoa(sizeof(Header), foo, 10), "\n"))); + } +} + +void* malloc(size_t size) +{ + if(allocp == NULL) return NULL; + size_t nUnits = ((size + sizeof(Header)) + sizeof(blockUnit) - 1)/sizeof(blockUnit); + Header *prev = allocp; + Header *cur, *temp; + for(cur = prev->next;; prev = cur, cur = cur->next) { + if(cur->size >= nUnits) { + if(cur->size == nUnits) { + prev->next = cur->next; + } else { + temp = cur + nUnits; //This requires sizeof(blockUnit) == sizeof(Header). TODO fix + temp->size = cur->size - nUnits; + temp->next = cur->next; + prev->next = temp; + cur->size = nUnits; + } + allocp = prev; + return (void*)(cur + 1); + } else if(cur == allocp) { //We went back to the start... + return NULL; + } + } +} + +void free(void *ptr) +{ + Header *toFree = (Header *)ptr - 1; + Header *scan; + for(scan = allocp; !(toFree > scan && toFree < scan->next); scan = scan->next) + if(scan->next < scan && (toFree > scan || toFree < scan->next)) break; + toFree->next = scan->next; + scan->next = toFree; + if(scan + scan->size == toFree) { + scan->size += toFree->size; + scan->next = toFree->next; + toFree = scan; + } + if(toFree + toFree->size == toFree->next) { + toFree->size += toFree->next->size; + toFree->next = toFree->next->next; + } +} + +void printHeader(Header* head) +{ + char buffer[20]; + sPrint("Memory address is: "); + sPrint(itoa((intptr_t)head, buffer, 16)); + sPrint("\n"); + sPrint("The size of the block is: "); + sPrint(itoa(head->size, buffer, 10)); + sPrint("\n"); + sPrint("Next memory address is: "); + sPrint(itoa((intptr_t)head->next, buffer, 16)); + sPrint("\n\n"); +} + +void printMem() +{ + Header *cur = allocp; + do { + printHeader(cur); + cur = cur->next; + } while(cur != allocp); + sPrint("PRINTOUT DONE\n\n"); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/testFS.c Thu May 12 13:25:58 2011 -0400 @@ -0,0 +1,144 @@ +#include <std.h> +#include <fs.h> +#include <error.h> + +void dumpText(char *text, int size) +{ + do { + putline(text, (size > CON_LEN)?CON_LEN:size); + size -= CON_LEN; + text += CON_LEN; + } while(size > 0); +} + +u32 listFiles() +{ + size_t i; + for(i = 0; 1; i++) { + Direntry de; + ErrCode err = getFInfo(i, &de); + if(err == mkError(MODFS, OUTOFRANGE, WARN)) break; + else if(isError(err)) return err; + printFname(de.fname), sPrint("\n"); + } + return 0; +} + +void start(u64 __memsize) +{ + init_all(__memsize); + char buffer[256]; + if(isError(init_fs(0x100, __memsize))) goto END; + + while(1) { + sPrint("Please select a mode:\n0: show file text\n1: make new file\n2: Append to file\n3: Delete File\n"); + sPrint("3: Delete File\n4: Write to file\n"); + sGet(buffer, 30); + int mode = atoi(buffer); + switch(mode) { + case 0: + { + if(isError(listFiles())) sPrint("WARNING: ERROR IN READING FILE NAMES\n"); + char fname[28]; + sPrint("Please enter the file to read: "); + getFname(fname); + u32 fid; + ErrCode err = lookupFile(fname, &fid); + if(isError(err)) { + if(errCode(err) == NOTFILE) sPrint("ERROR: Invalid file name\n"); + continue; + } + u32 fileSize; + if(isError(getFileSize(fid, &fileSize))) continue; + char *text = malloc(fileSize); + if(!text) continue; + if(isError(getFileData(fid, text))) { + free(text); + continue; + } + dumpText(text, fileSize); + free(text); + } + break; + case 1: + { + char fname[28]; + sPrint("Please enter a name for the new file: "); + getFname(fname); + u32 dummy; //I do not care about the fid personally + if(isError(makeFile(fname, &dummy))) { + sPrint("ERROR\n"); + continue; + } + } + break; + case 2: + { + if(isError(listFiles())) sPrint("WARNING: ERROR IN READING FILE NAMES\n"); + char fname[28]; + sPrint("Please enter the file to write to: "); + getFname(fname); + u32 fid; + ErrCode err = lookupFile(fname, &fid); + if(isError(err)) { + if(errCode(err) == NOTFILE) sPrint("ERROR: Invalid file name\n"); + continue; + } + sPrint("Please enter the text to append to the file: "); + u32 size = getline(buffer, CON_LEN); + if(isError(fileAppend(fid, buffer, size))) { + sPrint("ERROR\n"); + continue; + } + } + break; + case 3: + { + if(isError(listFiles())) sPrint("WARNING: ERROR IN READING FILE NAMES\n"); + char fname[28]; + sPrint("Please enter the file to delete: "); + getFname(fname); + u32 fid; + ErrCode err = lookupFile(fname, &fid); + if(isError(err)) { + if(errCode(err) == NOTFILE) sPrint("ERROR: Invalid file name\n"); + continue; + } + if(isError(deleteFile(fid))) { + sPrint("ERROR\n"); + continue; + } + } + break; + case 4: + { + if(isError(listFiles())) sPrint("WARNING: ERROR IN READING FILE NAMES\n"); + char fname[28]; + sPrint("Please enter the file to write text to: "); + getFname(fname); + u32 fid; + ErrCode err = lookupFile(fname, &fid); + if(isError(err)) { + if(errCode(err) == NOTFILE) sPrint("ERROR: Invalid file name\n"); + continue; + } + sPrint("Please enter the offset for the text: "); + sGet(buffer, 30); + unsigned int offset = atoi(buffer); + sPrint("Please enter the text to append to the file: "); + u32 size = getline(buffer, CON_LEN); + if(isError(fileWrite(fid, buffer, size, offset))) { + sPrint("ERROR\n"); + continue; + } + } + break; + } + } + +END: + sPrint("DONE\n"); + for(;;) { + sGet(buffer, 0); + } +}