mFS file system library for EEPROM memory chips.
Diff: mfs.cpp
- Revision:
- 12:928346513c87
- Parent:
- 11:6c4fcb9d6193
- Child:
- 13:142b6be3e3c8
--- a/mfs.cpp Tue Feb 22 21:39:41 2011 +0000 +++ b/mfs.cpp Thu Feb 24 00:02:36 2011 +0000 @@ -12,10 +12,10 @@ #include "mfs.h" #include "i2c_eeprom.h" -#define BLOCK_NLEN 1 /**< Block number length in bytes */ -#define RB 1+2*BLOCK_NLEN /**< Reseved bytes per block (1 attrb B, 2 B for next/prev pointers */ -#define I2C_SPEED 200000 /**< I2C bus speed in Hz */ -#define DEBUG /**< Adds extra safety in reading and writing */ +#define BLOCK_LLEN 2 /**< Block number link length in bytes */ +#define RB 1+2*BLOCK_LLEN /**< Reseved bytes per block (1 attrb B, 2 B for next/prev pointers */ +#define I2C_SPEED 200000 /**< I2C bus speed in Hz */ +#define DEBUG /**< Adds extra safety in reading and writing */ DigitalOut FlushLed(LED2); /**< Flush led */ @@ -32,7 +32,7 @@ return 1; #endif mem->read(BS*block+byte, n, data); - //wait_ms(1); + return 0; } @@ -44,6 +44,7 @@ return 1; #endif mem->write(data, BS*block+byte, n); + return 0; } @@ -129,9 +130,11 @@ return 2; // Out of space char cData[RB+20]; - cData[0] = '\xCC'; // Necessary flags for file - cData[1] = '\0'; // Only this block yet - cData[2] = '\0'; // First block there could't be prev blocks + cData[0] = '\xCC'; // Necessary flags for a file + cData[1] = '\0'; // Only this block yet + cData[2] = '\0'; + cData[3] = '\0'; // First block there could't be prev blocks + cData[4] = '\0'; for (char i=0; i < 20; i++) cData[RB+i] = filename[i]; @@ -145,32 +148,31 @@ char mfs::removeFile(char filename[20]) { uint32_t block; - char cData[3] = {'\0','\0','\0'}; + char cData[RB-BLOCK_LLEN]; + char cDataNew[RB] = {'\x04', '\0', '\0', '\0', '\0'}; + uint32_t i=0; // Check if file exists if (getFirstBlockOfFile(filename, &block) != 0) return 1; // File not found - // Clear blocks reserver by the file - uint32_t i=0; - char tmp_cData[2]; + read(cData, block, 0, RB-BLOCK_LLEN); + + // Check credentials + if (((cData[0] & 0x01)|((cData[0] & 0x10) >> 3)|((cData[0] & 0x20) >> 3) & 0x04) != 0) + return 2; // RO file + + // Clear blocks reserved by the file while(1) { - read(cData, block, 0, 2); - tmp_cData[0] = cData[0]; - tmp_cData[1] = cData[1]; - - // Clear the block - cData[0] = '\x04'; - write(cData, block, 0, 3); - - if ((tmp_cData[0] & 0x4C) != 0) - break; // End of File found - else if (i >= BC) - return 2; // fs is corrupted - block = tmp_cData[1]; - + write(cDataNew, block, 0, RB); + if ((cData[0] & 0x4C) == 0x4C) + break; // End of file found + else block = (uint32_t)(cData[1])<<8|cData[2]; // Set next block number i++; + if (i > BC) + return 1; // fs is corrupted + read(cData, block, 0, RB-BLOCK_LLEN); } return 0; // Everything went better than expected @@ -179,11 +181,18 @@ char mfs::renameFile(char oldFilename[20], char newFilename[20]) { uint32_t block; + char cData[1]; // Check if file exists if (getFirstBlockOfFile(oldFilename, &block) != 0) return 1; // File not found + // Check credentials + read(cData, block, 0, 1); + char flags = (cData[0] & 0x01)|((cData[0] & 0x10) >> 3)|((cData[0] & 0x20) >> 3); + if ((flags & 0x04) != 0) + return 2; // RO file + write(newFilename, block, RB, 20); return 0; // Everything went better than expected @@ -196,13 +205,15 @@ uint32_t n; char cData[1] = {'\0'}; + char cFlags; // Check if file exists if (getFirstBlockOfFile(filename, &n) != 0) return 1; // File not found read(cData, n, 0, 1); - cData[0] |= (flags[0] & 0x01)|((flags[0] & 0x02) << 3)|((flags[0] & 0x04) << 3); + cFlags = ((flags[0] & 0x01)|((flags[0] & 0x02) << 3)|((flags[0] & 0x04) << 3)); + cData[0] = cData[0] & (~0x31) | cFlags; write(cData, n, 0, 1); return 0; @@ -250,13 +261,13 @@ uint32_t iAddr = 0; uint32_t i = 0; uint32_t bad = 0; // For counting bad block headers - char cFlags[] = {'\0', '\0', '\0'}, a[1]; + char cFlags[RB] = {'\0', '\0', '\0', '\0', '\0'}, o[1]; if (createLabel == true) { // Write Volume label cFlags[0] = '\x0E'; - mem->write(cFlags, iAddr, 3); + mem->write(cFlags, iAddr, RB); iAddr = BS; i = 1; } @@ -264,9 +275,9 @@ cFlags[0] = '\x04'; for (; i < BC; i++) { - mem->write(cFlags, iAddr, 3); - mem->read(iAddr, 1, a); - if (a[0] != cFlags[0]) + mem->write(cFlags, iAddr, RB); + mem->read(iAddr, 1, o); + if (o[0] != cFlags[0]) bad++; iAddr += BS; } @@ -274,17 +285,14 @@ return bad; } -file::file(mfs *fs_ref, char filename[20], char operation) +file::file(mfs *fs_ref, char filename[20], FileOpenMode operation) { - // Operations: - // 0 = Open in RO - // 1 = Open in RW - attr = operation; + fMode = operation; fs = fs_ref; // Don't forget this :) uint32_t n; - char cData[3] = {'\0','\0','\0'}; + char cData[1] = {'\0'}; // Check if file exists if (fs->getFirstBlockOfFile(filename, &n) != 0) @@ -293,16 +301,14 @@ fs->read(cData, n, 0, 1); char flags = (cData[0] & 0x01)|((cData[0] & 0x10) >> 3)|((cData[0] & 0x20) >> 3); - if (attr == 1) - { - if ((flags & 0x04) != 0) - error("Oops, cant open in RW mode!"); - } + if ((fMode != RO) && ((flags & 0x04) != 0)) + error("Oops, cant open in RW mode!"); // Store FBOF number firstBlock = n; currBlock = n; blockPos = RB+20; // skip flags + pointers + filename + byteCount = 0; // First byte of the file // Initialize buffer for (unsigned int i=0; i < BUF; i++) @@ -315,36 +321,92 @@ flush(); } +char file::getBlockLink(BlockLinkType linkSelection, uint32_t *blockOut) +{ + char cData[1+BLOCK_LLEN]; + + if (linkSelection == NEXT) + { + // Fetch link to next block + fs->read(cData, currBlock, 0, 1+BLOCK_LLEN); + if ((cData[0] & 0x40) == 0) + { + *blockOut = ((uint32_t)(cData[1])) << 8; // Hbyte of next block link + *blockOut |= (uint32_t)cData[2]; // Lbyte of next block link + return 0; + } else return 1; // Already at last block + } else if (linkSelection == PREV) + { + if (currBlock != firstBlock) + { + fs->read(cData, currBlock, 1+BLOCK_LLEN, BLOCK_LLEN); + *blockOut = ((uint32_t)(cData[0])) << 8; // Hbyte of next block link + *blockOut |= (uint32_t)cData[1]; // Lbyte of next block link + return 0; + } else return 1; // Already at first block + } + + return 0; +} + +char file::removeFollowingBlocks(uint32_t block) +{ + char cData[RB-BLOCK_LLEN]; + char cDataNew[RB] = {'\x04', '\0', '\0', '\0', '\0'}; + uint32_t i=0; + + while(1) + { + fs->read(cData, block, 0, RB-BLOCK_LLEN); + fs->write(cDataNew, block, 0, RB); + if ((cData[0] & 0x4C) == 0x4C) + break; // End of file found + else block = (uint32_t)(cData[0])<<8|cData[1]; // Set next block number + i++; + if (i > BC) + return 1; // fs is corrupted + } + + return 0; +} + void file::rewind() { flush(); currBlock = firstBlock; blockPos = RB+20; // skip flags & pointers + filename + byteCount = 0; } char file::rewind(uint32_t n) { uint32_t i; - char cData[3]; + uint32_t block; + uint32_t varBlockOffset; flush(); // Check if flush is needed for (i=0; i < n; i++) { blockPos--; + byteCount--; // Change Block? - if (blockPos < 3) + if (blockPos == firstBlock) + varBlockOffset = RB+20; + else + varBlockOffset = RB; + if ((blockPos < varBlockOffset) && (currBlock > firstBlock)) { - // Fetch link to next block - fs->read(cData, currBlock, 0, RB); - if (!(cData[0] & 0x80)) + // Fetch link to previous block + if(getBlockLink(PREV, &block) == 0) { - currBlock = cData[2]; - blockPos = BS-1; // Set block postion offset at end of the block + currBlock = block; + blockPos = BS-1; // blockPos should be set at the end of block } else { blockPos++; - return 1; // This is the first block + byteCount++; + return 1; // This is the first block and byte } } } @@ -360,32 +422,34 @@ char file::forward(uint32_t n) { uint32_t i; - char cData[2]; + uint32_t block; // Next block number + char cData[1]; flush(); // Check if flush is needed for (i=0; i < n; i++) { blockPos++; + byteCount++; // Change Block? - if (blockPos > BS-1) + if (blockPos >= BS) { // Fetch link to next block - fs->read(cData, currBlock, 0, 2); - if (!(cData[0] & 0x40)) + if (getBlockLink(NEXT, &block) == 0) { - currBlock = cData[1]; + currBlock = block; blockPos = RB; // Reset block position offset } else { blockPos--; - return 1; // This is the last block + byteCount--; + return 1; // This is the last block & byte } } fs->read(cData, currBlock, blockPos, 1); if (cData[0] == mEOF) { - rewind(1); + rewind(1); // Get back to the byte before EOF return 1; } } @@ -393,25 +457,34 @@ return 0; // OK } +char file::seek(uint32_t byte) +{ + if (byte > byteCount) + return forward(byte-byteCount); + else if (byte < byteCount) + return rewind(byteCount-byte); + else return 0; +} + // Respects mEOF and automatically sets '\0' at the end of string void file::read(char *data, uint32_t n) { uint32_t i; - char cData[2]; + uint32_t block; + char cData[1]; flush(); for (i=0; i < n; i++) { // Change block? - if (blockPos == BS-1) + if (blockPos >= BS-1) { // Fetch link to next block - fs->read(cData, currBlock, 0, 2); - if (!(cData[0] & 0x40)) + if (getBlockLink(NEXT, &block) == 0) { - currBlock = cData[1]; - blockPos = RB; // Reset block position offset + currBlock = block; + blockPos = RB; // Reset block position offset } else goto stop; } @@ -425,17 +498,19 @@ } else { data[i] = cData[0]; blockPos++; + byteCount++; } } - if (data[i] != '\0') - data[i] = '\0'; + if (data[n-1] != '\0') + data[n-1] = '\0'; } // Ignores mEOF and doesn't set '\0' markings void file::readBin(char *data, uint32_t n) { uint32_t i; - char cData[2]; + uint32_t block; + char cData[1]; for (i=0; i < n; i++) { @@ -443,10 +518,9 @@ if (blockPos == BS-1) { // Fetch link to next block - fs->read(cData, currBlock, 0, 2); - if (!(cData[0] & 0x40)) + if (getBlockLink(NEXT, &block) == 0) { - currBlock = cData[1]; + currBlock = block; blockPos = RB; // Reset block position offset } else return; } @@ -456,14 +530,14 @@ data[i] = cData[0]; blockPos++; + byteCount++; } - data[i-1] = '\0'; } // Always binary char file::write(char *data, uint32_t n) { - if (attr == 0) return 1; + if (fMode == RO) return 1; for (uint32_t i=0; i < n; i++) { @@ -484,14 +558,18 @@ char file::flush() { - char cData[3], c[1]; + char cData[RB], cDataOB[RB-BLOCK_LLEN], c[1]; uint32_t nextFree; uint32_t i; + uint32_t leftSpaceEOF; + + bool destructiveFlag = false; // Set this true if there is any data to be removed + uint32_t destructiveBlock=0; // First block to be removed by DWRITE if (bufPos == 0) return 0; // File up-to date - if (attr == 0) return 1; + if (fMode == RO) return 1; - for (i=0; i < bufPos; i++) + for (i=0; i <= bufPos; i++) { if(i%2) FlushLed = 1; @@ -499,44 +577,71 @@ FlushLed = 0; // Change Block? - if (blockPos >= BS-2) // Must left space for mEOF + if ((bufPos - i) == 1) + leftSpaceEOF = 1; + else + leftSpaceEOF = 0; + if (blockPos >= BS-leftSpaceEOF) { // Fetch new unused block number if(fs->getNextFreeBlock(&nextFree) != 0) - return 1; + return 2; // No free space left - // Take new block into use - cData[0] = 0x4C; // New flags - cData[1] = '\0'; - cData[2] = currBlock; // Prev Block - fs->write(cData, nextFree, 0, RB); // Update Block Data + // Read flags from current block + fs->read(cDataOB, currBlock, 0, RB-BLOCK_LLEN); - // Link old block with new block - fs->read(cData, currBlock, 0, RB); - cData[0] &= ~0x40; // Clear LBOF flag if set - cData[1] = nextFree; - cData[2] = '\0'; - fs->write(cData, currBlock, 0, RB); // Update Block Data + /* If destructive write is set then check if there is something + to be marked for removal */ + if (((cDataOB[0] & 0x40) != 0x40) && (fMode == DWRITE)) + { + destructiveFlag = true; + destructiveBlock = (uint32_t)cDataOB[1]<<8|cDataOB[2]; + goto allocate_new_block; + } else if ((cDataOB[0] & 0x40) != 0x40) // fMode == AWRITE + { + // Update current block info + currBlock = (uint32_t)cDataOB[1]<<8|cDataOB[2]; + blockPos = RB; // Reset block position offset + } else // There is no block to append so we allocate a new one + { + allocate_new_block: + // Allocate new block for use + cData[0] = 0x4C; // New flags + cData[1] = '\0'; // Hbyte of Next Block link + cData[2] = '\0'; // Lbyte of Next Block link + cData[3] = (char)((currBlock & 0xff00) >> 8); // Hbyte of Prev Block link + cData[4] = (char)(currBlock & 0x00ff); // Lbyte of Prev Block link + fs->write(cData, nextFree, 0, RB); // Update Block Data - // Update current block info - currBlock = nextFree; - blockPos = RB; // Reset block position offset + // Link old block with new block + cDataOB[0] &= ~0x40; // Clear LBOF flag if set + cDataOB[1] = (char)((nextFree & 0xff00) >> 8); // Hbyte of Next Block link + cDataOB[2] = (char)(nextFree & 0x00ff); // Lbyte of Next Block link + fs->write(cDataOB, currBlock, 0, RB-BLOCK_LLEN); // Update Block Data + // Update current block info + currBlock = nextFree; + blockPos = RB; // Reset block position offset + } } - if (blockPos < 3) - error(""); - // Write file c[0]=buffer[i]; fs->write(c, currBlock, blockPos, 1); blockPos++; + byteCount++; } // Write mEOF fs->write((char[]){mEOF}, currBlock, blockPos+1, 1); bufPos = 0; // Reset buffer position counter + /* If destructive write flag is set + and there is data to be removed then remove data now */ + if (destructiveFlag == true) + if(removeFollowingBlocks(destructiveBlock) != 0) + return 3; + FlushLed = 0; return 0; } \ No newline at end of file