static ospfs_direntry_t * create_blank_direntry(ospfs_inode_t *dir_oi) { // Outline: // 1. Check the existing directory data for an empty entry. Return one // if you find it. // 2. If there's no empty entries, add a block to the directory. // Use ERR_PTR if this fails; otherwise, clear out all the directory // entries and return one of them. ospfs_direntry_t *dir_entry; int retval; // look for empty entry uint32_t offset; for (offset = 0; offset < dir_oi->oi_size; offset += OSPFS_DIRENTRY_SIZE) { dir_entry = ospfs_inode_data(dir_oi, offset); if (dir_entry->od_ino == 0) return dir_entry; } // no empty entry, add block (will be added at offset = current oi_size) retval = add_block(dir_oi); if (retval < 0) return ERR_PTR(retval); dir_entry = ospfs_inode_data(dir_oi, offset); return dir_entry; }
static ospfs_direntry_t * create_blank_direntry(ospfs_inode_t *dir_oi) { // Outline: // 1. Check the existing directory data for an empty entry. Return one // if you find it. // 2. If there's no empty entries, add a block to the directory. // Use ERR_PTR if this fails; otherwise, clear out all the directory // entries and return one of them. // not a directory if (dir_oi->oi_ftype != OSPFS_FTYPE_DIR) return ERR_PTR(-EINVAL); // check existing directory for empty entry int k; for (k = 0; k < dir_oi->oi_size; k += OSPFS_DIRENTRY_SIZE) { ospfs_direntry_t* od = ospfs_inode_data(dir_oi, k); // entry is empty if (od->od_ino == 0) { return od; } } // no empty entry exists // add new entry int r = add_block(dir_oi); if (r) return ERR_PTR(r); return ospfs_inode_data(dir_oi, dir_oi->oi_size - OSPFS_BLKSIZE); /* DONE: Your code here. */ }
static ospfs_direntry_t * create_blank_direntry(ospfs_inode_t *dir_oi) { // Outline: // 1. Check the existing directory data for an empty entry. Return one // if you find it. // 2. If there's no empty entries, add a block to the directory. // Use ERR_PTR if this fails; otherwise, clear out all the directory // entries and return one of them. /* EXERCISE: Your code here. */ //return ERR_PTR(-EINVAL); // Replace this line //Part 1: //Iterate through directory data and find empty entry uint32_t i = 0; ospfs_direntry_t *tmp; uint32_t num_entries = dir_oi->oi_size; for (i = 0; i < num_entries; i+= OSPFS_DIRENTRY_SIZE) { tmp = ospfs_inode_data(dir_oi, i); if (tmp->od_ino == 0) return tmp; } int blankdir = change_size(dir_oi, dir_oi->oi_size+OSPFS_DIRENTRY_SIZE); if (blankdir == 0) { tmp = ospfs_inode_data(dir_oi, num_entries); return tmp; } return ERR_PTR(blankdir); }
static ospfs_direntry_t * create_blank_direntry(ospfs_inode_t *dir_oi) { // Outline: // 1. Check the existing directory data for an empty entry. Return one // if you find it. // 2. If there's no empty entries, add a block to the directory. // Use ERR_PTR if this fails; otherwise, clear out all the directory // entries and return one of them. /* EXERCISE: Your code here. */ int f_pos = 0; int r; //Search for empty directory for(; f_pos < dir_oi->oi_size; f_pos+= OSPFS_DIRENTRY_SIZE){ ospfs_direntry_t *od = ospfs_inode_data(dir_oi, f_pos); if(od->od_ino == 0){ return od; } } //No empty directories found, so add a new block r = change_size(dir_oi, dir_oi->oi_size + OSPFS_BLKSIZE); //Check for error if(r < 0){ return ERR_PTR(r); } //Don't know if this is right, get the pos of the newly added block return ospfs_inode_data(dir_oi, f_pos); }
static ospfs_direntry_t * create_blank_direntry(ospfs_inode_t *dir_oi) { // Outline: // 1. Check the existing directory data for an empty entry. Return one // if you find it. // 2. If there's no empty entries, add a block to the directory. // Use ERR_PTR if this fails; otherwise, clear out all the directory // entries and return one of them. /* EXERCISE: Your code here. */ int i; int error; ospfs_direntry_t *entry = NULL; for(i = 0; i < dir_oi->oi_size; i += OSPFS_DIRENTRY_SIZE) { entry = ospfs_inode_data(dir_oi, i); if(entry->od_ino == 0) { return entry; } } error = add_block(dir_oi); if (error != 0) { return ERR_PTR(error); } entry = ospfs_inode_data(dir_oi, i); entry->od_ino = 0; entry->od_name[0] = 0; return entry; }
static int ospfs_unlink(struct inode *dirino, struct dentry *dentry) { ospfs_inode_t *oi = ospfs_inode(dentry->d_inode->i_ino); ospfs_inode_t *dir_oi = ospfs_inode(dentry->d_parent->d_inode->i_ino); int entry_off; ospfs_direntry_t *od; od = NULL; // silence compiler warning; entry_off indicates when !od for (entry_off = 0; entry_off < dir_oi->oi_size; entry_off += OSPFS_DIRENTRY_SIZE) { od = ospfs_inode_data(dir_oi, entry_off); if (od->od_ino > 0 && strlen(od->od_name) == dentry->d_name.len && memcmp(od->od_name, dentry->d_name.name, dentry->d_name.len) == 0) break; } if (entry_off == dir_oi->oi_size) { printk("<1>ospfs_unlink should not fail!\n"); return -ENOENT; } od->od_ino = 0; oi->oi_nlink--; //after unlinking, decrement number of links dir_oi->oi_nlink--; //if a file doesn't have any more links, we can delete it by giving it 0 size if (oi->oi_ftype != OSPFS_FTYPE_SYMLINK && oi->oi_nlink == 0) change_size(oi,0); return 0; }
static ospfs_direntry_t * create_blank_direntry(ospfs_inode_t *dir_oi) { uint32_t blockno; uint32_t off = 1; int ret; uint32_t entry_off; // Outline: // 1. Check the existing directory data for an empty entry. Return one // if you find it. // 2. If there's no empty entries, add a block to the directory. // Use ERR_PTR if this fails; otherwise, clear out all the directory // entries and return one of them. /* EXERCISE: Your code here. */ // Search through the directory block for (entry_off = 0; entry_off < dir_oi->oi_size; entry_off += OSPFS_DIRENTRY_SIZE) { // Find the OSPFS inode for the entry ospfs_direntry_t *od = ospfs_inode_data(dir_oi, entry_off); // Set 'entry_inode' if we find the file we are looking for if (od->od_ino == 0) { return od; } } if ((ret = change_size(dir_oi, dir_oi->oi_size + OSPFS_DIRENTRY_SIZE))) { return NULL; } return create_blank_direntry(dir_oi); }
static int ospfs_unlink(uint32_t i_ino, char *d_name) { ospfs_inode_t *oi = ospfs_inode(i_ino); // figure this out??? ospfs_inode_t *dir_oi = ospfs_inode(i_ino); int entry_off; ospfs_direntry_t *od; od = NULL; // silence compiler warning; entry_off indicates when !od for (entry_off = 0; entry_off < dir_oi->oi_size; entry_off += OSPFS_DIRENTRY_SIZE) { od = ospfs_inode_data(dir_oi, entry_off); if (od->od_ino > 0 && strlen(od->od_name) == strlen(d_name) && memcmp(od->od_name, d_name, strlen(d_name)) == 0) break; } if (entry_off == dir_oi->oi_size) { return -ENOENT; } od->od_ino = 0; oi->oi_nlink--; return 0; }
int ospfs_dir_readdir(uint32_t i_ino, int *pos, ospfs_direntry_t **_od) { ospfs_inode_t *dir_oi = ospfs_inode(i_ino); uint32_t f_pos = *pos; int r = -1; int entry_off; entry_off = f_pos * OSPFS_DIRENTRY_SIZE; if (f_pos >= 0 && entry_off < dir_oi->oi_size) { ospfs_direntry_t *od = ospfs_inode_data(dir_oi, entry_off); ospfs_inode_t *oi; /* If at the end of the directory, set 'r' to 1 and exit * the loop. For now we do this all the time. */ if (od->od_ino <= 0) { r = -1; *_od = NULL; } else { r = 0; f_pos++; *_od = od; } } // Save the file position and return! *pos = f_pos; return r; }
static int ospfs_unlink(struct inode *dirino, struct dentry *dentry) { ospfs_inode_t *oi = ospfs_inode(dentry->d_inode->i_ino); ospfs_inode_t *dir_oi = ospfs_inode(dentry->d_parent->d_inode->i_ino); int entry_off; ospfs_direntry_t *od; od = NULL; // silence compiler warning; entry_off indicates when !od for (entry_off = 0; entry_off < dir_oi->oi_size; entry_off += OSPFS_DIRENTRY_SIZE) { od = ospfs_inode_data(dir_oi, entry_off); if (od->od_ino > 0 && strlen(od->od_name) == dentry->d_name.len && memcmp(od->od_name, dentry->d_name.name, dentry->d_name.len) == 0) break; } if (entry_off == dir_oi->oi_size) { printk("<1>ospfs_unlink should not fail!\n"); return -ENOENT; } od->od_ino = 0; oi->oi_nlink--; // if not a symlink, delete file data when all links are gone if (oi->oi_ftype != OSPFS_FTYPE_SYMLINK && oi->oi_nlink == 0) return change_size(oi, 0); return 0; }
static ospfs_direntry_t * create_blank_direntry(ospfs_inode_t *dir_oi) { // Outline: // 1. Check the existing directory data for an empty entry. Return one // if you find it. // 2. If there's no empty entries, add a block to the directory. // Use ERR_PTR if this fails; otherwise, clear out all the directory // entries and return one of them. /* EXERCISE: Your code here. */ int off; for (off = 0; off < dir_oi->oi_size; off += OSPFS_DIRENTRY_SIZE) { ospfs_direntry_t *od = ospfs_inode_data(dir_oi, off); if (od->od_ino == 0) return od; } if (add_block(dir_oi) == -ENOSPC) return ERR_PTR(-EINVAL); return ospfs_inode_data(dir_oi, off); }
static ospfs_direntry_t * find_direntry(ospfs_inode_t *dir_oi, const char *name, int namelen) { int off; if (namelen < 0) namelen = strlen(name); for (off = 0; off < dir_oi->oi_size; off += OSPFS_DIRENTRY_SIZE) { ospfs_direntry_t *od = ospfs_inode_data(dir_oi, off); if (od->od_ino && strlen(od->od_name) == namelen && memcmp(od->od_name, name, namelen) == 0) return od; } return 0; }
static ospfs_direntry_t * create_blank_direntry(ospfs_inode_t *dir_oi) { // Outline: // 1. Check the existing directory data for an empty entry. Return one // if you find it. // 2. If there's no empty entries, add a block to the directory. // Use ERR_PTR if this fails; otherwise, clear out all the directory // entries and return one of them. /* EXERCISE: Your code here. */ //return ERR_PTR(-EINVAL); // Replace this line ospfs_direntry_t* dentry; int offset; for (offset = 0; (offset*OSPFS_DIRENTRY_SIZE)<dir_oi->oi_size; offset++) { //ospfs_inode_data(oi, offset) dentry = ospfs_inode_data(dir_oi, offset*OSPFS_DIRENTRY_SIZE); if (dentry->od_ino == 0) return dentry; else continue; } //no empty entries, add a block to the directory. int retval; //add_block(ospfs_inode_t *oi) retval = add_block (dir_oi); if (retval<0) return ERR_PTR(retval); else //add block success { dentry = ospfs_inode_data(dir_oi, offset*OSPFS_DIRENTRY_SIZE); //the new block entry; return dentry; } }
static struct dentry * ospfs_dir_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *ignore) { // Find the OSPFS inode corresponding to 'dir' ospfs_inode_t *dir_oi = ospfs_inode(dir->i_ino); struct inode *entry_inode = NULL; int entry_off; // Make sure filename is not too long if (dentry->d_name.len > OSPFS_MAXNAMELEN) return (struct dentry *) ERR_PTR(-ENAMETOOLONG); // Mark with our operations dentry->d_op = &ospfs_dentry_ops; // Search through the directory block for (entry_off = 0; entry_off < dir_oi->oi_size; entry_off += OSPFS_DIRENTRY_SIZE) { // Find the OSPFS inode for the entry ospfs_direntry_t *od = ospfs_inode_data(dir_oi, entry_off); // Set 'entry_inode' if we find the file we are looking for if (od->od_ino > 0 && strlen(od->od_name) == dentry->d_name.len && memcmp(od->od_name, dentry->d_name.name, dentry->d_name.len) == 0) { entry_inode = ospfs_mk_linux_inode(dir->i_sb, od->od_ino); if (!entry_inode) return (struct dentry *) ERR_PTR(-EINVAL); break; } } // We return a dentry whether or not the file existed. // The file exists if and only if 'entry_inode != NULL'. // If the file doesn't exist, the dentry is called a "negative dentry". // d_splice_alias() attaches the inode to the dentry. // If it returns a new dentry, we need to set its operations. if ((dentry = d_splice_alias(entry_inode, dentry))) dentry->d_op = &ospfs_dentry_ops; return dentry; }
static int ospfs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir) { struct inode *dir_inode = filp->f_dentry->d_inode; ospfs_inode_t *dir_oi = ospfs_inode(dir_inode->i_ino); uint32_t f_pos = filp->f_pos; int r = 0; /* Error return value, if any */ int ok_so_far = 0; /* Return value from 'filldir' */ // f_pos is an offset into the directory's data, plus two. // The "plus two" is to account for "." and "..". if (r == 0 && f_pos == 0) { ok_so_far = filldir(dirent, ".", 1, f_pos, dir_inode->i_ino, DT_DIR); if (ok_so_far >= 0) f_pos++; } if (r == 0 && ok_so_far >= 0 && f_pos == 1) { ok_so_far = filldir(dirent, "..", 2, f_pos, filp->f_dentry->d_parent->d_inode->i_ino, DT_DIR); if (ok_so_far >= 0) f_pos++; } // actual entries while (r == 0 && ok_so_far >= 0 && f_pos >= 2) { /* If at the end of the directory, set 'r' to 1 and exit * the loop. For now we do this all the time. * */ /* EXERCISE: Your code here */ // bounds checking if(((f_pos-2)*OSPFS_DIRENTRY_SIZE >= dir_oi->oi_size)) { r = 1; /* Fix me! */ break; /* Fix me! */ } /* Get a pointer to the next entry (od) in the directory. * The file system interprets the contents of a * directory-file as a sequence of ospfs_direntry structures. * You will find 'f_pos' and 'ospfs_inode_data' useful. * * Then use the fields of that file to fill in the directory * entry. To figure out whether a file is a regular file or * another directory, use 'ospfs_inode' to get the directory * entry's corresponding inode, and check out its 'oi_ftype' * member. * * Make sure you ignore blank directory entries! (Which have * an inode number of 0.) * * If the current entry is successfully read (the call to * filldir returns >= 0), or the current entry is skipped, * your function should advance f_pos by the proper amount to * advance to the next directory entry. */ /* EXERCISE: Your code here */ ospfs_direntry_t *od = ospfs_inode_data(dir_oi,(f_pos-2)*OSPFS_DIRENTRY_SIZE); // ignore and advance if(od->od_ino == 0) { f_pos++; continue; } ospfs_inode_t *entry_oi = ospfs_inode(od->od_ino); // call filldir based on type if(entry_oi->oi_ftype == OSPFS_FTYPE_REG) { ok_so_far = filldir(dirent, od->od_name, strlen(od->od_name), f_pos, od->od_ino, DT_LNK); } else if(entry_oi->oi_ftype == OSPFS_FTYPE_DIR) { ok_so_far = filldir(dirent, od->od_name, strlen(od->od_name), f_pos, od->od_ino, DT_LNK); } else if(entry_oi->oi_ftype == OSPFS_FTYPE_SYMLINK) { ok_so_far = filldir(dirent, od->od_name, strlen(od->od_name), f_pos, od->od_ino, DT_LNK); } else return -EFAULT; // ok so keep going if (ok_so_far >= 0) f_pos++; } // Save the file position and return! filp->f_pos = f_pos; return r; }
static int ospfs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir) { struct inode *dir_inode = filp->f_dentry->d_inode; ospfs_inode_t *dir_oi = ospfs_inode(dir_inode->i_ino); uint32_t f_pos = filp->f_pos; int r = 0; /* Error return value, if any */ int ok_so_far = 0; /* Return value from 'filldir' */ // f_pos is an offset into the directory's data, plus two. // The "plus two" is to account for "." and "..". if (r == 0 && f_pos == 0) { ok_so_far = filldir(dirent, ".", 1, f_pos, dir_inode->i_ino, DT_DIR); if (ok_so_far >= 0) f_pos++; } if (r == 0 && ok_so_far >= 0 && f_pos == 1) { ok_so_far = filldir(dirent, "..", 2, f_pos, filp->f_dentry->d_parent->d_inode->i_ino, DT_DIR); if (ok_so_far >= 0) f_pos++; } // actual entries while (r == 0 && ok_so_far >= 0 && f_pos >= 2) { ospfs_direntry_t *od; ospfs_inode_t *entry_oi; /* If at the end of the directory, set 'r' to 1 and exit * the loop. For now we do this all the time. */ if (f_pos > dir_oi->oi_size * OSPFS_DIRENTRY_SIZE) { /* TODO: error cond */ r = 1; break; } /* Get a pointer to the next entry (od) in the directory. * The file system interprets the contents of a * directory-file as a sequence of ospfs_direntry structures. * You will find 'f_pos' and 'ospfs_inode_data' useful. * * Then use the fields of that file to fill in the directory * entry. To figure out whether a file is a regular file or * another directory, use 'ospfs_inode' to get the directory * entry's corresponding inode, and check out its 'oi_ftype' * member. * * Make sure you ignore blank directory entries! (Which have * an inode number of 0.) * * If the current entry is successfully read (the call to * filldir returns >= 0), or the current entry is skipped, * your function should advance f_pos by the proper amount to * advance to the next directory entry. */ // get inode od = ospfs_inode_data(dir_oi, f_pos * OSPFS_DIRENTRY_SIZE); entry_oi = ospfs_inode(od->od_ino); // ignore blank directory entries if(entry_oi != 0) { // determine filetype switch(entry_oi->oi_ftype) { case OSPFS_FTYPE_REG: ok_so_far = filldir(dirent, od->od_name, strlen(od->od_name), f_pos, od->od_ino, DT_REG); break; case OSPFS_FTYPE_DIR: ok_so_far = filldir(dirent, od->od_name, strlen(od->od_name), f_pos, od->od_ino, DT_DIR); break; case OSPFS_FTYPE_SYMLINK: ok_so_far = filldir(dirent, od->od_name, strlen(od->od_name), f_pos, od->od_ino, DT_LNK); break; default: eprintk("Mystery error!\n"); r=1; continue; } } f_pos++; } // Save the file position and return! filp->f_pos = f_pos; return r; }
static int ospfs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir) { struct inode *dir_inode = filp->f_dentry->d_inode; ospfs_inode_t *dir_oi = ospfs_inode(dir_inode->i_ino); uint32_t f_pos = filp->f_pos; int r = 0; /* Error return value, if any */ int ok_so_far = 0; /* Return value from 'filldir' */ // f_pos is an offset into the directory's data, plus two. // The "plus two" is to account for "." and "..". if (r == 0 && f_pos == 0) { ok_so_far = filldir(dirent, ".", 1, f_pos, dir_inode->i_ino, DT_DIR); if (ok_so_far >= 0) f_pos++; } if (r == 0 && ok_so_far >= 0 && f_pos == 1) { ok_so_far = filldir(dirent, "..", 2, f_pos, filp->f_dentry->d_parent->d_inode->i_ino, DT_DIR); if (ok_so_far >= 0) f_pos++; } // actual entries while (r == 0 && ok_so_far >= 0 && f_pos >= 2) { ospfs_direntry_t *od; ospfs_inode_t *entry_oi; /* If at the end of the directory, set 'r' to 1 and exit * the loop. For now we do this all the time. * * EXERCISE: Your code here */ //r = 1; /* Fix me! */ //break; /* Fix me! */ //If we found the end, set r to 1 and break //how to find end? //dir_oi pulls up inode struct for our file //we then pull up its property oi_size which gives us file size //then we have to multiply file size by size of each entry //when f_pos gets past that, we know we've hit the end if (f_pos >= dir_oi->oi_size * OSPFS_DIRENTRY_SIZE) { r = 1; break; } /* Get a pointer to the next entry (od) in the directory. * The file system interprets the contents of a * directory-file as a sequence of ospfs_direntry structures. * You will find 'f_pos' and 'ospfs_inode_data' useful. * * Then use the fields of that file to fill in the directory * entry. To figure out whether a file is a regular file or * another directory, use 'ospfs_inode' to get the directory * entry's corresponding inode, and check out its 'oi_ftype' * member. * * Make sure you ignore blank directory entries! (Which have * an inode number of 0.) * * If the current entry is successfully read (the call to * filldir returns >= 0), or the current entry is skipped, * your function should advance f_pos by the proper amount to * advance to the next directory entry. */ /* EXERCISE: Your code here */ //get pointer to nex entry -> put in od //offset for ospfs_inode_data = (f_pos - 2) * size of each entry od = ospfs_inode_data(dir_oi, (f_pos-2)*OSPFS_DIRENTRY_SIZE); entry_oi = ospfs_inode(od->od_ino); //if od's ino = 0 or entry is null, increment f_pos if (od->od_ino == 0 || entry_oi == NULL) { f_pos++; } int ftype; if (r == 0 && ok_so_far >= 0) { switch(entry_oi->oi_ftype) { case OSPFS_FTYPE_DIR: { ftype = DT_DIR; break; } case OSPFS_FTYPE_REG: { ftype = DT_REG; break; } case OSPFS_FTYPE_SYMLINK: { ftype = DT_LNK; break; } } ok_so_far = filldir(dirent, od->od_name, strlen(od->od_name), f_pos, od->od_ino, ftype); } if (ok_so_far >= 0) f_pos++; } // Save the file position and return! filp->f_pos = f_pos; return r; }
static int ospfs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir) { struct inode *dir_inode = filp->f_dentry->d_inode; ospfs_inode_t *dir_oi = ospfs_inode(dir_inode->i_ino); uint32_t f_pos = filp->f_pos; int r = 0; /* Error return value, if any */ int ok_so_far = 0; /* Return value from 'filldir' */ // f_pos is an offset into the directory's data, plus two. // The "plus two" is to account for "." and "..". if (r == 0 && f_pos == 0) { ok_so_far = filldir(dirent, ".", 1, f_pos, dir_inode->i_ino, DT_DIR); if (ok_so_far >= 0) f_pos++; } if (r == 0 && ok_so_far >= 0 && f_pos == 1) { ok_so_far = filldir(dirent, "..", 2, f_pos, filp->f_dentry->d_parent->d_inode->i_ino, DT_DIR); if (ok_so_far >= 0) f_pos++; } /* EXERCISE: Your code here */ // actual entries while (r == 0 && ok_so_far >= 0 && f_pos >= 2 && f_pos < dir_oi->oi_size) { ospfs_direntry_t *od = ospfs_inode_data(dir_oi, f_pos-2); ospfs_inode_t *entry_oi = ospfs_inode(od->od_ino); //Skip entry if inode number is 0 if(od->od_ino > 0 && entry_oi && entry_oi->oi_nlink > 0){ //eprintk("inode: %d, name:%s\n", od->od_ino, od->od_name); switch(entry_oi->oi_ftype){ case OSPFS_FTYPE_REG: ok_so_far = filldir(dirent, od->od_name, strlen(od->od_name), f_pos, od->od_ino, DT_REG); break; case OSPFS_FTYPE_DIR: ok_so_far = filldir(dirent, od->od_name, strlen(od->od_name), f_pos, od->od_ino, DT_DIR); break; case OSPFS_FTYPE_SYMLINK: ok_so_far = filldir(dirent, od->od_name, strlen(od->od_name), f_pos, od->od_ino, DT_LNK); break; default: r = 0; continue; } //If error on filldir exit while loop and return 0 if(ok_so_far < 0){ return 0; } } //Advance f_pos by dir entry size, if at the end of the directory, set 'r' to 1 and exit f_pos += sizeof(OSPFS_DIRENTRY_SIZE); if(f_pos-2 >= dir_oi->oi_size){ r = 1; } } // Save the file position and return! filp->f_pos = f_pos; return r; }