Esempio n. 1
0
/*
 * Get the inumber for the given file. Also makes sure that the cursor
 * is within the file.
 */
int
Fileops_getinumber(int fd, int *size)
{
  int inumber;
  struct inode in;
  int err;

  inumber = pathname_lookup(unixfs, openFileTable[fd].pathname);
  if (inumber < 0) {
    return inumber; // Can't find file
  }

  err = inode_iget(unixfs, inumber,&in);
  if (err < 0) {
    return err;
  }
  if (!(in.i_mode & IALLOC)) {
    return -1;
  }

  *size = inode_getsize(&in);

  //if (openFileTable[fd].cursor >= size) return -1; // Finished with file

  return inumber;
}
Esempio n. 2
0
/*
 * Output to the specified file the checksum of all allocated inodes.
 *
 * This is used by the grading script, so be careful not to change its output
 * format.
 */
void
DumpInodeChecksum(struct unixfilesystem *fs, FILE *f)
{
  for (int inumber = 1; inumber < fs->superblock.s_isize*16; inumber++) {
    struct inode in;
    if (inode_iget(fs, inumber, &in) < 0) {
      fprintf(stderr,"Can't read inode %d \n", inumber);
      return;
    }
    if ((in.i_mode & IALLOC) == 0) {
      // Skip this inode if it's not allocated.
      continue;
    }

    char chksum[CHKSUMFILE_SIZE];
    if (chksumfile_byinumber(fs, inumber, chksum) < 0) {
      fprintf(stderr, "Inode %d can't compute chksum\n", inumber);
      continue;
    }

    char chksumstring[CHKSUMFILE_STRINGSIZE];
    chksumfile_cvt2string(chksum, chksumstring);

    int size = inode_getsize(&in);
    fprintf(f, "Inode %d mode 0x%x size %d checksum %s\n",inumber,in.i_mode, size, chksumstring);
  }
}
/*
 * Print all the entries in the specified directory. 
 */
void PrintDirectory(struct unixfilesystem *fs, char *pathname)
{
  int inumber = pathname_lookup(fs, pathname);
  if (inumber < 0) {
    fprintf(stderr, "Can't find %s\n", pathname);
    return;
  }
  
  struct direntv6 direntries[1000];
  int numentries = GetDirEntries(fs, inumber, direntries, 1000);
  if (numentries < 0) {
    fprintf(stderr, "Can't read entries from %s\n", pathname);
    return;
  }
  
  struct inode in;
  int i, rowLength = 0; 
  for (i = 0; i < numentries; i++) { 
      inode_iget(fs, direntries[i].d_inumber, &in);
      printf("%s",direntries[i].d_name);
      if ((in.i_mode & IFMT) == IFDIR)
          printf("/");
      printf("\t");
      rowLength += strlen(direntries[i].d_name) + 1;
      if ((i+1) % 6 == 0)
          puts("");
  }
}
Esempio n. 4
0
/*
 * Lookup the specified name (name) in the directory (dirinumber). If found, return the 
 * directory entry in dirEnt. Return 0 on success and something negative on failure. 
 */
int
directory_findname(struct unixfilesystem *fs, const char *name,
                   int dirinumber, struct direntv6 *dirEnt)
{
  
	struct inode ino;
	if(inode_iget(fs, dirinumber, &ino) == -1) return -1;
	if((ino.i_mode & IFMT) != IFDIR) return -1;

	//traverse the inodes datablocks forloop
	//compare the given file with directory entries
  	int size = inode_getsize(&ino);
	int numBlocks = (size + DISKIMG_SECTOR_SIZE - 1) / DISKIMG_SECTOR_SIZE;

	for(int block = 0; block < numBlocks; block++) {
		struct direntv6 buffer[DISKIMG_SECTOR_SIZE / sizeof(struct direntv6)]; //an array of direntv6s 
		int validBytes = file_getblock(fs, dirinumber, block, &buffer);
		if(validBytes < 0) return -1;
		
		int dirsPerBlock = validBytes / sizeof(struct direntv6); //calculate the number of dirsPerBlock based on validBytes of block

		for(int dir = 0; dir < dirsPerBlock; dir++) {
			if(strcmp(name, buffer[dir].d_name) == 0) { //copy memory into the direntv6 only if name is found in block
				memcpy(dirEnt, &buffer[dir], sizeof(struct direntv6));
				return 0;
			}
		}
		
	}

  	return -1;

}
Esempio n. 5
0
/*
 * Fetch the specified file block from the specified inode.
 * Return the number of valid bytes in the block, -1 on error.
 */
