/*#include <stddef.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <assert.h> #include <iostream> #include "ubixfs.h" #include "btree.h" using namespace std; UbixFS::UbixFS(void) { device = NULL; freeBlockList = NULL; superBlock = NULL; root = NULL; } // UbixFS::UbixFS UbixFS::UbixFS(device_t * dev) { device = dev; freeBlockList = NULL; superBlock = NULL; root = NULL; } // UbixFS::UbixFS void UbixFS::printSuperBlock(void) { printf("superBlock->name........... %s\n", superBlock->name); printf("superBlock->magic1......... %X\n", superBlock->magic1); printf("superBlock->fsByteOrder.... %d\n", superBlock->fsByteOrder); printf("superBlock->blockSize...... %d\n", superBlock->blockSize); printf("superBlock->blockShift..... %d\n", superBlock->blockShift); printf("superBlock->numBlocks...... %lld\n", superBlock->numBlocks); printf("superBlock->usedBlocks..... %lld\n", superBlock->usedBlocks); printf("superBlock->batSectors..... %d\n", superBlock->batSectors); printf("superBlock->inodeCount..... %d\n", superBlock->inodeCount); printf("superBlock->magic2......... %X\n", superBlock->magic2); printf("superBlock->blocksPerAG.... %d\n", superBlock->blocksPerAG); printf("superBlock->AGShift........ %d\n", superBlock->AGShift); printf("superBlock->numAGs......... %d\n", superBlock->numAGs); printf("superBlock->lastUsedAG..... %d\n", superBlock->lastUsedAG); printf("superBlock->flags.......... %X\n", superBlock->flags); printf("superBlock->magic3......... %X\n", superBlock->magic3); return; } // UbixFS::printSuperBlock int UbixFS::vfs_init(void) { assert(device); size_t result; cout << "vfs_init()" << endl; assert(device); if (device == NULL) return -1; if (superBlock != NULL) delete superBlock; superBlock = new diskSuperBlock; assert(superBlock); if (superBlock == NULL) return -1; // read in the superBlock. It's always the last block on the partition cout << "reading in superBlock" << endl; device->read(device, superBlock, device->sectors-1, 1); cout << "done" << endl; assert(superBlock->magic1 == UBIXFS_MAGIC1); assert(superBlock->magic2 == UBIXFS_MAGIC2); assert(superBlock->magic3 == UBIXFS_MAGIC3); assert(strcmp(superBlock->name, "UbixFS") == 0); assert((1 << superBlock->blockShift) == superBlock->blockSize); assert((unsigned)(1 << superBlock->AGShift) == superBlock->blocksPerAG); assert(superBlock->flags == UBIXFS_CLEAN); if (freeBlockList != NULL) delete [] freeBlockList; freeBlockList = new signed char[superBlock->batSectors*512]; assert(freeBlockList); memset(freeBlockList, 0, superBlock->batSectors*512); device->read(device, freeBlockList, device->sectors - superBlock->batSectors-1, superBlock->batSectors ); // device->read() root = new fileDescriptor; assert(root); memset(root, 0, sizeof(fileDescriptor)); cout << "allocating root dir inode" << endl; root->inode = new ubixfsInode; memset(root->inode, 0, sizeof(ubixfsInode)); cout << "root dir inode starting sector: " << ((superBlock->rootDir.AG << superBlock->AGShift) + superBlock->rootDir.start) * (superBlock->blockSize / 512) << endl; cout << "reading in root dir inode" << endl; device->read(device, root->inode, ((superBlock->rootDir.AG << superBlock->AGShift) + superBlock->rootDir.start) * (superBlock->blockSize / 512), sizeof(ubixfsInode) / 512 ); cout << "done" << endl; ubixfsInode * rootInode = static_cast<ubixfsInode *>(root->inode); assert(rootInode); //the bTree constructor now loads in the header rootInode->data.btPtr = new bTree(this, root); rootInode->data.btPtr->Info(); printSuperBlock(); return 0; } // UbixFS::init int UbixFS::vfs_format(device_t * dev) { cout << "vfs_format()" << endl; char sector[512]; uInt32 blocks, batSect, batSize; if (dev == NULL) return -1; // zero out the sector memset(§or, 0x0, sizeof(sector)); // fill the drive in with zeroed out sectors cout << "dev->sectors: " << dev->sectors << endl; cout << "clearing device..."; for (unsigned int i = 0; i < dev->sectors; i++) { dev->write(dev, §or, i, 1); } // for i cout << "done" << endl; // allocate a new superBlock and clear it diskSuperBlock *sb = new diskSuperBlock; if (sb == NULL) return -1; memset(sb, 0, sizeof(diskSuperBlock)); // dev->sectors is the number of 512 byte sectors blocks = (dev->sectors-1) / 8; // 4k blocks batSize = (dev->sectors-1) % 8; // remainder // compute the BAT size while ((batSize * 4096) < blocks) { batSize += 8; --blocks; } // while // batSize is in sectors batSect = blocks * 8; strcpy(sb->name, "UbixFS"); sb->magic1 = UBIXFS_MAGIC1; sb->fsByteOrder = 0; sb->blockSize = 4096; sb->blockShift = 12; sb->numBlocks = blocks; sb->usedBlocks = 2; // root dir takes two blocks (inode + bTree header) sb->inodeCount = 1; sb->inodeSize = 4096; sb->magic2 = UBIXFS_MAGIC2; sb->blocksPerAG = 2048; sb->AGShift = 11; sb->numAGs = (sb->numBlocks+2047) / 2048; sb->lastUsedAG = 0; // the BAT exists outside our official block count, so no // entries in the BAT need to be set for it sb->batSectors = batSize; sb->flags = 0x434C454E; // CLEN sb->logBlocks.AG = 0; sb->logBlocks.start = 0; sb->logBlocks.len = 0; sb->logStart = 0; sb->logEnd = 0; sb->magic3 = UBIXFS_MAGIC3; sb->indicies.AG = 0; sb->indicies.start = 0; sb->indicies.len = 0; sb->rootDir.AG = 0; sb->rootDir.start = 0; sb->rootDir.len = 1; // write out the superBlock dev->write(dev, sb, dev->sectors-1, 1); // mark the first two 4k blocks used memset(§or, 0, sizeof(sector)); sector[0] = (1 << 7) | (1 << 6); // write out the first sector of the BAT dev->write(dev, §or, batSect, 1); // clear the rest sector[0] = 0; // write out the rest of the BAT for (unsigned int i = 1; i < batSize; i++) { dev->write(dev, §or, (batSect)+i, 1); } // for i // allocate part of the root dir // sanity checks assert(sb->blockSize); assert((unsigned)sb->blockSize >= sizeof(bTreeHeader)); bTreeHeader * bth = new bTreeHeader; assert(bth); memset(bth, 0, sizeof(bTreeHeader)); bth->firstDeleted = -1; bth->firstNodeOffset = -1; bth->treeDepth = 1; bth->treeWidth = 0; bth->treeLeafCount = 0; // create the root dir inode here ubixfsInode * inode = new ubixfsInode; assert(inode); if (inode == NULL) return -1; memset(inode, 0, sizeof(ubixfsInode)); inode->magic1 = UBIXFS_INODE_MAGIC; // inodes point to themselves inode->inodeNum.AG = 0; inode->inodeNum.start = 0; inode->inodeNum.len = 1; // root dir has no parent directory inode->parent.iAddr.AG = 0; inode->parent.iAddr.start = 0; inode->parent.iAddr.len = 0; // this is part of the root dir structure (the bTreeHeader) inode->blocks.direct[0].AG = 0; inode->blocks.direct[0].start = 1; inode->blocks.direct[0].len = 1; inode->blocks.maxDirectRange = sizeof(bTreeHeader); inode->blocks.size = sizeof(bTreeHeader); strcpy(inode->name, "/"); inode->uid = getuid(); inode->gid = getgid(); // inode->mode inode->flags = INODE_DIRECTORY; // inode->createTime // inode->lastModifiedTime // inode->type inode->attributes.AG = 0; inode->attributes.start = 0; inode->attributes.len = 0; inode->inodeSize = sb->inodeSize; *//* * next and prev are used in memory to hold pointers to the next/prev * inodes in this dir. On disk they may have another value, but for * now they should be set to null. *//* inode->next.offset = 0; inode->prev.offset = 0; // write out the "root" dir inode dev->write(dev, inode, ((inode->inodeNum.AG << sb->AGShift) + inode->inodeNum.start) * (sb->blockSize / 512), sb->inodeSize / 512 ); // dev->write // write out the "root" dir dev->write(dev, bth, ((inode->blocks.direct[0].AG << sb->AGShift) + inode->blocks.direct[0].start) * (sb->blockSize / 512), sb->blockSize / 512 ); // dev->write delete inode; delete bth; delete sb; cout << "format complete" << endl; return 0; } // UbixFS::vfs_format void * UbixFS::vfs_mknod(const char *path, mode_t mode) { return mknod(path, 0, mode); // <- this probably isn't correct } // UbixFS::vfs_mknod int UbixFS::vfs_open(const char * filename, fileDescriptor * fd, int flags, ...) { if (filename == NULL || fd == NULL) return -1; flags = flags; fd->inode = NULL; fd->offset = 0; fd->size = 0; // look up the file here return 0; } // UbixFS::vfs_open size_t UbixFS::vfs_read(fileDescriptor * fd, void * data, off_t offset, size_t size) { unsigned int i; off_t sum, startingBlock; size_t runSize, sectorCount, totalSize, bSize; // blockSize ubixfsInode * inode = NULL; if (fd == NULL || data == NULL) return ~0; if (size == 0) return 0; // don't fail if size is 0? assert(device); assert(superBlock); inode = static_cast<ubixfsInode *>(fd->inode); assert(inode); bSize = superBlock->blockSize; totalSize = sum = i = 0; while (size > 0) { *//* * place check here to see which set of blocks we're looking through *//* // scan through direct blocks do { if (offset >= sum && offset < sum + inode->blocks.direct[i].len * bSize) break; sum += inode->blocks.direct[i++].len * bSize; } while (i < NUM_DIRECT_BLOCKS); startingBlock = (inode->blocks.direct[i].AG << superBlock->AGShift) + inode->blocks.direct[i].start + ((offset - sum) / bSize); runSize = inode->blocks.direct[i].len * bSize; // startingBlock is in 4k blocks startingBlock *= (bSize / 512); // startingBlock is now in sectors if (runSize >= size) { runSize = size; size = 0; } else { size -= runSize; } // else sectorCount = runSize / 512; cout << "device->read(device, data, " << startingBlock << ", "; cout << sectorCount << ");" << endl; device->read(device, data, startingBlock, sectorCount); (uInt8 *)data += runSize; totalSize += runSize; } // while return totalSize; } // UbixFS::vfs_read size_t UbixFS::vfs_write(fileDescriptor * fd, void * data, off_t offset, size_t size) { // char * sector[512]; // used to pad unsigned int i, whichBlocks; off_t sum, startingBlock, EORPos, maxRange; size_t runSize, runRemainder, sectorCount, totalSize, bSize; // blockSize ubixfsInode * inode = NULL; blockRun br; if (fd == NULL || data == NULL) return ~0; if (size == 0) return 0; // don't fail if size is 0? assert(device); assert(superBlock); inode = static_cast<ubixfsInode *>(fd->inode); assert(inode); bSize = superBlock->blockSize; assert(bSize != 0); totalSize = sum = i = whichBlocks = 0; EORPos = offset + size; // compute End Of Run Position maxRange = inode->blocks.maxDirectRange; if (inode->blocks.maxIndirectRange > maxRange) { maxRange = inode->blocks.maxIndirectRange; whichBlocks = 1; } if (inode->blocks.maxDoubleIndirectRange > maxRange) { maxRange = inode->blocks.maxDoubleIndirectRange; whichBlocks = 2; } if (EORPos > maxRange) { *//* * The offset+size is greater than the size of the file, so we need to * extend out the file. Scan through the direct blocks (FIX LATER) * to find out where we need to extend *//* switch (whichBlocks) { case 0: while (i < NUM_DIRECT_BLOCKS && inode->blocks.direct[i].len != 0) ++i; // i holds which direct block we're going to add to break; case 1: case 2: assert(false); // UNFINISHED break; default: assert(false); // sanity check } // switch *//* * NOTE: it's possible that if we scan through to find where the * run goes, we might be able to extend the previous block extent. * This will require that we set up br.start to be where we'd like to * start looking through the free block list, and then modifying * getFreeBlock() to honour that. *//* br.AG = inode->inodeNum.AG; // request a sane allocation group br.start = 0; // getFreeBlock() will ignore this *//* * The length that we need is determined by how much extra slack we * already have in the pre-allocated blocks. * e.g. (assumes 4k blocks) * bSize = 4096 * maxRange = 4096 * size = 3000 * offset = 3000 * size = 4000 * [--- data block ---][--- data block ---] <---- blocks on disk * <-file data-> <---- actual file size * <-----> <---- slack * [ data block size ] <---- maxRange * | <---- offset * ***************** <---- new data * * In the above example, you'd need at least one more block to write * out the data. * ((offset + size) - maxRange + (bSize-1)) / bSize * ((3000 + 4000) - 4096 + (4095)) / 4096 == 1 (rounded down) * And then we expand it by a little extra so we don't have to keep * looking for more blocks. Currently we use 32k of slack (or 8 blocks) *//* br.len = ((EORPos - maxRange + (bSize-1)) / bSize); if (br.len < 8) br.len = 8; // we allocate 32k if the file needs to grow br = getFreeBlock(br); assert(br.len > 0); switch (whichBlocks) { case 0: inode->blocks.direct[i] = br; inode->blocks.maxDirectRange += br.len * bSize; break; case 1: assert(false); // UNFINISHED inode->blocks.maxIndirectRange += br.len * bSize; break; case 2: assert(false); // UNFINISHED inode->blocks.maxDoubleIndirectRange += br.len * bSize; break; default: assert(false); // sanity check } // switch inode->blocks.size = EORPos; } // if runRemainder = size % 512; size -= runRemainder; totalSize = sum = i = 0; while (size > 0) { / place check here to see which set of blocks we're looking through // scan through direct blocks do { if (offset >= sum && offset < sum + inode->blocks.direct[i].len * bSize) break; sum += inode->blocks.direct[i++].len * bSize; } while (i < NUM_DIRECT_BLOCKS); startingBlock = (inode->blocks.direct[i].AG << superBlock->AGShift) + inode->blocks.direct[i].start + ((offset - sum) / bSize); runSize = inode->blocks.direct[i].len * bSize; // startingBlock is in 4k blocks startingBlock *= (bSize / 512); // startingBlock is now in sectors if (runSize >= size) { runSize = size; size = 0; } else { size -= runSize; } // else sectorCount = runSize / 512; cout << "device->write(device, data, " << startingBlock << ", "; cout << sectorCount << ");" << endl; device->write(device, data, startingBlock, sectorCount); (uInt8 *)data += runSize; totalSize += runSize; } // while assert(runRemainder != 0); // UNFINISHED return totalSize; } // UbixFS::vfs_write int UbixFS::vfs_stop(void) { if (vfs_sync() != 0) return -1; // you must delete the root dir first, in case it needs to // still write anything out if (root != NULL) { ubixfsInode * rootInode = static_cast<ubixfsInode *>(root->inode); delete rootInode->data.btPtr; delete rootInode; root->inode = NULL; } // if delete root; delete [] freeBlockList; delete superBlock; freeBlockList = NULL; superBlock = NULL; root = NULL; *//* * The device isn't null at this point, allowing for people to restart * the mount point. Or, alternatively, to blow things up. *//* return 0; } // UbixFS::vfs_stop int UbixFS::vfs_sync(void) { if (device == NULL || superBlock == NULL || freeBlockList == NULL) return -1; device->write(device, freeBlockList, device->sectors - superBlock->batSectors - 1, superBlock->batSectors ); device->write(device, superBlock, device->sectors-1, 1); return 0; } // UbixFS::vfs_sync void UbixFS::setFreeBlock(blockRun ibr) { signed char * ptr; if (superBlock == NULL || freeBlockList == NULL) return; if (ibr.len == 0) return; ptr = freeBlockList + ((ibr.AG << superBlock->AGShift) >> 3); ptr += ibr.start >> 3; if (ibr.start % 8 != 0) { ibr.len -= ibr.start % 8; } // if } // UbixFS::setFreeBlock blockRun UbixFS::getFreeBlock(blockRun ibr) { signed char * ptr; signed char * holdPtr; int32 count, holdCount; blockRun obr = {0, 0, 0}; // output block run // Check to make sure none of these are null if (device == NULL || freeBlockList == NULL || superBlock == NULL) return obr; if (ibr.len == 0) return obr; if (ibr.len > superBlock->numBlocks) return obr; if (ibr.len == 1) return getFreeBlock(ibr.AG); *//* * count is the block from the base of the list. * Since we're given a specific AG to look through, we start the count at * AG << AGShift, where AGShift is the shift value of the number of blocks * in an AG *//* count = (ibr.AG << superBlock->AGShift); *//* * The freeBlockList is a bit map of the free/used blocks. * Used = on bit * Unused = off bit * There are 8 bits per byte (hopefully) and so we have to divide the count * by 8 to get our starting byte offset to look from *//* ptr = freeBlockList + (count >> 3); rescan: // look for the first free 8 blocks (this may create holes) while (*ptr != 0) { ++ptr; count += 8; if (count+8 > superBlock->numBlocks) { ptr = freeBlockList; count = 0; } // if } // while *ptr != 0 holdPtr = ptr; holdCount = count; for (unsigned short i = 0; i < ((ibr.len+7) / 8); i++) { ++ptr; count += 8; if (count+8 > superBlock->numBlocks) { ptr = freeBlockList; count = 0; goto rescan; } // if if (*ptr != 0) goto rescan; } // for i // we have found a range of blocks that work for us obr.AG = holdCount / superBlock->blocksPerAG; obr.start = holdCount % superBlock->blocksPerAG; obr.len = ibr.len; for (unsigned short i = 0; i < (ibr.len / 8); i++) { *holdPtr = -1; ++holdPtr; } // for if (ibr.len % 8 != 0) *holdPtr = (-1 << (8-(ibr.len % 8))); superBlock->usedBlocks += ibr.len; // increment the number of used blocks return obr; } // UbixFS::getFreeBlock blockRun UbixFS::getFreeBlock(uInt32 AG) { // AG == AllocationGroup blockRun br; signed char * ptr; int32 count; int32 subCount = 128; br.AG = 0; br.start = 0; br.len = 0; // Check to make sure neither of these are null if (device == NULL || freeBlockList == NULL || superBlock == NULL) return br; // Are there any blocks available? if (superBlock->numBlocks == superBlock->usedBlocks) return br; *//* * count is the block from the base of the list. * Since we're given a specific AG to look through, we start the count at * AG << AGShift, where AGShift is the shift value of the number of blocks * in an AG *//* count = (AG << superBlock->AGShift); *//* * The freeBlockList is a bit map of the free/used blocks. * Used = on bit * Unused = off bit * There are 8 bits per byte (hopefully) and so we have to divide the count * by 8 to get our starting byte offset to look from *//* ptr = freeBlockList + (count >> 3); // Scan through the freeBlockList rescan: while (*ptr == -1) { ++ptr; count += 8; if (count+8 > superBlock->numBlocks) break; } // while *ptr == -1 subCount = 128; do { if ((*ptr & subCount) == 0) break; subCount >>= 1; ++count; if (count == superBlock->numBlocks) { count = 0; ptr = freeBlockList; goto rescan; } // if } while(subCount > 1); *ptr |= subCount; // mark this block as used ++superBlock->usedBlocks; // increment the number of used blocks br.AG = count / superBlock->blocksPerAG; br.start = count % superBlock->blocksPerAG; br.len = 1; return br; // return the allocated block number } // Ubixfs::getFreeBlock uInt32 UbixFS::getNextAG(void) { if (superBlock->lastUsedAG == superBlock->numAGs) superBlock->lastUsedAG = 0; else superBlock->lastUsedAG++; return superBlock->lastUsedAG; } // UbixFS::getNextAG *//* * UbixFS::getFreeBlock(void) * upon success returns a free block based on the next AG after the lastUsedAG * failure returns -1 *//* blockRun UbixFS::getFreeBlock(void) { return getFreeBlock(getNextAG()); } // UbixFS::getFreeBlock blockRun UbixFS::get8FreeBlocks(uInt32 AG) { // AG == AllocationGroup blockRun br; signed char * ptr; signed char * endPtr; int32 count; br.AG = 0; br.start = 0; br.len = 0; if (device == NULL || freeBlockList == NULL || superBlock == NULL) return br; // Are there any blocks available? if (superBlock->usedBlocks+8 > superBlock->numBlocks) return br; *//* * count is the block from the base of the list. * Since we're given a specific AG to look through, we start the count at * AG << AGShift, where AGShift is the shift value of the number of blocks * in an AG *//* count = (AG << superBlock->AGShift); ptr = freeBlockList + (count >> 3); endPtr = freeBlockList + (superBlock->numBlocks >> 3); bool secondTime = false; while (*ptr != 0) { ++ptr; count += 8; if (ptr == endPtr) { if (secondTime) return br; else secondTime = true; count = 0; ptr = freeBlockList; } // if } // while *ptr = -1; // mark 8 blocks as taken br.AG = count / superBlock->blocksPerAG; br.start = count % superBlock->blocksPerAG; br.len = 8; return br; } // UbixFS::get8FreeBlocks void * UbixFS::mknod(const char *filename, ubixfsInode * parent, mode_t mode) { ubixfsInode * inode = NULL; inode = new ubixfsInode; assert(inode); if (inode == NULL) return NULL; memset(inode, 0, sizeof(ubixfsInode)); inode->magic1 = UBIXFS_INODE_MAGIC; *//* * in retrospect.. I'm not sure why parent would be null.. only the * root directory would have a null parent, but that's manually allocated * in vfs_format() *//* if (parent == NULL) { inode->inodeNum = getFreeBlock(); inode->parent.iAddr.AG = 0; inode->parent.iAddr.start = 0; inode->parent.iAddr.len = 0; } else { inode->inodeNum = getFreeBlock(parent->inodeNum.AG); inode->parent.iAddr = parent->inodeNum; } // else strncpy(inode->name, filename, MAX_FILENAME_LENGTH); inode->uid = getuid(); inode->gid = getgid(); // inode->mode inode->flags = mode; // inode->createTime // inode->lastModifiedTime inode->inodeSize = superBlock->inodeSize; inode->attributes.AG = 0; inode->attributes.start = 0; inode->attributes.len = 0; // inode->type *//* * next and prev are used in memory to hold pointers to the next/prev * inodes in this dir. On disk they may have another value, but for * now they should be set to null. *//* inode->next.offset = 0; inode->prev.offset = 0; inode->refCount = 0; ++superBlock->inodeCount; return inode; } // UbixFS::mknod int UbixFS::vfs_mkdir(const char * path, mode_t mode) { char name[MAX_FILENAME_LENGTH]; unsigned int start, end, len, nameStart; ubixfsInode * dir = static_cast<ubixfsInode *>(root->inode); ubixfsInode * inode = NULL; assert(path); // bad input: vfs_mkdir(NULL); assert(*path); // bad input: vfs_mkdir(""); memset(&name, 0, sizeof(name)); // find the dir name len = strlen(path); assert(path[0] == '/'); // bad input: vfs isn't doing its job assert(len > 1); // bad input: mkdir / // remove trailing "/" if present if (path[len-1] == '/') --len; assert(len > 1); // bad input: mkdir // nameStart = len-1; assert(path[nameStart] != '/'); // bad input: mkdir /a// *//* * we're guaranteed by the assert() above that there is * at least one "/" before our location. If you remove the assert * you might need to make sure nameStart stays above 0 in the following * while *//* while (path[nameStart] != '/') --nameStart; ++nameStart; assert(len - nameStart > 0); *//* e.g. * v--------------------- start * v------------------ end * v------ nameStart * /usr/local/data/dirname/ <--- ignores trailing / * <---------23----------> len *//* start = end = 1; // skip leading / while (end < nameStart) { do { ++end; } while(path[end] != '/'); assert(end-start+1 < sizeof(name)); // this is probably wrong: strncpy(name, &path[start], end-start+1); cout << name << endl; dir = dir->data.btPtr->Find(name); assert(dir); assert(dir->flags & INODE_DIRECTORY == INODE_DIRECTORY); start = ++end; } strncpy(name, &path[nameStart], len - nameStart); inode = (ubixfsInode *)mknod(name, dir, mode | INODE_DIRECTORY); *//* * keep in mind that the reason for passing in the name is because * we thought about allowing key names to be different from inode * names. In retrospect, I don't think that's a good idea since a dir * listing will print the actual dir name instead of . and .. * Thus: the first parameter of btPtr->Insert() may go away. *//* assert(dir->data.btPtr->Insert(inode->name, inode)); return 0; } // UbixFS::vfs_mkdir void UbixFS::printFreeBlockList(uInt32 AG) { unsigned int j; if (superBlock == NULL || freeBlockList == NULL) return; printf("AG = %d\n", AG); for (unsigned int i = 0; i < superBlock->blocksPerAG / 8; i++) { j = 128; signed char foo = freeBlockList[(AG << superBlock->AGShift)+i]; while (j > 0) { if ((foo & j) == j) printf("1"); else printf("0"); j >>= 1; } } // for i printf("\n"); return; } // UbixFS::printFreeBlockList UbixFS::~UbixFS(void) { delete [] freeBlockList; return; } */