UbixOS V2  2.0
ubixfs.cpp
Go to the documentation of this file.
1 /*#include <stddef.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <string.h>
5 #include <assert.h>
6 #include <iostream>
7 
8 #include "ubixfs.h"
9 #include "btree.h"
10 
11 using namespace std;
12 
13 UbixFS::UbixFS(void) {
14  device = NULL;
15  freeBlockList = NULL;
16  superBlock = NULL;
17  root = NULL;
18 } // UbixFS::UbixFS
19 
20 
21 UbixFS::UbixFS(device_t * dev) {
22  device = dev;
23  freeBlockList = NULL;
24  superBlock = NULL;
25  root = NULL;
26 } // UbixFS::UbixFS
27 
28 void
29 UbixFS::printSuperBlock(void) {
30  printf("superBlock->name........... %s\n", superBlock->name);
31  printf("superBlock->magic1......... %X\n", superBlock->magic1);
32  printf("superBlock->fsByteOrder.... %d\n", superBlock->fsByteOrder);
33  printf("superBlock->blockSize...... %d\n", superBlock->blockSize);
34  printf("superBlock->blockShift..... %d\n", superBlock->blockShift);
35  printf("superBlock->numBlocks...... %lld\n", superBlock->numBlocks);
36  printf("superBlock->usedBlocks..... %lld\n", superBlock->usedBlocks);
37  printf("superBlock->batSectors..... %d\n", superBlock->batSectors);
38  printf("superBlock->inodeCount..... %d\n", superBlock->inodeCount);
39  printf("superBlock->magic2......... %X\n", superBlock->magic2);
40  printf("superBlock->blocksPerAG.... %d\n", superBlock->blocksPerAG);
41  printf("superBlock->AGShift........ %d\n", superBlock->AGShift);
42  printf("superBlock->numAGs......... %d\n", superBlock->numAGs);
43  printf("superBlock->lastUsedAG..... %d\n", superBlock->lastUsedAG);
44  printf("superBlock->flags.......... %X\n", superBlock->flags);
45  printf("superBlock->magic3......... %X\n", superBlock->magic3);
46  return;
47 } // UbixFS::printSuperBlock
48 
49 int
50 UbixFS::vfs_init(void) {
51 assert(device);
52  size_t result;
53  cout << "vfs_init()" << endl;
54  assert(device);
55 
56  if (device == NULL) return -1;
57  if (superBlock != NULL) delete superBlock;
58  superBlock = new diskSuperBlock;
59 assert(superBlock);
60  if (superBlock == NULL) return -1;
61 
62  // read in the superBlock. It's always the last block on the partition
63 cout << "reading in superBlock" << endl;
64  device->read(device, superBlock, device->sectors-1, 1);
65 cout << "done" << endl;
66 
67  assert(superBlock->magic1 == UBIXFS_MAGIC1);
68  assert(superBlock->magic2 == UBIXFS_MAGIC2);
69  assert(superBlock->magic3 == UBIXFS_MAGIC3);
70  assert(strcmp(superBlock->name, "UbixFS") == 0);
71  assert((1 << superBlock->blockShift) == superBlock->blockSize);
72  assert((unsigned)(1 << superBlock->AGShift) == superBlock->blocksPerAG);
73  assert(superBlock->flags == UBIXFS_CLEAN);
74 
75  if (freeBlockList != NULL) delete [] freeBlockList;
76  freeBlockList = new signed char[superBlock->batSectors*512];
77 assert(freeBlockList);
78  memset(freeBlockList, 0, superBlock->batSectors*512);
79 
80  device->read(device,
81  freeBlockList,
82  device->sectors - superBlock->batSectors-1,
83  superBlock->batSectors
84  ); // device->read()
85 
86  root = new fileDescriptor;
87  assert(root);
88  memset(root, 0, sizeof(fileDescriptor));
89 cout << "allocating root dir inode" << endl;
90  root->inode = new ubixfsInode;
91  memset(root->inode, 0, sizeof(ubixfsInode));
92 cout << "root dir inode starting sector: " <<
93  ((superBlock->rootDir.AG << superBlock->AGShift)
94  + superBlock->rootDir.start) * (superBlock->blockSize / 512)
95  << endl;
96 
97 cout << "reading in root dir inode" << endl;
98 
99  device->read(device,
100  root->inode,
101  ((superBlock->rootDir.AG << superBlock->AGShift)
102  + superBlock->rootDir.start) * (superBlock->blockSize / 512),
103  sizeof(ubixfsInode) / 512
104  );
105 cout << "done" << endl;
106  ubixfsInode * rootInode = static_cast<ubixfsInode *>(root->inode);
107  assert(rootInode);
108 
109  //the bTree constructor now loads in the header
110 
111  rootInode->data.btPtr = new bTree(this, root);
112  rootInode->data.btPtr->Info();
113  printSuperBlock();
114  return 0;
115 } // UbixFS::init
116 
117 int
118 UbixFS::vfs_format(device_t * dev) {
119  cout << "vfs_format()" << endl;
120  char sector[512];
121  uInt32 blocks, batSect, batSize;
122  if (dev == NULL) return -1;
123 
124  // zero out the sector
125  memset(&sector, 0x0, sizeof(sector));
126 
127  // fill the drive in with zeroed out sectors
128  cout << "dev->sectors: " << dev->sectors << endl;
129  cout << "clearing device...";
130 
131  for (unsigned int i = 0; i < dev->sectors; i++) {
132  dev->write(dev, &sector, i, 1);
133  } // for i
134 
135  cout << "done" << endl;
136 
137  // allocate a new superBlock and clear it
138 
139  diskSuperBlock *sb = new diskSuperBlock;
140  if (sb == NULL) return -1;
141  memset(sb, 0, sizeof(diskSuperBlock));
142 
143  // dev->sectors is the number of 512 byte sectors
144 
145  blocks = (dev->sectors-1) / 8; // 4k blocks
146  batSize = (dev->sectors-1) % 8; // remainder
147 
148  // compute the BAT size
149 
150  while ((batSize * 4096) < blocks) {
151  batSize += 8;
152  --blocks;
153  } // while
154 
155  // batSize is in sectors
156  batSect = blocks * 8;
157 
158  strcpy(sb->name, "UbixFS");
159  sb->magic1 = UBIXFS_MAGIC1;
160  sb->fsByteOrder = 0;
161  sb->blockSize = 4096;
162  sb->blockShift = 12;
163  sb->numBlocks = blocks;
164  sb->usedBlocks = 2; // root dir takes two blocks (inode + bTree header)
165  sb->inodeCount = 1;
166  sb->inodeSize = 4096;
167  sb->magic2 = UBIXFS_MAGIC2;
168  sb->blocksPerAG = 2048;
169  sb->AGShift = 11;
170  sb->numAGs = (sb->numBlocks+2047) / 2048;
171  sb->lastUsedAG = 0;
172 
173  // the BAT exists outside our official block count, so no
174  // entries in the BAT need to be set for it
175  sb->batSectors = batSize;
176 
177  sb->flags = 0x434C454E; // CLEN
178  sb->logBlocks.AG = 0;
179  sb->logBlocks.start = 0;
180  sb->logBlocks.len = 0;
181  sb->logStart = 0;
182  sb->logEnd = 0;
183  sb->magic3 = UBIXFS_MAGIC3;
184  sb->indicies.AG = 0;
185  sb->indicies.start = 0;
186  sb->indicies.len = 0;
187 
188  sb->rootDir.AG = 0;
189  sb->rootDir.start = 0;
190  sb->rootDir.len = 1;
191 
192  // write out the superBlock
193 
194  dev->write(dev, sb, dev->sectors-1, 1);
195 
196  // mark the first two 4k blocks used
197  memset(&sector, 0, sizeof(sector));
198  sector[0] = (1 << 7) | (1 << 6);
199 
200  // write out the first sector of the BAT
201 
202  dev->write(dev, &sector, batSect, 1);
203  // clear the rest
204  sector[0] = 0;
205 
206  // write out the rest of the BAT
207 
208  for (unsigned int i = 1; i < batSize; i++) {
209  dev->write(dev, &sector, (batSect)+i, 1);
210  } // for i
211 
212  // allocate part of the root dir
213 
214  // sanity checks
215  assert(sb->blockSize);
216  assert((unsigned)sb->blockSize >= sizeof(bTreeHeader));
217 
218  bTreeHeader * bth = new bTreeHeader;
219  assert(bth);
220  memset(bth, 0, sizeof(bTreeHeader));
221 
222  bth->firstDeleted = -1;
223  bth->firstNodeOffset = -1;
224  bth->treeDepth = 1;
225  bth->treeWidth = 0;
226  bth->treeLeafCount = 0;
227 
228  // create the root dir inode here
229 
230  ubixfsInode * inode = new ubixfsInode;
231  assert(inode);
232  if (inode == NULL) return -1;
233  memset(inode, 0, sizeof(ubixfsInode));
234 
235  inode->magic1 = UBIXFS_INODE_MAGIC;
236 
237  // inodes point to themselves
238  inode->inodeNum.AG = 0;
239  inode->inodeNum.start = 0;
240  inode->inodeNum.len = 1;
241 
242  // root dir has no parent directory
243  inode->parent.iAddr.AG = 0;
244  inode->parent.iAddr.start = 0;
245  inode->parent.iAddr.len = 0;
246 
247  // this is part of the root dir structure (the bTreeHeader)
248  inode->blocks.direct[0].AG = 0;
249  inode->blocks.direct[0].start = 1;
250  inode->blocks.direct[0].len = 1;
251 
252  inode->blocks.maxDirectRange = sizeof(bTreeHeader);
253  inode->blocks.size = sizeof(bTreeHeader);
254 
255  strcpy(inode->name, "/");
256  inode->uid = getuid();
257  inode->gid = getgid();
258  // inode->mode
259  inode->flags = INODE_DIRECTORY;
260  // inode->createTime
261  // inode->lastModifiedTime
262  // inode->type
263 
264  inode->attributes.AG = 0;
265  inode->attributes.start = 0;
266  inode->attributes.len = 0;
267 
268  inode->inodeSize = sb->inodeSize;
269 
270  *//*
271  * next and prev are used in memory to hold pointers to the next/prev
272  * inodes in this dir. On disk they may have another value, but for
273  * now they should be set to null.
274  *//*
275 
276  inode->next.offset = 0;
277  inode->prev.offset = 0;
278 
279  // write out the "root" dir inode
280 
281  dev->write(dev,
282  inode,
283  ((inode->inodeNum.AG << sb->AGShift) +
284  inode->inodeNum.start) * (sb->blockSize / 512),
285  sb->inodeSize / 512
286  ); // dev->write
287 
288  // write out the "root" dir
289 
290  dev->write(dev,
291  bth,
292  ((inode->blocks.direct[0].AG << sb->AGShift) +
293  inode->blocks.direct[0].start) * (sb->blockSize / 512),
294  sb->blockSize / 512
295  ); // dev->write
296 
297  delete inode;
298  delete bth;
299  delete sb;
300  cout << "format complete" << endl;
301  return 0;
302 } // UbixFS::vfs_format
303 
304 void *
305 UbixFS::vfs_mknod(const char *path, mode_t mode) {
306  return mknod(path, 0, mode); // <- this probably isn't correct
307 } // UbixFS::vfs_mknod
308 
309 int
310 UbixFS::vfs_open(const char * filename, fileDescriptor * fd, int flags, ...) {
311  if (filename == NULL || fd == NULL) return -1;
312  flags = flags;
313  fd->inode = NULL;
314  fd->offset = 0;
315  fd->size = 0;
316  // look up the file here
317  return 0;
318 } // UbixFS::vfs_open
319 
320 size_t
321 UbixFS::vfs_read(fileDescriptor * fd, void * data, off_t offset, size_t size) {
322 
323  unsigned int i;
324  off_t sum, startingBlock;
325  size_t runSize, sectorCount, totalSize, bSize; // blockSize
326  ubixfsInode * inode = NULL;
327 
328  if (fd == NULL || data == NULL) return ~0;
329 
330  if (size == 0) return 0; // don't fail if size is 0?
331 
332  assert(device);
333  assert(superBlock);
334 
335  inode = static_cast<ubixfsInode *>(fd->inode);
336 
337  assert(inode);
338 
339  bSize = superBlock->blockSize;
340 
341  totalSize = sum = i = 0;
342 
343  while (size > 0) {
344 
345  *//*
346  * place check here to see which set of blocks we're looking through
347  *//*
348 
349  // scan through direct blocks
350  do {
351  if (offset >= sum && offset < sum + inode->blocks.direct[i].len * bSize) break;
352 
353  sum += inode->blocks.direct[i++].len * bSize;
354 
355  } while (i < NUM_DIRECT_BLOCKS);
356 
357  startingBlock = (inode->blocks.direct[i].AG << superBlock->AGShift) +
358  inode->blocks.direct[i].start + ((offset - sum) / bSize);
359 
360  runSize = inode->blocks.direct[i].len * bSize;
361 
362  // startingBlock is in 4k blocks
363  startingBlock *= (bSize / 512);
364  // startingBlock is now in sectors
365 
366  if (runSize >= size) {
367  runSize = size;
368  size = 0;
369  } else {
370  size -= runSize;
371  } // else
372 
373  sectorCount = runSize / 512;
374 
375  cout << "device->read(device, data, " << startingBlock << ", ";
376  cout << sectorCount << ");" << endl;
377 
378  device->read(device, data, startingBlock, sectorCount);
379 
380  (uInt8 *)data += runSize;
381  totalSize += runSize;
382  } // while
383  return totalSize;
384 } // UbixFS::vfs_read
385 
386 size_t
387 UbixFS::vfs_write(fileDescriptor * fd, void * data, off_t offset, size_t size) {
388  // char * sector[512]; // used to pad
389  unsigned int i, whichBlocks;
390  off_t sum, startingBlock, EORPos, maxRange;
391  size_t runSize, runRemainder, sectorCount, totalSize, bSize; // blockSize
392  ubixfsInode * inode = NULL;
393  blockRun br;
394 
395  if (fd == NULL || data == NULL) return ~0;
396 
397  if (size == 0) return 0; // don't fail if size is 0?
398 
399  assert(device);
400  assert(superBlock);
401 
402  inode = static_cast<ubixfsInode *>(fd->inode);
403 
404  assert(inode);
405 
406  bSize = superBlock->blockSize;
407  assert(bSize != 0);
408 
409  totalSize = sum = i = whichBlocks = 0;
410 
411  EORPos = offset + size; // compute End Of Run Position
412  maxRange = inode->blocks.maxDirectRange;
413 
414  if (inode->blocks.maxIndirectRange > maxRange) {
415  maxRange = inode->blocks.maxIndirectRange;
416  whichBlocks = 1;
417  }
418 
419  if (inode->blocks.maxDoubleIndirectRange > maxRange) {
420  maxRange = inode->blocks.maxDoubleIndirectRange;
421  whichBlocks = 2;
422  }
423 
424  if (EORPos > maxRange) {
425  *//*
426  * The offset+size is greater than the size of the file, so we need to
427  * extend out the file. Scan through the direct blocks (FIX LATER)
428  * to find out where we need to extend
429  *//*
430  switch (whichBlocks) {
431  case 0:
432  while (i < NUM_DIRECT_BLOCKS && inode->blocks.direct[i].len != 0) ++i;
433  // i holds which direct block we're going to add to
434  break;
435  case 1:
436  case 2:
437  assert(false); // UNFINISHED
438  break;
439  default:
440  assert(false); // sanity check
441  } // switch
442 
443  *//*
444  * NOTE: it's possible that if we scan through to find where the
445  * run goes, we might be able to extend the previous block extent.
446  * This will require that we set up br.start to be where we'd like to
447  * start looking through the free block list, and then modifying
448  * getFreeBlock() to honour that.
449  *//*
450 
451  br.AG = inode->inodeNum.AG; // request a sane allocation group
452  br.start = 0; // getFreeBlock() will ignore this
453 
454  *//*
455  * The length that we need is determined by how much extra slack we
456  * already have in the pre-allocated blocks.
457  * e.g. (assumes 4k blocks)
458  * bSize = 4096
459  * maxRange = 4096
460  * size = 3000
461  * offset = 3000
462  * size = 4000
463  * [--- data block ---][--- data block ---] <---- blocks on disk
464  * <-file data-> <---- actual file size
465  * <-----> <---- slack
466  * [ data block size ] <---- maxRange
467  * | <---- offset
468  * ***************** <---- new data
469  *
470  * In the above example, you'd need at least one more block to write
471  * out the data.
472  * ((offset + size) - maxRange + (bSize-1)) / bSize
473  * ((3000 + 4000) - 4096 + (4095)) / 4096 == 1 (rounded down)
474  * And then we expand it by a little extra so we don't have to keep
475  * looking for more blocks. Currently we use 32k of slack (or 8 blocks)
476  *//*
477 
478  br.len = ((EORPos - maxRange + (bSize-1)) / bSize);
479 
480  if (br.len < 8) br.len = 8; // we allocate 32k if the file needs to grow
481 
482  br = getFreeBlock(br);
483  assert(br.len > 0);
484  switch (whichBlocks) {
485  case 0:
486  inode->blocks.direct[i] = br;
487  inode->blocks.maxDirectRange += br.len * bSize;
488  break;
489  case 1:
490  assert(false); // UNFINISHED
491  inode->blocks.maxIndirectRange += br.len * bSize;
492  break;
493  case 2:
494  assert(false); // UNFINISHED
495  inode->blocks.maxDoubleIndirectRange += br.len * bSize;
496  break;
497  default:
498  assert(false); // sanity check
499  } // switch
500 
501  inode->blocks.size = EORPos;
502  } // if
503 
504 
505  runRemainder = size % 512;
506  size -= runRemainder;
507 
508  totalSize = sum = i = 0;
509 
510  while (size > 0) {
511 
512  / place check here to see which set of blocks we're looking through
513 
514 
515  // scan through direct blocks
516  do {
517  if (offset >= sum && offset < sum + inode->blocks.direct[i].len * bSize)
518  break;
519 
520  sum += inode->blocks.direct[i++].len * bSize;
521 
522  } while (i < NUM_DIRECT_BLOCKS);
523 
524  startingBlock = (inode->blocks.direct[i].AG << superBlock->AGShift) +
525  inode->blocks.direct[i].start + ((offset - sum) / bSize);
526 
527  runSize = inode->blocks.direct[i].len * bSize;
528 
529  // startingBlock is in 4k blocks
530  startingBlock *= (bSize / 512);
531  // startingBlock is now in sectors
532 
533  if (runSize >= size) {
534  runSize = size;
535  size = 0;
536  } else {
537  size -= runSize;
538  } // else
539 
540  sectorCount = runSize / 512;
541 
542  cout << "device->write(device, data, " << startingBlock << ", ";
543  cout << sectorCount << ");" << endl;
544 
545  device->write(device, data, startingBlock, sectorCount);
546 
547  (uInt8 *)data += runSize;
548  totalSize += runSize;
549  } // while
550 
551  assert(runRemainder != 0); // UNFINISHED
552  return totalSize;
553 } // UbixFS::vfs_write
554 
555 int
556 UbixFS::vfs_stop(void) {
557  if (vfs_sync() != 0) return -1;
558 
559  // you must delete the root dir first, in case it needs to
560  // still write anything out
561 
562  if (root != NULL) {
563  ubixfsInode * rootInode = static_cast<ubixfsInode *>(root->inode);
564  delete rootInode->data.btPtr;
565  delete rootInode;
566  root->inode = NULL;
567 
568  } // if
569 
570  delete root;
571  delete [] freeBlockList;
572  delete superBlock;
573 
574  freeBlockList = NULL;
575  superBlock = NULL;
576  root = NULL;
577 
578  *//*
579  * The device isn't null at this point, allowing for people to restart
580  * the mount point. Or, alternatively, to blow things up.
581  *//*
582 
583  return 0;
584 } // UbixFS::vfs_stop
585 
586 int
587 UbixFS::vfs_sync(void) {
588  if (device == NULL || superBlock == NULL || freeBlockList == NULL) return -1;
589  device->write(device,
590  freeBlockList,
591  device->sectors - superBlock->batSectors - 1,
592  superBlock->batSectors
593  );
594  device->write(device, superBlock, device->sectors-1, 1);
595  return 0;
596 } // UbixFS::vfs_sync
597 
598 void
599 UbixFS::setFreeBlock(blockRun ibr) {
600  signed char * ptr;
601 
602  if (superBlock == NULL || freeBlockList == NULL) return;
603  if (ibr.len == 0) return;
604  ptr = freeBlockList + ((ibr.AG << superBlock->AGShift) >> 3);
605  ptr += ibr.start >> 3;
606 
607  if (ibr.start % 8 != 0) {
608 
609  ibr.len -= ibr.start % 8;
610  } // if
611 
612 } // UbixFS::setFreeBlock
613 
614 blockRun
615 UbixFS::getFreeBlock(blockRun ibr) {
616  signed char * ptr;
617  signed char * holdPtr;
618  int32 count, holdCount;
619 
620  blockRun obr = {0, 0, 0}; // output block run
621 
622  // Check to make sure none of these are null
623  if (device == NULL || freeBlockList == NULL || superBlock == NULL) return obr;
624 
625  if (ibr.len == 0) return obr;
626 
627  if (ibr.len > superBlock->numBlocks) return obr;
628 
629  if (ibr.len == 1) return getFreeBlock(ibr.AG);
630  *//*
631  * count is the block from the base of the list.
632  * Since we're given a specific AG to look through, we start the count at
633  * AG << AGShift, where AGShift is the shift value of the number of blocks
634  * in an AG
635  *//*
636 
637  count = (ibr.AG << superBlock->AGShift);
638 
639  *//*
640  * The freeBlockList is a bit map of the free/used blocks.
641  * Used = on bit
642  * Unused = off bit
643  * There are 8 bits per byte (hopefully) and so we have to divide the count
644  * by 8 to get our starting byte offset to look from
645  *//*
646 
647  ptr = freeBlockList + (count >> 3);
648 
649 rescan:
650  // look for the first free 8 blocks (this may create holes)
651  while (*ptr != 0) {
652  ++ptr;
653  count += 8;
654  if (count+8 > superBlock->numBlocks) {
655  ptr = freeBlockList;
656  count = 0;
657  } // if
658  } // while *ptr != 0
659 
660  holdPtr = ptr;
661  holdCount = count;
662 
663  for (unsigned short i = 0; i < ((ibr.len+7) / 8); i++) {
664  ++ptr;
665  count += 8;
666  if (count+8 > superBlock->numBlocks) {
667  ptr = freeBlockList;
668  count = 0;
669  goto rescan;
670  } // if
671  if (*ptr != 0) goto rescan;
672  } // for i
673 
674  // we have found a range of blocks that work for us
675 
676  obr.AG = holdCount / superBlock->blocksPerAG;
677  obr.start = holdCount % superBlock->blocksPerAG;
678  obr.len = ibr.len;
679 
680  for (unsigned short i = 0; i < (ibr.len / 8); i++) {
681  *holdPtr = -1;
682  ++holdPtr;
683  } // for
684 
685  if (ibr.len % 8 != 0) *holdPtr = (-1 << (8-(ibr.len % 8)));
686 
687  superBlock->usedBlocks += ibr.len; // increment the number of used blocks
688  return obr;
689 } // UbixFS::getFreeBlock
690 
691 blockRun
692 UbixFS::getFreeBlock(uInt32 AG) {
693  // AG == AllocationGroup
694  blockRun br;
695  signed char * ptr;
696  int32 count;
697  int32 subCount = 128;
698 
699  br.AG = 0;
700  br.start = 0;
701  br.len = 0;
702  // Check to make sure neither of these are null
703  if (device == NULL || freeBlockList == NULL || superBlock == NULL) return br;
704 
705  // Are there any blocks available?
706  if (superBlock->numBlocks == superBlock->usedBlocks) return br;
707 
708  *//*
709  * count is the block from the base of the list.
710  * Since we're given a specific AG to look through, we start the count at
711  * AG << AGShift, where AGShift is the shift value of the number of blocks
712  * in an AG
713  *//*
714 
715  count = (AG << superBlock->AGShift);
716 
717  *//*
718  * The freeBlockList is a bit map of the free/used blocks.
719  * Used = on bit
720  * Unused = off bit
721  * There are 8 bits per byte (hopefully) and so we have to divide the count
722  * by 8 to get our starting byte offset to look from
723  *//*
724 
725  ptr = freeBlockList + (count >> 3);
726 
727  // Scan through the freeBlockList
728 
729 rescan:
730  while (*ptr == -1) {
731  ++ptr;
732  count += 8;
733  if (count+8 > superBlock->numBlocks) break;
734  } // while *ptr == -1
735 
736  subCount = 128;
737 
738  do {
739  if ((*ptr & subCount) == 0) break;
740  subCount >>= 1;
741  ++count;
742  if (count == superBlock->numBlocks) {
743  count = 0;
744  ptr = freeBlockList;
745  goto rescan;
746  } // if
747  } while(subCount > 1);
748 
749  *ptr |= subCount; // mark this block as used
750  ++superBlock->usedBlocks; // increment the number of used blocks
751 
752  br.AG = count / superBlock->blocksPerAG;
753  br.start = count % superBlock->blocksPerAG;
754  br.len = 1;
755  return br; // return the allocated block number
756 } // Ubixfs::getFreeBlock
757 
758 uInt32
759 UbixFS::getNextAG(void) {
760 
761  if (superBlock->lastUsedAG == superBlock->numAGs)
762  superBlock->lastUsedAG = 0;
763  else
764  superBlock->lastUsedAG++;
765  return superBlock->lastUsedAG;
766 
767 } // UbixFS::getNextAG
768 
769 *//*
770  * UbixFS::getFreeBlock(void)
771  * upon success returns a free block based on the next AG after the lastUsedAG
772  * failure returns -1
773  *//*
774 
775 blockRun
776 UbixFS::getFreeBlock(void) {
777  return getFreeBlock(getNextAG());
778 } // UbixFS::getFreeBlock
779 
780 blockRun
781 UbixFS::get8FreeBlocks(uInt32 AG) {
782  // AG == AllocationGroup
783  blockRun br;
784  signed char * ptr;
785  signed char * endPtr;
786  int32 count;
787 
788  br.AG = 0;
789  br.start = 0;
790  br.len = 0;
791 
792  if (device == NULL || freeBlockList == NULL || superBlock == NULL) return br;
793 
794  // Are there any blocks available?
795  if (superBlock->usedBlocks+8 > superBlock->numBlocks) return br;
796 
797  *//*
798  * count is the block from the base of the list.
799  * Since we're given a specific AG to look through, we start the count at
800  * AG << AGShift, where AGShift is the shift value of the number of blocks
801  * in an AG
802  *//*
803 
804  count = (AG << superBlock->AGShift);
805 
806  ptr = freeBlockList + (count >> 3);
807 
808  endPtr = freeBlockList + (superBlock->numBlocks >> 3);
809 
810  bool secondTime = false;
811  while (*ptr != 0) {
812  ++ptr;
813  count += 8;
814  if (ptr == endPtr) {
815  if (secondTime)
816  return br;
817  else
818  secondTime = true;
819 
820  count = 0;
821  ptr = freeBlockList;
822  } // if
823  } // while
824 
825  *ptr = -1; // mark 8 blocks as taken
826 
827  br.AG = count / superBlock->blocksPerAG;
828  br.start = count % superBlock->blocksPerAG;
829  br.len = 8;
830  return br;
831 } // UbixFS::get8FreeBlocks
832 
833 void *
834 UbixFS::mknod(const char *filename, ubixfsInode * parent, mode_t mode) {
835  ubixfsInode * inode = NULL;
836 
837  inode = new ubixfsInode;
838  assert(inode);
839  if (inode == NULL) return NULL;
840  memset(inode, 0, sizeof(ubixfsInode));
841 
842  inode->magic1 = UBIXFS_INODE_MAGIC;
843 
844  *//*
845  * in retrospect.. I'm not sure why parent would be null.. only the
846  * root directory would have a null parent, but that's manually allocated
847  * in vfs_format()
848  *//*
849 
850  if (parent == NULL) {
851  inode->inodeNum = getFreeBlock();
852  inode->parent.iAddr.AG = 0;
853  inode->parent.iAddr.start = 0;
854  inode->parent.iAddr.len = 0;
855  } else {
856  inode->inodeNum = getFreeBlock(parent->inodeNum.AG);
857  inode->parent.iAddr = parent->inodeNum;
858  } // else
859 
860  strncpy(inode->name, filename, MAX_FILENAME_LENGTH);
861 
862  inode->uid = getuid();
863  inode->gid = getgid();
864  // inode->mode
865  inode->flags = mode;
866  // inode->createTime
867  // inode->lastModifiedTime
868  inode->inodeSize = superBlock->inodeSize;
869 
870  inode->attributes.AG = 0;
871  inode->attributes.start = 0;
872  inode->attributes.len = 0;
873 
874  // inode->type
875 
876  *//*
877  * next and prev are used in memory to hold pointers to the next/prev
878  * inodes in this dir. On disk they may have another value, but for
879  * now they should be set to null.
880  *//*
881 
882  inode->next.offset = 0;
883  inode->prev.offset = 0;
884  inode->refCount = 0;
885  ++superBlock->inodeCount;
886  return inode;
887 } // UbixFS::mknod
888 
889 int
890 UbixFS::vfs_mkdir(const char * path, mode_t mode) {
891  char name[MAX_FILENAME_LENGTH];
892  unsigned int start, end, len, nameStart;
893  ubixfsInode * dir = static_cast<ubixfsInode *>(root->inode);
894  ubixfsInode * inode = NULL;
895 
896  assert(path); // bad input: vfs_mkdir(NULL);
897  assert(*path); // bad input: vfs_mkdir("");
898 
899  memset(&name, 0, sizeof(name));
900  // find the dir name
901  len = strlen(path);
902 
903  assert(path[0] == '/'); // bad input: vfs isn't doing its job
904  assert(len > 1); // bad input: mkdir /
905 
906  // remove trailing "/" if present
907  if (path[len-1] == '/') --len;
908 
909  assert(len > 1); // bad input: mkdir //
910 
911  nameStart = len-1;
912 
913  assert(path[nameStart] != '/'); // bad input: mkdir /a//
914 
915  *//*
916  * we're guaranteed by the assert() above that there is
917  * at least one "/" before our location. If you remove the assert
918  * you might need to make sure nameStart stays above 0 in the following
919  * while
920  *//*
921 
922  while (path[nameStart] != '/') --nameStart;
923  ++nameStart;
924  assert(len - nameStart > 0);
925 
926  *//* e.g.
927  * v--------------------- start
928  * v------------------ end
929  * v------ nameStart
930  * /usr/local/data/dirname/ <--- ignores trailing /
931  * <---------23----------> len
932  *//*
933 
934  start = end = 1; // skip leading /
935  while (end < nameStart) {
936  do { ++end; } while(path[end] != '/');
937 
938  assert(end-start+1 < sizeof(name));
939  // this is probably wrong:
940  strncpy(name, &path[start], end-start+1);
941  cout << name << endl;
942  dir = dir->data.btPtr->Find(name);
943  assert(dir);
944  assert(dir->flags & INODE_DIRECTORY == INODE_DIRECTORY);
945  start = ++end;
946  }
947 
948  strncpy(name, &path[nameStart], len - nameStart);
949  inode = (ubixfsInode *)mknod(name, dir, mode | INODE_DIRECTORY);
950 
951  *//*
952  * keep in mind that the reason for passing in the name is because
953  * we thought about allowing key names to be different from inode
954  * names. In retrospect, I don't think that's a good idea since a dir
955  * listing will print the actual dir name instead of . and ..
956  * Thus: the first parameter of btPtr->Insert() may go away.
957  *//*
958 
959  assert(dir->data.btPtr->Insert(inode->name, inode));
960 
961  return 0;
962 } // UbixFS::vfs_mkdir
963 
964 void
965 UbixFS::printFreeBlockList(uInt32 AG) {
966  unsigned int j;
967  if (superBlock == NULL || freeBlockList == NULL) return;
968  printf("AG = %d\n", AG);
969  for (unsigned int i = 0; i < superBlock->blocksPerAG / 8; i++) {
970  j = 128;
971  signed char foo = freeBlockList[(AG << superBlock->AGShift)+i];
972  while (j > 0) {
973  if ((foo & j) == j)
974  printf("1");
975  else
976  printf("0");
977  j >>= 1;
978 
979  }
980  } // for i
981  printf("\n");
982  return;
983 } // UbixFS::printFreeBlockList
984 
985 UbixFS::~UbixFS(void) {
986  delete [] freeBlockList;
987  return;
988 }
989 */