int
file_getblock(struct unixfilesystem *fs, int inumber, int blockNum, void *buf)
{

    // First retrieve the inode in question
    struct inode node;
    int inode_iget_status = inode_iget(fs, inumber, &node);
    if (inode_iget_status == -1)
        return -1;

    // Then we want to get the block
    int block = inode_indexlookup(fs, &node, blockNum);
    if (!block)
        return -1;

    // Now retrive the contents of the block and put it into the buffer
    int sector_status = diskimg_readsector(fs->dfd, block, buf);

    // Figure out what the size was supposed to be
    int inodesize = inode_getsize(&node);

    // Now figure out what the valid number of bytes to return is
    int bytesRemaining = inodesize - blockNum * 512;
    if (bytesRemaining < 512) {
        return bytesRemaining;
    }

    return sector_status;

}
struct unixfilesystem *
unixfilesystem_format(int dfd) 
{
    uint16_t bootblock[256];
    bootblock[0] = BOOTBLOCK_MAGIC_NUM;
    diskimg_writesector(dfd, BOOTBLOCK_SECTOR, bootblock);
    
    struct unixfilesystem *fs = malloc(sizeof(struct unixfilesystem));
    if (fs == NULL) {
      fprintf(stderr,"Out of memory.\n");
      return NULL;
    }
    fs->dfd = dfd;
    
    // 144 inodes in total, so we have 8 blocks 
    // to store inodes, plus 2 start blocks, 
    // we have 10 blocks in use, and we allocate the entire volume 110 blocks
    // so the rest 100 blocks is file blocks, and all blocks formats to free.
    fs->superblock.s_isize = 144;  
    fs->superblock.s_fsize = 110; // 110 blocks of entire volume 
    
    fs->superblock.s_ninode = fs->superblock.s_isize; // at begining, free inodes number = total inodes number
    
    int i;
    // consider s_inode as bitmap
    for (i = 0;i < 100;i++)
        fs->superblock.s_inode[i] = 0;
    
    fs->superblock.s_nfree = fs->superblock.s_fsize ; // at begining, free blocks number = total blocks number
    // consider s_free as bitmap
    for (i = 0;i < 100;i++)
        fs->superblock.s_free[i] = 0;

    diskimg_writesector(dfd, SUPERBLOCK_SECTOR, &fs->superblock);
    
    
    int inumber = filsys_allocInode(fs);
    if (inumber != ROOT_INUMBER) {
        fprintf(stderr, "ROOT_INUMBER is not 1, format failed\n");
        return -1;
    }
    
    struct inode in;
    inode_iget(fs, inumber, &in);
    // format the root dir, and set the i_mode field to DIR
    inode_format(&in);
    //in.i_mode &= (0xffff - IFMT);
    in.i_mode |= IFDIR;
    inode_iwrite(fs, ROOT_INUMBER, &in);
    
    fs->workDirInumber = ROOT_INUMBER;
    strcpy(fs->workDirName, "/");
    return fs;
}
/*
 * Fetch as many entries from a directory that will fit in the specified array. Return the 
 * number of entries found. 
 */
