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 int ospfs_link(struct dentry *src_dentry, struct inode *dir, struct dentry *dst_dentry) { ospfs_inode_t *dir_oi = ospfs_inode(dir->i_ino); ospfs_inode_t *src_oi = ospfs_inode(src_dentry->d_inode->i_ino); ospfs_direntry_t *entry; if (dst_dentry->d_name.len > OSPFS_MAXSYMLINKLEN) { return -ENAMETOOLONG; } if (find_direntry(dir_oi, dst_dentry->d_name.name, dst_dentry->d_name.len) != NULL) { return -EEXIST; } if (dir_oi == NULL || dir_oi->oi_nlink + 1 == 0) { return -EIO; } entry = create_blank_direntry(dir_oi); if (IS_ERR(entry)) { return PTR_ERR(entry); } else if(entry == NULL) { return -EIO; } entry->od_ino = src_dentry->d_inode->i_ino; memcpy(entry->od_name, dst_dentry->d_name.name, dst_dentry->d_name.len); entry->od_name[dst_dentry->d_name.len] = 0; src_oi->oi_nlink++; dir_oi->oi_nlink++; return 0; }
int32_t copy_inode(uint32_t i_ino, uint8_t *bitmap, ospfs_inode_t *inodeTable) { memcpy(&inodeTable[i_ino], ospfs_inode(i_ino), sizeof(*inodeTable)); mark_inode_bitmap(ospfs_inode(i_ino), bitmap); }
static int ospfs_link(struct dentry *src_dentry, struct inode *dir, struct dentry *dst_dentry) { ospfs_direntry_t* link; // check if name too long if (dst_dentry->d_name.len > OSPFS_MAXNAMELEN) return -ENAMETOOLONG; // check if directory entry already exists if (find_direntry(ospfs_inode(dir->i_ino), dst_dentry->d_name.name, dst_dentry->d_name.len)) return -EEXIST; // create new hardlinked file link = create_blank_direntry(ospfs_inode(dir->i_ino)); if (IS_ERR(link)) return PTR_ERR(link); // copy file information link->od_ino = src_dentry->d_inode->i_ino; memcpy(link->od_name, dst_dentry->d_name.name, dst_dentry->d_name.len); link->od_name[dst_dentry->d_name.len] = '\0'; // increment source file link count ospfs_inode(src_dentry->d_inode->i_ino)->oi_nlink++; return 0; }
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; }
static int ospfs_link(struct dentry *src_dentry, struct inode *dir, struct dentry *dst_dentry) { /* EXERCISE: Your code here. */ ospfs_inode_t *dir_oi = ospfs_inode(dir->i_ino); ospfs_direntry_t *od; ospfs_inode_t *oi; uint32_t entry_ino = 0; if (dst_dentry->d_name.len > OSPFS_MAXNAMELEN) return -ENAMETOOLONG; if (find_direntry(dir_oi, dst_dentry->d_name.name, dst_dentry->d_name.len)) return -EEXIST; od = create_blank_direntry(dir_oi); if (IS_ERR(od)) return -ENOSPC; for (entry_ino = 2; entry_ino < ospfs_super->os_ninodes; entry_ino++) { oi = ospfs_inode(entry_ino); if (oi->oi_nlink == 0) break; } if (entry_ino == ospfs_super->os_ninodes) return -EIO; od->od_ino = src_dentry->d_inode->i_ino; strcpy(od->od_name, dst_dentry->d_name.name); oi = ospfs_inode(od->od_ino); oi->oi_nlink++; return 0; }
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 int ospfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) { ospfs_inode_t *dir_oi = ospfs_inode(dir->i_ino); uint32_t entry_ino = 0; ospfs_symlink_inode_t *symlink_inode; if (find_direntry(dir_oi, dentry->d_name.name, dentry->d_name.len)) return -EEXIST; if (strlen(symname) > OSPFS_MAXSYMLINKLEN || dentry->d_name.len > OSPFS_MAXNAMELEN) return -ENAMETOOLONG; // create a blank direntry, and return error if bad things happen ospfs_direntry_t* od = create_blank_direntry(dir_oi); if (IS_ERR(od)) { return PTR_ERR(od); } // find empty inode by linear searching the inodes for (entry_ino = 0; entry_ino < ospfs_super->os_ninodes; entry_ino++) { if (!ospfs_inode(entry_ino)->oi_nlink) break; } // entry_ino is now either a ptr to an empty inode we can use or ninodes (no space) if (entry_ino == ospfs_super->os_ninodes) return -ENOSPC; // write directory entry (inode number and the name) od->od_ino = entry_ino; memcpy(od->od_name, dentry->d_name.name, dentry->d_name.len); od->od_name[dentry->d_name.len] = '\0'; symlink_inode = ospfs_inode(entry_ino); // set values in inode symlink_inode->oi_nlink = 1; symlink_inode->oi_size = strlen(symname); symlink_inode->oi_ftype = OSPFS_FTYPE_SYMLINK; memcpy(symlink_inode->oi_symlink, symname, strlen(symname)); symlink_inode->oi_symlink[strlen(symname)] = '\0'; /* Execute this code after your function has successfully created the file. Set entry_ino to the created file's inode number before getting here. */ { struct inode *i = ospfs_mk_linux_inode(dir->i_sb, entry_ino); if (!i) return -ENOMEM; d_instantiate(dentry, i); return 0; } }
static int ospfs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd) { ospfs_inode_t *dir_oi = ospfs_inode(dir->i_ino); uint32_t entry_ino = 0; // if the entry is found, it already exists if (find_direntry(dir, dentry->d_name.name, dentry->d_name.len)) return -EEXIST; // if entry name is too long if (dentry->d_name.len > OSPFS_MAXNAMELEN) return -ENAMETOOLONG; // create a blank direntry, and return error if bad things happen ospfs_direntry_t* od = create_blank_direntry(dir_oi); if (IS_ERR(od)) { return PTR_ERR(od); } // find empty inode by linear searching the inodes for (entry_ino = 0; entry_ino < ospfs_super->os_ninodes; entry_ino++) { if (!ospfs_inode(entry_ino)->oi_nlink) break; } // entry_ino is now either a ptr to an empty inode we can use or ninodes (no space) if (entry_ino == ospfs_super->os_ninodes) return -ENOSPC; od->od_ino = entry_ino; memcpy(od->od_name, dentry->d_name.name, dentry->d_name.len); od->od_name[dentry->d_name.len] = '\0'; ospfs_inode_t* inode = ospfs_inode(entry_ino); // set values in inode inode->oi_mode = mode; inode->oi_nlink = 1; inode->oi_size = 0; inode->oi_ftype = OSPFS_FTYPE_REG; memset(inode->oi_direct, 0, sizeof(inode->oi_direct[0]) * OSPFS_NDIRECT); inode->oi_indirect = 0; inode->oi_indirect2 = 0; /* Execute this code after your function has successfully created the file. Set entry_ino to the created file's inode number before getting here. */ { struct inode *i = ospfs_mk_linux_inode(dir->i_sb, entry_ino); if (!i) return -ENOMEM; d_instantiate(dentry, i); return 0; } }
static int ospfs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd) { ospfs_inode_t *dir_oi = ospfs_inode(dir->i_ino); uint32_t entry_ino = 0; ospfs_direntry_t *entry = NULL; ospfs_inode_t *temp = NULL; /* EXERCISE: Your code here. */ if (dentry->d_name.len > OSPFS_MAXNAMELEN) { return -ENAMETOOLONG; } if (find_direntry(ospfs_inode(dir->i_ino), dentry->d_name.name, dentry->d_name.len) != NULL) { return -EEXIST; } entry = create_blank_direntry(dir_oi); if (IS_ERR(entry)) { return PTR_ERR(entry); } while(entry_ino < ospfs_super->os_ninodes) { temp = ospfs_inode(entry_ino); if(temp != NULL && temp->oi_nlink == 0) { break; } entry_ino++; } if (entry_ino == ospfs_super->os_ninodes) { return -ENOSPC; } temp->oi_size = 0; temp->oi_ftype = OSPFS_FTYPE_REG; temp->oi_nlink = 1; temp->oi_mode = mode; temp->oi_direct[0] = 0; dir_oi->oi_nlink++; entry->od_ino = entry_ino; memcpy(entry->od_name, dentry->d_name.name, dentry->d_name.len); entry->od_name[dentry->d_name.len] = 0; /* Execute this code after your function has successfully created the file. Set entry_ino to the created file's inode number before getting here. */ { struct inode *i = ospfs_mk_linux_inode(dir->i_sb, entry_ino); if (!i) return -ENOMEM; d_instantiate(dentry, i); return 0; } }
static int ospfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) { //eprintk("simlink"); ospfs_inode_t *dir_oi = ospfs_inode(dir->i_ino); uint32_t entry_ino = 0; //EXERCISE: Your code here. if (dentry->d_name.len > OSPFS_MAXNAMELEN) return -ENAMETOOLONG; if (find_direntry(dir_oi, dentry->d_name.name, dentry->d_name.len)) return -EEXIST; //create a new symlink inode ospfs_inode_t *free_inode = ospfs_block(ospfs_super->os_firstinob); uint32_t count = 1; while(count<ospfs_super->os_ninodes) { if (free_inode[count].oi_nlink == 0) break; count++; } //no free inode if (count == ospfs_super->os_ninodes) { count = 0; return -ENOSPC; } else entry_ino = count; //create new inode and entry; ospfs_symlink_inode_t* symlink_oi = ospfs_inode(entry_ino); ospfs_direntry_t * sym_dentry = create_blank_direntry(dir_oi); if (IS_ERR(sym_dentry)) return PTR_ERR(sym_dentry); //init symlink inode: if (strlen(symname)>OSPFS_MAXSYMLINKLEN) return -ENAMETOOLONG; symlink_oi->oi_size = strlen(symname); symlink_oi->oi_ftype = OSPFS_FTYPE_SYMLINK; symlink_oi->oi_nlink = 1; memcpy (symlink_oi->oi_symlink, symname, strlen(symname)); symlink_oi->oi_symlink[strlen(symname)] = '\0'; memcpy (sym_dentry->od_name, dentry->d_name.name, dentry->d_name.len); sym_dentry->od_name[dentry->d_name.len] = '\0'; sym_dentry->od_ino = entry_ino; //Execute this code after your function has successfully created the //file. Set entry_ino to the created file's inode number before //getting here. { struct inode *i = ospfs_mk_linux_inode(dir->i_sb, entry_ino); if (!i) return -ENOMEM; d_instantiate(dentry, i); return 0; } }
static int ospfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) { ospfs_inode_t *dir_oi = ospfs_inode(dir->i_ino); uint32_t entry_ino = 0; ospfs_direntry_t *entry = NULL; ospfs_symlink_inode_t *symlink = NULL; /* EXERCISE: Your code here. */ if(dentry->d_name.len > OSPFS_MAXNAMELEN || strlen(symname) > OSPFS_MAXNAMELEN) { return -ENAMETOOLONG; } if(find_direntry(dir_oi,dentry->d_name.name,dentry->d_name.len)) { return -EEXIST; } entry = create_blank_direntry(dir_oi); if (IS_ERR(entry)) { return PTR_ERR(entry); } while(entry_ino < ospfs_super->os_ninodes) { symlink = ospfs_inode(entry_ino); if(symlink != NULL && symlink->oi_nlink == 0) { break; } entry_ino++; } if (entry_ino == ospfs_super->os_ninodes) { return -ENOSPC; } symlink->oi_size = strlen(symname); symlink->oi_ftype = OSPFS_FTYPE_SYMLINK; symlink->oi_nlink = 1; strncpy(symlink->oi_symlink,symname,symlink->oi_size); symlink->oi_symlink[symlink->oi_size] = 0; dir_oi->oi_nlink++; entry->od_ino = entry_ino; strncpy(entry->od_name,dentry->d_name.name, dentry->d_name.len); entry->od_name[dentry->d_name.len] = 0; /* Execute this code after your function has successfully created the file. Set entry_ino to the created file's inode number before getting here. */ { struct inode *i = ospfs_mk_linux_inode(dir->i_sb, entry_ino); if (!i) return -ENOMEM; d_instantiate(dentry, i); return 0; } }
static int ospfs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd) { ospfs_inode_t *dir_oi = ospfs_inode(dir->i_ino); ospfs_direntry_t *dir_entry; ospfs_inode_t *inode; uint32_t entry_ino = 0; // check if name too long if (dentry->d_name.len > OSPFS_MAXNAMELEN) return -ENAMETOOLONG; // check if directory entry already exists if (find_direntry(dir_oi, dentry->d_name.name, dentry->d_name.len)) return -EEXIST; // create new directory entry dir_entry = create_blank_direntry(dir_oi); if (IS_ERR(dir_entry)) return PTR_ERR(dir_entry); // find empty inode for (entry_ino = 0; entry_ino < ospfs_super->os_ninodes; entry_ino++) { inode = ospfs_inode(entry_ino); if (inode->oi_nlink == 0) break; // empty inode } if (entry_ino == ospfs_super->os_ninodes) return -ENOSPC; // initialize directory entry dir_entry->od_ino = entry_ino; memcpy(dir_entry->od_name, dentry->d_name.name, dentry->d_name.len); dir_entry->od_name[dentry->d_name.len] = '\0'; // initialize file inode->oi_size = 0; inode->oi_ftype = OSPFS_FTYPE_REG; inode->oi_mode = mode; inode->oi_nlink = 1; /* Execute this code after your function has successfully created the file. Set entry_ino to the created file's inode number before getting here. */ { struct inode *i = ospfs_mk_linux_inode(dir->i_sb, entry_ino); if (!i) return -ENOMEM; d_instantiate(dentry, i); return 0; } }
int is_dir(uint32_t i_ino) { ospfs_inode_t *oi = ospfs_inode(i_ino); return oi->oi_ftype == OSPFS_FTYPE_DIR ? 1 : 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; }
int is_reg(uint32_t i_ino) { ospfs_inode_t *oi = ospfs_inode(i_ino); return oi->oi_ftype == OSPFS_FTYPE_REG ? 1 : 0; }
static void * ospfs_follow_link(struct dentry *dentry, struct nameidata *nd) { ospfs_symlink_inode_t *oi = (ospfs_symlink_inode_t *) ospfs_inode(dentry->d_inode->i_ino); // check for conditional symlink if (strncmp(oi->oi_symlink, "root?", 5) == 0) { // find the pivot between first and second paths int pivot = strchr(oi->oi_symlink, ':') - oi->oi_symlink; // root user if (current->uid == 0) { // use null-terminator to indicate ending oi->oi_symlink[pivot] = '\0'; nd_set_link(nd, oi->oi_symlink + 5 + 1); // use first path } // normal user else nd_set_link(nd, oi->oi_symlink + pivot + 1); // use second path } else nd_set_link(nd, oi->oi_symlink); return (void *) 0; }
static int ospfs_notify_change(struct dentry *dentry, struct iattr *attr) { struct inode *inode = dentry->d_inode; ospfs_inode_t *oi = ospfs_inode(inode->i_ino); int retval = 0; if (attr->ia_valid & ATTR_SIZE) { // We should not be able to change directory size if (oi->oi_ftype == OSPFS_FTYPE_DIR) return -EPERM; if ((retval = change_size(oi, attr->ia_size)) < 0) goto out; } if (attr->ia_valid & ATTR_MODE) // Set this inode's mode to the value 'attr->ia_mode'. oi->oi_mode = attr->ia_mode; if ((retval = inode_change_ok(inode, attr)) < 0 || (retval = inode_setattr(inode, attr)) < 0) goto out; out: return retval; }
static ssize_t ospfs_read(struct file *filp, char __user *buffer, size_t count, loff_t *f_pos) { ospfs_inode_t *oi = ospfs_inode(filp->f_dentry->d_inode->i_ino); int retval = 0; size_t amount = 0; // Make sure we don't read past the end of the file! // Change 'count' so we never read past the end of the file. if(*f_pos > oi->oi_size) return 0; //we do not read past the end of the file if(*f_pos + count > oi->oi_size) count = oi->oi_size - *f_pos; /* EXERCISE: Your code here */ // Copy the data to user block by block while (amount < count && retval >= 0) { uint32_t blockno = ospfs_inode_blockno(oi, *f_pos); uint32_t n; char *data; //eprintk("reading!!"); // ospfs_inode_blockno returns 0 on error if (blockno == 0) { retval = -EIO; goto done; } data = ospfs_block(blockno); int offs = *f_pos % OSPFS_BLKSIZE; n = OSPFS_BLKSIZE - offs; int left = count - amount; n = (n > left) ? left : n; if(copy_to_user (buffer, data, n)) //if copy success return 0; { retval = -EFAULT; goto done; } //to: Destination address, in user space. //from: Source address, in kernel space. //n: Number of bytes to copy. // Figure out how much data is left in this block to read. // Copy data into user space. Return -EFAULT if unable to write // into user space. // Use variable 'n' to track number of bytes moved. /* EXERCISE: Your code here */ //retval = -EIO; // Replace these lines //goto done; buffer += n; amount += n; *f_pos += n; } done: return (retval >= 0 ? amount : retval); }
static void * ospfs_follow_link(struct dentry *dentry, struct nameidata *nd) { ospfs_symlink_inode_t *oi = (ospfs_symlink_inode_t *) ospfs_inode(dentry->d_inode->i_ino); // Exercise: Your code here. nd_set_link(nd, oi->oi_symlink); return (void *) 0; }
static ssize_t ospfs_read(struct file *filp, char __user *buffer, size_t count, loff_t *f_pos) { ospfs_inode_t *oi = ospfs_inode(filp->f_dentry->d_inode->i_ino); int retval = 0; size_t amount = 0; // Make sure we don't read past the end of the file! // Change 'count' so we never read past the end of the file. /* DONE: Your code here */ if (count > oi->oi_size - *f_pos) { count = oi->oi_size - *f_pos; } // Copy the data to user block by block while (amount < count && retval >= 0) { uint32_t blockno = ospfs_inode_blockno(oi, *f_pos); uint32_t n; char *data; // ospfs_inode_blockno returns 0 on error if (blockno == 0) { retval = -EIO; goto done; } data = ospfs_block(blockno); // Figure out how much data is left in this block to read. // Copy data into user space. Return -EFAULT if unable to write // into user space. // Use variable 'n' to track number of bytes moved. //goto done; long block_pos = *f_pos % OSPFS_BLKSIZE; if (count - amount > OSPFS_BLKSIZE - block_pos) { n = OSPFS_BLKSIZE - block_pos; } else { n = count - amount; } retval = copy_to_user(buffer, data + block_pos, n); if (retval != 0) { return -EFAULT; } buffer += n; amount += n; *f_pos += n; } done: return (retval >= 0 ? amount : retval); }
static ssize_t ospfs_write(struct file *filp, const char __user *buffer, size_t count, loff_t *f_pos) { ospfs_inode_t *oi = ospfs_inode(filp->f_dentry->d_inode->i_ino); int retval = 0; size_t amount = 0; // Support files opened with the O_APPEND flag. To detect O_APPEND, // use struct file's f_flags field and the O_APPEND bit. /* EXERCISE: Your code here */ int append = filp->f_flags & O_APPEND; if (append) *f_pos = oi->oi_size; // If the user is writing past the end of the file, change the file's // size to accomodate the request. (Use change_size().) /* EXERCISE: Your code here */ if (count > oi->oi_size - *f_pos) { change_size(oi, count + oi->oi_size); } // Copy data block by block while (amount < count && retval >= 0) { uint32_t blockno = ospfs_inode_blockno(oi, *f_pos); uint32_t n; char *data; if (blockno == 0) { retval = -EIO; goto done; } data = ospfs_block(blockno); // Figure out how much data is left in this block to write. // Copy data from user space. Return -EFAULT if unable to read // read user space. // Keep track of the number of bytes moved in 'n'. /* EXERCISE: Your code here */ n = count - amount; //left to write! if (n > OSPFS_BLKSIZE) n = OSPFS_BLKSIZE; if (copy_from_user(data + *f_pos, buffer, n) != 0) { return -EFAULT; } buffer += n; amount += n; *f_pos += n; } done: return (retval >= 0 ? amount : retval); }
static int ospfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) { ospfs_inode_t *dir_oi = ospfs_inode(dir->i_ino); uint32_t entry_ino = 0; ospfs_symlink_inode_t* link; // check if name too long if (dentry->d_name.len > OSPFS_MAXNAMELEN || strlen(symname) > OSPFS_MAXSYMLINKLEN) return -ENAMETOOLONG; // check if directory entry already exists if (find_direntry(ospfs_inode(dir->i_ino), dentry->d_name.name, dentry->d_name.len)) return -EEXIST; // create new symlinked file entry_ino = ospfs_create(dir, dentry, dir_oi->oi_mode, NULL); if (entry_ino < 0) return entry_ino; entry_ino = find_direntry(ospfs_inode(dir->i_ino), dentry->d_name.name, dentry->d_name.len)->od_ino; link = (ospfs_symlink_inode_t*) ospfs_inode(entry_ino); // copy file information link->oi_size = strlen(symname); link->oi_ftype = OSPFS_FTYPE_SYMLINK; link->oi_nlink = 1; memcpy(link->oi_symlink, symname, strlen(symname)); /* Execute this code after your function has successfully created the file. Set entry_ino to the created file's inode number before getting here. */ { struct inode *i = ospfs_mk_linux_inode(dir->i_sb, entry_ino); if (!i) return -ENOMEM; d_instantiate(dentry, i); return 0; } }
static int ospfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) { ospfs_inode_t *dir_oi = ospfs_inode(dir->i_ino); uint32_t entry_ino = 0; /* EXERCISE: Your code here. */ ospfs_direntry_t *od; ospfs_symlink_inode_t *oi = NULL; if (dentry->d_name.len > OSPFS_MAXNAMELEN || strlen(symname) > OSPFS_MAXSYMLINKLEN) return -ENAMETOOLONG; if (find_direntry(dir_oi, dentry->d_name.name, dentry->d_name.len)) return -EEXIST; od = create_blank_direntry(dir_oi); if (IS_ERR(od)) return -ENOSPC; for (entry_ino = 2; entry_ino < ospfs_super->os_ninodes; entry_ino++) { oi = (ospfs_symlink_inode_t *) ospfs_inode(entry_ino); if (oi->oi_nlink == 0) break; } if (entry_ino == ospfs_super->os_ninodes) return -EIO; od->od_ino = entry_ino; strcpy(od->od_name, dentry->d_name.name); oi->oi_size = strlen(symname); oi->oi_ftype = OSPFS_FTYPE_SYMLINK; oi->oi_nlink = 1; strcpy(oi->oi_symlink, symname); /* Execute this code after your function has successfully created the file. Set entry_ino to the created file's inode number before getting here. */ { struct inode *i = ospfs_mk_linux_inode(dir->i_sb, entry_ino); if (!i) return -ENOMEM; d_instantiate(dentry, i); return 0; } }
static int ospfs_link(struct dentry *src_dentry, struct inode *dir, struct dentry *dst_dentry) { /* EXERCISE: Your code here. */ // ospfs_inode_t *dir_oi = ospfs_inode(dir->i_ino); ospfs_inode_t *dummy_i; //if name is too long if(dst_dentry->d_name.len > OSPFS_MAXNAMELEN) return -ENAMETOOLONG; //if the file already exists if(find_direntry(dir_oi, dst_dentry->d_name.name, dst_dentry->d_name.len)) return -EEXIST; // get a directory entry ospfs_direntry_t* dir_entry = create_blank_direntry(dir_oi); if(IS_ERR(dir_entry)) return PTR_ERR(dir_entry); // increment link count dummy_i = ospfs_inode(src_dentry->d_inode->i_ino); if(!dummy_i) return -EIO; dummy_i->oi_nlink++; // set fields of directory entry dir_entry->od_ino = src_dentry->d_inode->i_ino; memcpy(dir_entry->od_name, dst_dentry->d_name.name, dst_dentry->d_name.len); //add null ending character dir_entry->od_name[dst_dentry->d_name.len] = 0; //eprintk("Complete\n"); return 0; //return -EINVAL; }
static int ospfs_link(struct dentry *src_dentry, struct inode *dir, struct dentry *dst_dentry) { // EXERCISE: Your code here. ospfs_inode_t* dir_oi = ospfs_inode (dir->i_ino); if (dst_dentry->d_name.len > OSPFS_MAXNAMELEN) return -ENAMETOOLONG; if (find_direntry(dir_oi, dst_dentry->d_name.name, dst_dentry->d_name.len)) return -EEXIST; //create new dir entry; ospfs_direntry_t *new_dentry = create_blank_direntry (dir_oi); if (IS_ERR(new_dentry)) return PTR_ERR (new_dentry); //the link of the inode++ ospfs_inode_t * target_ino = ospfs_inode(src_dentry->d_inode->i_ino); if (!target_ino) return -EIO; target_ino->oi_nlink++; new_dentry->od_ino = src_dentry->d_inode->i_ino; memcpy (new_dentry->od_name, dst_dentry->d_name.name, dst_dentry->d_name.len); new_dentry->od_name[dst_dentry->d_name.len]='\0'; return 0; }
static int ospfs_link(struct dentry *src_dentry, struct inode *dir, struct dentry *dst_dentry) { // if the name is too long, return too long if (dst_dentry->d_name.len > OSPFS_MAXNAMELEN) return -ENAMETOOLONG; // if the entry is found, it already exists if (find_direntry(ospfs_inode(dir->i_ino), dst_dentry->d_name.name, dst_dentry->d_name.len)) return -EEXIST; ospfs_direntry_t* hard_link = create_blank_direntry(ospfs_inode(dir->i_ino)); if (IS_ERR(hard_link)) return PTR_ERR(hard_link); hard_link->od_ino = src_dentry->d_inode->i_ino; memcpy(hard_link->od_name, dst_dentry->d_name.name, dst_dentry->d_name.len); hard_link->od_name[dst_dentry->d_name.len] = '\0'; ospfs_inode(src_dentry->d_inode->i_ino)->oi_nlink++; return 0; }
static ssize_t ospfs_write(struct file *filp, const char __user *buffer, size_t count, loff_t *f_pos) { ospfs_inode_t *oi = ospfs_inode(filp->f_dentry->d_inode->i_ino); int retval = 0; size_t amount = 0; // Support files opened with the O_APPEND flag. To detect O_APPEND, // use struct file's f_flags field and the O_APPEND bit. /* EXERCISE: Your code here */ // If the user is writing past the end of the file, change the file's // size to accomodate the request. (Use change_size().) /* EXERCISE: Your code here */ // Copy data block by block while (amount < count && retval >= 0) { uint32_t blockno = ospfs_inode_blockno(oi, *f_pos); uint32_t n; char *data; if (blockno == 0) { retval = -EIO; goto done; } data = ospfs_block(blockno); //unsigned long copy_from_user ( (void *) ,(const void __user *) buffer, unsigned long count); // Returns: a pointer to that block's data //to Destination address, in kernel space. //from: Source address, in user space. //n: Number of bytes to copy. // Figure out how much data is left in this block to write. // Copy data from user space. Return -EFAULT if unable to read // read user space. // Keep track of the number of bytes moved in 'n'. /* EXERCISE: Your code here */ retval = -EIO; // Replace these lines goto done; buffer += n; amount += n; *f_pos += n; } done: return (retval >= 0 ? amount : retval); }
static ssize_t ospfs_read(struct file *filp, char __user *buffer, size_t count, loff_t *f_pos) { ospfs_inode_t *oi = ospfs_inode(filp->f_dentry->d_inode->i_ino); int retval = 0; size_t amount = 0; /* EXERCISE: Your code here */ //Never let count request more data than the file size if(count > oi->oi_size - *f_pos) count = oi->oi_size - *f_pos; // Copy the data to user block by block while (amount < count && retval >= 0) { uint32_t blockno = ospfs_inode_blockno(oi, *f_pos); uint32_t n; char *data; // ospfs_inode_blockno returns 0 on error if (blockno == 0) { retval = -EIO; goto done; } data = ospfs_block(blockno); /* EXERCISE: Your code here */ //Calulate amount of block left needed to copy n = count-amount; //Calculate offset of f_pos from a multiple of blocksize uint32_t offset = *f_pos % OSPFS_BLKSIZE; if(count-amount > OSPFS_BLKSIZE - offset){ n = OSPFS_BLKSIZE - offset; } if(copy_to_user(buffer, data + offset, n) != 0){ //eprintk("Unable to write into user space.\n"); retval = -EFAULT; goto done; } buffer += n; amount += n; *f_pos += n; } done: return (retval >= 0 ? amount : retval); }
static struct inode * ospfs_mk_linux_inode(struct super_block *sb, ino_t ino) { ospfs_inode_t *oi = ospfs_inode(ino); struct inode *inode; if (!oi) return 0; if (!(inode = new_inode(sb))) return 0; inode->i_ino = ino; // Make it look like everything was created by root. inode->i_uid = inode->i_gid = 0; inode->i_size = oi->oi_size; if (oi->oi_ftype == OSPFS_FTYPE_REG) { // Make an inode for a regular file. inode->i_mode = oi->oi_mode | S_IFREG; inode->i_op = &ospfs_reg_inode_ops; inode->i_fop = &ospfs_reg_file_ops; inode->i_nlink = oi->oi_nlink; } else if (oi->oi_ftype == OSPFS_FTYPE_DIR) { // Make an inode for a directory. inode->i_mode = oi->oi_mode | S_IFDIR; inode->i_op = &ospfs_dir_inode_ops; inode->i_fop = &ospfs_dir_file_ops; inode->i_nlink = oi->oi_nlink + 1 /* dot-dot */; } else if (oi->oi_ftype == OSPFS_FTYPE_SYMLINK) { // Make an inode for a symbolic link. inode->i_mode = S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH | S_IXUSR | S_IXGRP | S_IXOTH | S_IFLNK; inode->i_op = &ospfs_symlink_inode_ops; inode->i_nlink = oi->oi_nlink; } else panic("OSPFS: unknown inode type!"); // Access and modification times are now. inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; return inode; }