int
GetDirEntries(struct unixfilesystem *fs, int inumber, struct direntv6 *entries, int maxNumEntries)
{
  struct inode in;
  int err = inode_iget(fs, inumber, &in); 
  
  if (err < 0) {
      fprintf(stderr, "GetDirEntries using inode_iget err\n");
      return err;
  }
  
  if (!(in.i_mode & IALLOC) || ((in.i_mode & IFMT) != IFDIR)) {
    /* Not allocated or not a directory */
    fprintf(stderr, "GetDirEntries inode is not dir or not allocated %d %d\n",in.i_mode & IALLOC, (in.i_mode & IFMT) == IFDIR);
    return -1;
  }
  
  if (maxNumEntries < 1) {
      fprintf(stderr, "maxNumEntries = %d\n",maxNumEntries);
      return -1;
  }
  int size = inode_getsize(&in);

  assert((size % sizeof(struct direntv6)) == 0);

  int count = 0;
  
  /* block number in the directory */
  int numBlocks  = (size + DISKIMG_SECTOR_SIZE - 1) / DISKIMG_SECTOR_SIZE;

  /* buf to get bytes from diskimg */ 
  char buf[DISKIMG_SECTOR_SIZE];
  struct direntv6 *dir = (struct direntv6 *) buf; // use direntv6 handle
  int bno;
  for (bno = 0; bno < numBlocks; bno++) {
    int bytesLeft, numEntriesInBlock, i;
    bytesLeft = file_getblock(fs, inumber, bno, dir);
    if (bytesLeft < 0) {
      fprintf(stderr, "Error reading directory\n");
      return -1;
    }
    numEntriesInBlock = bytesLeft / sizeof(struct direntv6); 
    for (i = 0; i <  numEntriesInBlock ; i++) { 
      entries[count] = dir[i];
      count++;
      if (count >= maxNumEntries) return count;
    }
  }
  return count;
}
/*
 * Lookup the specified name (name) in the directory (dirinumber). If found, return the 
 * directory entry in dirEnt. Return 0 on success and something negative on failure. 
 */
int directory_findname(struct unixfilesystem *fs, const char *name,
                   int dirinumber, struct direntv6 *dirEnt)
{
  //return -1;
  //fprintf(stderr, "directory_lookupname(name=%s dirinumber=%d)\n", name, dirinumber); 
  struct inode in;
  int err = inode_iget(fs, dirinumber, &in);
  if (err < 0) {
      fprintf(stderr, "director_findname get inode error");
      return -1;
  }
  
  if (!(in.i_mode & IALLOC) || ((in.i_mode & IFMT) != IFDIR)) {
    fprintf(stderr, "director_findname dir inode is not IFDIR");
    return -1;
  }

  int size = inode_getsize(&in);

  assert((size % sizeof(struct direntv6)) == 0);
  
  /* block number in the directory */
  int numBlocks  = (size + DISKIMG_SECTOR_SIZE - 1) / DISKIMG_SECTOR_SIZE;

  /* buf to get bytes from diskimg */ 
  char buf[DISKIMG_SECTOR_SIZE];
  struct direntv6 *dir = (struct direntv6 *) buf; // use direntv6 handle
  
  int bno;
  for (bno = 0; bno < numBlocks; bno++) {
    int bytesLeft, numEntriesInBlock, i;
    bytesLeft = file_getblock(fs, dirinumber, bno, dir);
    if (bytesLeft < 0) {
      fprintf(stderr, "Error reading directory\n");
      return -1;
    }
    numEntriesInBlock = bytesLeft / sizeof(struct direntv6); 
    for (i = 0; i <  numEntriesInBlock ; i++) {
        //printf("list = %s\n", dir[i].d_name);
        if (strcmp(dir[i].d_name, name) == 0) {
            *dirEnt = dir[i];
            return 0;
        }
    }
  }
  //printf("Dir %d find name not find %s\n",dirinumber, name);
  return -1;
}
Esempio n. 9
0
/*
 * Lookup the specified name (name) in the directory (dirinumber). If found, return the 
 * directory entry in dirEnt. Return 0 on success and something negative on failure. 
 */
int
directory_findname(struct unixfilesystem *fs, const char *name,
                   int dirinumber, struct direntv6 *dirEnt)
{

    // First fetch the inode corresponding to dirinumber
    struct inode in;
    int err = inode_iget(fs, dirinumber, &in);
    if (err < 0) return err;

    // Get the number of blocks
    int size = inode_getsize(&in);
    printf("size: %d\n", size);
    int numBlocks = (size + DISKIMG_SECTOR_SIZE - 1) / DISKIMG_SECTOR_SIZE;

    // Next access the block that has the directory entries
    int numdirent = DISKIMG_SECTOR_SIZE / sizeof(struct direntv6);
    struct direntv6 dir[numdirent];

    // Cached for the strncp function
    int targetlen = strlen(name);

    // Loop through the blocks
    for (int bno = 0; bno < numBlocks; bno++) {

        // Get the number of bytes we want to consider
        int bytes = file_getblock(fs, dirinumber, bno, dir);

        // Loop through the directory entries
        for (int i = 0; i < numdirent; i++) {

            // Use strncmp to see if we have a match on the character name
            if (strncmp(dir[i].d_name, name, targetlen) == 0) {

                // Found it! Set values of dirEnt and return success
                strncpy(dirEnt->d_name, dir[i].d_name, targetlen);
                dirEnt->d_inumber = dir[i].d_inumber;
                return 0;

            }

        }
    }

    return -1;

}
Esempio n. 10
0
int remove_file(struct unixfilesystem *fs, int inumber)
{
  struct inode in;
  int err = inode_iget(fs, inumber, &in);
  if (err < 0) return -1;
  
  if (!(in.i_mode & IALLOC) || ((in.i_mode & IFMT) == IFDIR))
  {
    /* Not allocated or is a directory */
    fprintf(stderr, "The input path is not a file and cannot be removed");
    return -1;
  }
  
  if (in.i_nlink == 1) // only one link, so overwrite the file
  {
    char zeros[DISKIMG_SECTOR_SIZE] = {0};
    int size = inode_getsize(&in);
    int blockNum = 0;
    
    // overwrite the file with zeros
    for (blockNum = 0; blockNum < size / DISKIMG_SECTOR_SIZE; blockNum++)
    {
      char buf[DISKIMG_SECTOR_SIZE];
      
      int blockAddress = inode_indexlookup(fs, &in, blockNum);
      
      if (blockAddress == -1) {
        fprintf(stderr, "Error looking up block number %d in inode %d", blockNum, inumber);
        return -1;
      }
      
      if (diskimg_writesector(fs->dfd, blockAddress, &zeros) == -1)
      {
        fprintf(stderr, "Error overwriting file");
        return -1;
      }
    }
  }
  else  // multiple links to file, so only remove this link
  {
    in.i_nlink--;
    
  }
  
  return 0;
}
Esempio n. 11
0
/*
 * Fetch the next character from the file. Return -1 if at end of file.
 */
int
Fileops_getchar(int fd,int inumber, int size)
{
  int inumber;
  struct inode in;
  unsigned char buf[DISKIMG_SECTOR_SIZE];
  int bytesMoved;
  int err, size;
  int blockNo, blockOffset;

  numgetchars++;

  if (openFileTable[fd].pathname == NULL)
    return -1;  // fd not opened.

  inumber = pathname_lookup(unixfs, openFileTable[fd].pathname);
  if (inumber < 0) {
    return inumber; // Can't find file
  }

  err = inode_iget(unixfs, inumber,&in);
  if (err < 0) {
    return err;
  }
  if (!(in.i_mode & IALLOC)) {
    return -1;
  }

  size = inode_getsize(&in);

  if (openFileTable[fd].cursor >= size) return -1; // Finished with file

  blockNo = openFileTable[fd].cursor / DISKIMG_SECTOR_SIZE;
  blockOffset =  openFileTable[fd].cursor % DISKIMG_SECTOR_SIZE;

  bytesMoved = file_getblock(unixfs, inumber,blockNo,buf);
  if (bytesMoved < 0) {
    return -1;
  }
  assert(bytesMoved > blockOffset);


  openFileTable[fd].cursor += 1;

  return (int)(buf[blockOffset]);
}
Esempio n. 12
0
/*
 * Return true if specified pathname is a regular file.
 */
int
Fileops_isfile(char *pathname)
{
  numisfiles++;

  int inumber = pathname_lookup(unixfs, pathname);
  if (inumber < 0) {
    return 0;
  }

  struct inode in;
  int err = inode_iget(unixfs, inumber, &in);
  if (err < 0) return 0;

  if (!(in.i_mode & IALLOC) || ((in.i_mode & IFMT) != 0)) {
    /* Not allocated or not a file */
    return 0;
  }
  return 1; /* Must be a file */
}
Esempio n. 13
0
/*
 * Fetch the specified file block from the specified inode.
 * Return the number of valid bytes in the block, -1 on error.
 */
int
file_getblock(struct unixfilesystem *fs, int inumber, int blockNum, void *buf)
{
	//fprintf(stderr, "in file_getblock, size %d, inum: %d\n", cacheMemSizeInKB, inumber);
	struct inode in;
	int getResult = inode_iget(fs, inumber, &in);
	int sectorNum = inode_indexlookup(fs, &in, blockNum);
	int bytesRead = diskimg_readsector(fs->dfd, sectorNum, buf);
	if ((getResult == -1) || (bytesRead == -1) || (sectorNum == -1)) return -1;
	int size = inode_getsize(&in);
	if ((size % BYTES_PER_BLOCK) == 0) {
		return BYTES_PER_BLOCK;
	} else {
		int numblocks = (size / BYTES_PER_BLOCK);
		if (blockNum == numblocks) {
			return size % BYTES_PER_BLOCK;
		} else {
			return BYTES_PER_BLOCK;
		}
	}
}
Esempio n. 14
0
/*
 * Fetch the specified file block from the specified inode.
 * Return the number of valid bytes in the block, -1 on error.
 */
int
file_getblock(struct unixfilesystem *fs, int inumber, int blockNum, void *buf)
{
	// Consider inumber = 17, blocknumber = 5: 
	// – Find the inode
	struct inode inp;
	if(inode_iget(fs, inumber, &inp) < 0){
		printf("Error getting inode %i\n", inumber);
		return -1;
	}
	int filesize = inode_getsize(&inp);
	int partial = (filesize % DISKIMG_SECTOR_SIZE == 0) ? 0 : 1;
	int blocks = (filesize / DISKIMG_SECTOR_SIZE) + partial;
	
	// – Find the sector number
	int sectorNum = inode_indexlookup(fs, &inp, blockNum);
	if(sectorNum == -1){
		printf("Error getting data sector %i\n", blockNum);
		return -1;
	}
	if((sectorNum > (int)fs->superblock.s_fsize) || (sectorNum < fs->superblock.s_isize + INODE_START_SECTOR)){
		printf("sectorNum: %i blockNum: %i blocks: %i inode: %i\n", sectorNum, blockNum, blocks, inumber);
		
	}
	// – Read the data in the sector into the buffer
	if (diskimg_readsector(fs->dfd, sectorNum, buf) != DISKIMG_SECTOR_SIZE) {
	    fprintf(stderr, "Error reading sector %i for block %i of %i\n", sectorNum, blockNum, blocks);
	    return -1;
	}
	//Determine value of valid bytes in the block
	if(blockNum == blocks - 1){
		if(partial) {
			return (filesize % DISKIMG_SECTOR_SIZE);
		}else{
			return DISKIMG_SECTOR_SIZE;
		}
	}else{
		return DISKIMG_SECTOR_SIZE;
	}
}
/*
 * Compute the checksum of a inumber. Assumes chksum arguments points to a
 * CHKSUMFILE_SIZE byte array. Returns the length of the checksum, or -1 if
 * it encounters an error.
 */
int
chksumfile_byinumber(struct unixfilesystem *fs, int inumber, void *chksum)
{
  SHA_CTX shactx;
  if (!SHA1_Init(&shactx)) {
    // An error occurred initializing the SHA1 context.
    return -1;
  }

  struct inode in;
  int err = inode_iget(fs, inumber, &in);
  if (err < 0) {
    return err;
  }

  if (!(in.i_mode & IALLOC)) {
    // The inode isn't allocated, so we can't hash it.
    return -1;
  }

  int size = inode_getsize(&in);

  for (int offset = 0; offset < size; offset += DISKIMG_SECTOR_SIZE) {
    char buf[DISKIMG_SECTOR_SIZE];
    int bno = offset/DISKIMG_SECTOR_SIZE;

    int bytesMoved = file_getblock(fs, inumber, bno, buf);
    if (bytesMoved < 0)
      return -1;

    if (!SHA1_Update(&shactx, buf, bytesMoved))
      return -1;
  }

  if (!SHA1_Final(chksum, &shactx))
    return -1;

  return SHA_DIGEST_LENGTH;
}
Esempio n. 16
0
/*
 * Lookup the specified name (name) in the directory (dirinumber). If found, return the 
 * directory entry in dirEnt. Return 0 on success and something negative on failure. 
 */
int
directory_findname(struct unixfilesystem *fs, const char *name,
                   int dirinumber, struct direntv6 *dirEnt)
{
  struct inode directory;
  if (inode_iget(fs, dirinumber, &directory)) return -1;
  int mode = directory.i_mode;
  //Checks that directory is indeed a directory. 
  if ((mode & IFMT) != IFDIR) return -1;
  int dirSize = inode_getsize(&directory);
  int dirBlocks = dirSize / DISKIMG_SECTOR_SIZE;
  int check = 0;
  for (int i=0; i <= dirBlocks; i++)
  {
        struct direntv6 filenames[DIRENTV6_IN_SECTOR];
	int validBytes = file_getblock (fs, dirinumber, i, filenames);
	int validFiles = validBytes / sizeof(struct direntv6);
	check = search_for_filename(filenames, validFiles, name, dirEnt);
	if(check) break;
  }
  return check-1;
}
Esempio n. 17
0
/*
 * Fetch the specified file block from the specified inode.
 * Return the number of valid bytes in the block, -1 on error.
 */
int
file_getblock(struct unixfilesystem *fs, int inumber, int blockNum, void *buf)
{
	//Find the inode
	struct inode inp;
	if(inode_iget(fs, inumber, &inp) < 0){
		printf("Error getting inode %i\n", inumber);
		return -1;
	}
	//Find the sector number for the blockNum
	int sectorNum = inode_indexlookup(fs, &inp, blockNum);
	if(sectorNum == -1){
		printf("Error getting data sector %i\n", blockNum);
		return -1;
	}
	//Read the data in the sector into the buffer
	if (diskimg_readsector(fs->dfd, sectorNum, buf) != DISKIMG_SECTOR_SIZE) {
	    fprintf(stderr, "Error reading sector %i for block %i\n", sectorNum, blockNum);
	    return -1;
	}
	//Return number of valid bytes in the block
	return validBytes(&inp, blockNum);
}
Esempio n. 18
0
/*
 * Lookup the specified name (name) in the directory (dirinumber). If found, return the 
 * directory entry in dirEnt. Return 0 on success and something negative on failure. 
 */
int
directory_findname(struct unixfilesystem *fs, const char *name,
                   int dirinumber, struct direntv6 *dirEnt)
{
	// Get the directory's inode
	struct inode inp;
	int success = inode_iget(fs, dirinumber, &inp);
	// Return -1 on error
	if (success == -1){
		return -1;
	}
	// The dirinumber does not match to a directory
	if ((inp.i_mode & IFMT) != IFDIR) {
		return -1;
	}
	// The size of the directory
	int size = inode_getsize(&inp);
	
	// Total number of dirent's
	int numDirEnts = size/ sizeof(struct direntv6);
	
	// The number of dirEnt's in one block
	int numDirEntsInBlock = DISKIMG_SECTOR_SIZE / sizeof(struct direntv6);
	
	// The number of blocks the struct consistst of
	int numBlocks = numDirEnts / numDirEntsInBlock;
	// If the number of dirEnts don't fully occupy a block, add one
	if(numDirEnts % numDirEntsInBlock !=0) numBlocks +=1;
	
	
	// Look through all of the blocks in the inode
	for(int block = 0; block < numBlocks; block++){
		
		// Create a buffer
		struct direntv6 dirEntTable[numDirEntsInBlock];
		// Had &dirEntTable
		success = file_getblock(fs,dirinumber,block,dirEntTable);
		
		// Check for error
		if (success < 0){
			return -1;
		}
		
		// Look over all of the dirEnt's in a block
		for(int d = 0; d < numDirEntsInBlock; d++){
			
			struct direntv6 dir = dirEntTable[d];
			
			// See if the strings match	
			if(strcmp(name,dir.d_name) == 0){
				
				// Copy the dir into dirEnt and return
				memcpy(dirEnt,&dir,sizeof(struct direntv6));
				return 0;
			}
			
		}
	}
	// return -1 on no match
	return -1;
}
Esempio n. 19
0
/*
 * Output to the specified file the checksum of the specified pathname and
 * inode as well as all its children if it is a directory.
 *
 * This is used by the grading script, so be careful not to change its output
 * format.
 */
void
DumpPathAndChildren(struct unixfilesystem *fs, const char *pathname, int inumber, FILE *f)
{
  struct inode in;
  if (inode_iget(fs, inumber, &in) < 0) {
    fprintf(stderr,"Can't read inode %d \n", inumber);
    return;
  }
  assert(in.i_mode & IALLOC);

  char chksum1[CHKSUMFILE_SIZE];
  if (chksumfile_byinumber(fs, inumber, chksum1) < 0) {
    fprintf(stderr,"Can't checksum inode %d path %s\n", inumber, pathname);
    return;
  }

  char chksum2[CHKSUMFILE_SIZE];
  if (chksumfile_bypathname(fs, pathname, chksum2) < 0) {
    fprintf(stderr,"Can't checksum inode %d path %s\n", inumber, pathname);
    return;
  }

  if (!chksumfile_compare(chksum1, chksum2)) {
    fprintf(stderr,"Pathname checksum of %s differs from inode %d\n", pathname, inumber);
    return;
  }

  char chksumstring[CHKSUMFILE_STRINGSIZE];
  chksumfile_cvt2string(chksum2, chksumstring);
  int size = inode_getsize(&in);
  fprintf(f, "Path %s %d mode 0x%x size %d checksum %s\n",pathname,inumber,in.i_mode, size, chksumstring);

  if (pathname[1] == 0) {
    /* pathame == "/" */
    pathname++; /* Delete extra / character */
  }

  if ((in.i_mode & IFMT) == IFDIR) { 
      const unsigned int MAXPATH = 1024;

      if (strlen(pathname) > MAXPATH-16) {
        fprintf(stderr, "Too deep of directories %s\n", pathname);
      }

      struct direntv6 direntries[10000];
      int numentries = GetDirEntries(fs, inumber, direntries, 10000);

      for (int i = 0; i < numentries; i++) {
        char *n;
        n =  direntries[i].d_name;
        if (n[0] == '.') {
          if ((n[1] == 0) || ((n[1] == '.') && (n[2] == 0))) {
            /* Skip over "." and ".." */
            continue;
          }
        }

        char nextpath[MAXPATH];
        sprintf(nextpath, "%s/%s",pathname, direntries[i].d_name);
        DumpPathAndChildren(fs, nextpath,  direntries[i].d_inumber, f);
      }
  }
}
/*
 * add one entry to the directory initialized by entry name
 * detail impletation is read the last block of the directory and add the item.
 * it is kind of troublesome to consider the block shortage problem and others
 */
int directory_addItem(struct unixfilesystem *fs, const char *entryName,
                      int dirinumber, int FileType)
{
    struct inode dirIn;
    int err = inode_iget(fs, dirinumber, &dirIn);
    if (err < 0) {
        fprintf(stderr, "directory_addItem get dir inode failed\n");
        return -1;
    }
    if (!(dirIn.i_mode & IALLOC) || ((dirIn.i_mode & IFMT) != IFDIR)) {
        fprintf(stderr, "directory_addItem dir inode is not DIR or ALLOCATED");
        return -1;
    }
    /* 
     * inode_size % DISKIMG_SECTOR_SIZE == 0 
     * means no space left in inode, so we need alloc a new block
     */ 
    int inode_size = inode_getsize(&dirIn);
    if (inode_size % DISKIMG_SECTOR_SIZE == 0) 
    {
        err = filsys_allocBlocks(fs, &dirIn, 1);
        if (err < 0) {
            fprintf(stderr, "directory_addItem can't apply new blocks and inode_size = %d\n",inode_size);
        }
    }
    /* increase dir's inode_size first to make the file_getblock works legal */
    inode_setsize(&dirIn, inode_size +  sizeof(struct direntv6)); 
    inode_iwrite(fs, dirinumber, &dirIn); /* Save dir's inode_size first */
    
    /* Read the last item of directory, change and write it back
       because we handle the overflow problem in above code, so 
       just do the normal routine */ 
    char buf[DISKIMG_SECTOR_SIZE]; 
    {
        /* 
           Read Last block of directory, because inode_size has increased before,
           now the inode_size is the old one, but easy to compute if inode_size % DISKIMG_SECTOR_SIZE == 0 
           then inode_lastBlockNum = new allocated blockNum.
        */
        int inode_lastBlockNum = inode_size / DISKIMG_SECTOR_SIZE;
        
        struct direntv6 *dirEnt = (struct direntv6 *)buf;
        
        //printf("directory i_mode = %d %d\n", in.i_mode, dirinumber);
        file_getblock(fs, dirinumber, inode_lastBlockNum, buf); // last block is inode_BlockNum
        
        /* locate the entry id */
        int dirEnt_last = (inode_size % DISKIMG_SECTOR_SIZE) / sizeof(struct direntv6);
        
        strcpy(dirEnt[dirEnt_last].d_name, entryName);     // copy name
        int inumber_new = filsys_allocInode(fs);      // allocate an new inode and copy to dirEnt.
        if (inumber_new < 0) {
            fprintf(stderr, "directory_addItem can't apply new Inode");
        }
        dirEnt[dirEnt_last].d_inumber = inumber_new;
        
        //printf("new allocated inumber = %d , entryName = %s, dir_bno = %d\n", inumber_new, entryName, inode_lastBlockNum);
        
        /* initialize new inode and save */
        struct inode in_new;
        inode_iget(fs, inumber_new, &in_new);
        inode_format(&in_new); 
        in_new.i_mode |= FileType; // set inode mode.
        inode_iwrite(fs, inumber_new, &in_new); // save new allocated inode
        
        /* write buf back to the block */
        file_writeblock(fs, dirinumber, inode_lastBlockNum, buf);
    }
    inode_iwrite(fs, dirinumber, &dirIn); /* Save dir's inode */
    return 0;
}