/* Reads the next directory entry in DIR and stores the name in NAME. Returns true if successful, false if the directory contains no more entries. */ bool dir_readdir (struct dir *dir, char name[NAME_MAX + 1]) { struct dir_entry e; while (inode_read_at (dir->inode, &e, sizeof e, dir->pos) == sizeof e) { dir->pos += sizeof e; if (e.in_use && strcmp(e.name,".") != 0 && strcmp(e.name,"..") != 0 ) { strlcpy (name, e.name, NAME_MAX + 1); return true; } } return false; }
bool dir_is_empty( struct dir *dir) { struct dir_entry e; int pos = 0; while (inode_read_at (dir->inode, &e, sizeof e, pos) == sizeof e) { pos += sizeof e; if (e.in_use) { if (strcmp(e.name,".")==0 || strcmp(e.name,"..")==0) continue; return false; } } return true; }
/* Adds a file named NAME to DIR, which must not already contain a file by that name. The file's inode is in sector INODE_SECTOR. Returns true if successful, false on failure. Fails if NAME is invalid (i.e. too long) or a disk or memory error occurs. */ bool dir_add (struct dir *dir, const char *name, block_sector_t inode_sector) { struct dir_entry e; off_t ofs; bool success = false; name = getfilename(name); ASSERT (dir != NULL); ASSERT (name != NULL); /* Check NAME for validity. */ if (*name == '\0' || strlen (name) > NAME_MAX) { return false; } //lock the directory for the operation inode_lock(dir->inode); /* Check that NAME is not in use. */ if (lookup (dir, name, NULL, NULL)) goto done; /* Set OFS to offset of free slot. If there are no free slots, then it will be set to the current end-of-file. inode_read_at() will only return a short read at end of file. Otherwise, we'd need to verify that we didn't get a short read due to something intermittent such as low memory. */ for (ofs = 0; inode_read_at (dir->inode, &e, sizeof e, ofs) == sizeof e; ofs += sizeof e) if (!e.in_use) break; /* Write slot. */ e.in_use = true; strlcpy (e.name, name, sizeof e.name); e.inode_sector = inode_sector; success = inode_write_at (dir->inode, &e, sizeof e, ofs) == sizeof e; done: //unlock the directory again inode_unlock(dir->inode); return success; }
/* Adds a file named NAME to DIR, which must not already contain a file by that name. The file's inode is in sector INODE_SECTOR. Returns true if successful, false on failure. Fails if NAME is invalid (i.e. too long) or a disk or memory error occurs. */ bool dir_add (struct file *dir, const char *name, block_sector_t inode_sector) { ASSERT (file_is_dir (dir)); struct dir_entry e; size_t ofs; bool success = false; ASSERT (dir != NULL); ASSERT (name != NULL); /* Check NAME for validity. */ if (*name == '\0' || strlen (name) > NAME_MAX) return false; bool locked = file_lock (dir); /* Check that NAME is not in use. */ if (dir_lookup (dir, name) >= 0) goto done; /* Set OFS to offset of free slot. If there are no free slots, then it will be set to the current end-of-file. inode_read_at() will only return a short read at end of file. Otherwise, we'd need to verify that we didn't get a short read due to something intermittent such as low memory. */ size_t dir_size = inode_length (dir->inode); for (ofs = 0; ofs < dir_size; ofs += sizeof e) { inode_read_at (dir->inode, &e, sizeof e, ofs); if (!e.in_use) break; } /* Write slot. */ e.in_use = true; strlcpy (e.name, name, sizeof e.name); e.inode_sector = inode_sector; success = inode_write_at (dir->inode, &e, sizeof e, ofs) == sizeof e; done: if (locked) file_unlock (dir); return success; }
/* Returns the num of entries in this directory, EXCLUDING '.' and '..' */ static size_t dir_size (struct dir *dir) { struct dir_entry e; size_t ofs; size_t count = 0; ASSERT (dir != NULL); lock_acquire (&dir->l); for (ofs = 0; inode_read_at (dir->inode, &e, sizeof e, ofs) == sizeof e; ofs += sizeof e) { if (e.in_use) count++; } lock_release (&dir->l); return count - 2; }
static struct directory *dir_get_root(struct block *d){ struct inode *root_ino; struct directory *root; ASSERT(d != NULL); // get root inode root_ino = ext2_get_inode(d,EXT2_ROOT_INO); // allocate memory root = kmalloc(root_ino->i_size); if(root == NULL) return NULL; // read entire file inode_read_at(d,root_ino,root,root_ino->i_size,0); return root; }
/* Reads the next directory entry in DIR and stores the name in NAME. Returns true if successful, false if the directory contains no more entries. */ bool dir_readdir (struct dir *dir, char name[NAME_MAX + 1]) { struct dir_entry e; while (inode_read_at (dir->inode, &e, sizeof e, dir->pos) == sizeof e) { dir->pos += sizeof e; if (e.in_use) { // printf ("readdir name:%x, name:%s, pos:%d\n", name, e.name, dir->pos); strlcpy (name, e.name, NAME_MAX + 1); // printf ("strlcpy end\n"); return true; } } return false; }
/* Reads the next directory entry in DIR and stores the name in NAME. Returns true if successful, false if the directory contains no more entries. */ bool dir_readdir (struct dir *dir, char name[NAME_MAX + 1]) { struct dir_entry e; bool result = false; lock_acquire (&dir->l); while (!result && inode_read_at (dir->inode, &e, sizeof e, dir->pos) == sizeof e) { if (e.in_use) { strlcpy (name, e.name, NAME_MAX + 1); result = true; } dir->pos += sizeof e; } lock_release (&dir->l); return result; }
/* Reads the next directory entry in DIR and stores the name in NAME. Returns true if successful, false if the directory contains no more entries. */ bool dir_readdir (struct dir *dir, char name[NAME_MAX + 1]) { // lock_acquire(&directory_lock); struct dir_entry e; bool success = false; while (inode_read_at (dir->inode, &e, sizeof e, dir->pos) == sizeof e) { dir->pos += sizeof e; if (e.in_use) { strlcpy (name, e.name, NAME_MAX + 1); // return true; success = true; break; } } // lock_release(&directory_lock); return success; }
bool dir_readdir (struct dir *directory, char file [MAXIMUM_FILE_NAME_LENGTH + 1]) { struct dir_entry directory_element; bool success = false; acquire_inode_lock (directory->inode); while (inode_read_at (directory->inode, &directory_element, sizeof directory_element, directory->pos) == sizeof directory_element) { directory->pos += sizeof directory_element; if (directory_element.in_use) { strlcpy (file, directory_element.name, MAXIMUM_FILE_NAME_LENGTH + 1); success = true; break; } } release_inode_lock (directory->inode); return success; }
/* Searches DIR for a file with the given NAME. If successful, returns true, sets *EP to the directory entry if EP is non-null, and sets *OFSP to the byte offset of the directory entry if OFSP is non-null. otherwise, returns false and ignores EP and OFSP. */ static bool lookup (const struct dir *dir, const char *name, struct dir_entry *ep, off_t *ofsp) { struct dir_entry e; size_t ofs; ASSERT (dir != NULL); ASSERT (name != NULL); for (ofs = 0; inode_read_at (dir->inode, &e, sizeof e, ofs) == sizeof e; ofs += sizeof e) if (e.in_use && !strcmp (name, e.name)) { if (ep != NULL) *ep = e; if (ofsp != NULL) *ofsp = ofs; return true; } return false; }
/* Returns whether or not the given directory is empty (an empty directory is one in which the only entries are "." and ".."). NOTE : Assumes the caller has already acquired a lock on the directory. */ bool dir_is_empty (struct file *dir) { ASSERT (file_is_dir (dir)); /* Look through all the directory entries, counting up the entries that are in use. */ size_t dir_size = inode_length (dir->inode); struct dir_entry e; size_t ofs; size_t entries = 0; for (ofs = 0; ofs < dir_size; ofs += sizeof e) { inode_read_at (dir->inode, &e, sizeof e, ofs); if (e.in_use) entries++; } /* A directory should never have less than 2 entries. */ ASSERT (entries >= 2); /* The directory is empty if it contains only "." and ".." - 2 entries. */ return entries == 2; }
/*! Reads SIZE bytes from FILE into BUFFER, starting at offset FILE_OFS in the file. Returns the number of bytes actually read, which may be less than SIZE if end of file is reached. The file's current position is unaffected. */ off_t file_read_at(struct file *file, void *buffer, off_t size, off_t file_ofs) { ASSERT(file != NULL); ASSERT(buffer != NULL); return inode_read_at(file->inode, buffer, size, file_ofs); }
/* Creates a file named NAME with the given INITIAL_SIZE. Returns true if successful, false otherwise. Fails if a file named NAME already exists, or if internal memory allocation fails. */ static bool _filesys_create (const char *full_path, off_t initial_size, bool is_dir) { block_sector_t cwd = thread_current ()->cwd_sector; bool found = true; if (cwd != (block_sector_t) ROOT_DIR_SECTOR) { struct inode *curr = NULL; curr = inode_open (cwd); struct dir *p; p = dir_open (inode_open (curr->data.parent_dir_sector)); struct dir_entry e; size_t ofs; ASSERT (p != NULL); found = false; for (ofs = 0; inode_read_at (p->inode, &e, sizeof e, ofs) == sizeof e; ofs += sizeof e) { if (e.inode_sector == cwd && e.in_use) { found = true; break; } } } if (!found) return false; char leaf_name[NAME_MAX + 1]; if (!dir_get_leaf_name (full_path, leaf_name)) return false; struct dir *parent_dir = dir_get_parent_dir (full_path); if (parent_dir == NULL) return false; block_sector_t inode_sector = 0; if (!free_map_allocate_one (&inode_sector)) { dir_close (parent_dir); return false; } bool success = is_dir? dir_create (inode_sector, BLOCK_SECTOR_SIZE / sizeof (struct dir_entry)) : inode_create (inode_sector, initial_size); if (!success) { free_map_release (inode_sector, 1); dir_close (parent_dir); return false; } if (!dir_add (parent_dir, leaf_name, inode_sector)) { inode_remove (inode_open (inode_sector)); free_map_release (inode_sector, 1); dir_close (parent_dir); return false; } dir_close (parent_dir); return true; }
bool dir_remove (struct dir *directory, const char *file) { struct dir_entry directory_element_1, directory_element_2; struct inode *inode = NULL; bool present = false; off_t offset_1, offset_2; int count; ASSERT(directory != NULL); ASSERT(file != NULL); acquire_inode_lock (directory->inode); for (offset_2 = 0; inode_read_at (directory->inode, &directory_element_2, sizeof directory_element_2, offset_2) == sizeof directory_element_2; offset_2 += sizeof directory_element_2) if (directory_element_2.in_use && !strcmp (file, directory_element_2.name)) { directory_element_1 = directory_element_2; offset_1 = offset_2; present = true; } if (!present) { inode_close (inode); release_inode_lock (directory->inode); return false; } inode = inode_open (directory_element_1.inode_sector); if (inode == NULL) { inode_close (inode); release_inode_lock (directory->inode); return false; } if (is_inode_dir (inode) && get_inode_open_cnt (inode) > 1) { inode_close (inode); release_inode_lock (directory->inode); return false; } if (is_inode_dir (inode) && !dir_is_empty (inode)) { inode_close (inode); release_inode_lock (directory->inode); return false; } directory_element_1.in_use = false; offset_2 = inode_write_at (directory->inode, &directory_element_1, sizeof directory_element_1, offset_1); if (sizeof directory_element_1 != offset_2) { inode_close (inode); release_inode_lock (directory->inode); return false; } inode_remove (inode); inode_close (inode); release_inode_lock (directory->inode); return true; }
/* Reads SIZE bytes from FILE into BUFFER, starting at offset FILE_OFS in the file. Returns the number of bytes actually read, which may be less than SIZE if end of file is reached. The file's current position is unaffected. */ off_t file_read_at (struct file *file, void *buffer, off_t size, off_t file_ofs) { return inode_read_at (file->inode, buffer, size, file_ofs); }
struct directory *dir_lookup(struct block *d, const char *path){ char *path_copy, *token, *save_ptr; struct directory *cur,*next,*last,*file_ptr; struct directory *found = NULL; ASSERT(path != NULL); // copy path path_copy = kmalloc(strlen(path)+1); memcpy(path_copy,path,strlen(path)+1); // start from root last = NULL; cur = dir_get_root(d); ASSERT(cur != NULL); // search path for(token = strtok_r(path_copy,"/",&save_ptr); token != NULL; token = strtok_r(NULL,"/",&save_ptr)){ // check if current directory is the same as the last if(cur == last) { file_ptr = NULL; break; } // look up current directory file_ptr = dir_lookup_current(cur,token); last = cur; //save current directory // if file is directory if(file_ptr != NULL && file_ptr->inode != 0 && file_ptr->file_type == EXT2_FT_DIR){ // get file inode, it is temporary struct inode *file_ino = ext2_get_inode(d,file_ptr->inode); if(file_ino == NULL || (file_ino->i_mode & EXT2_S_IFDIR) == 0){ file_ptr = NULL; if(file_ino != NULL) kfree(file_ino); break; } // read directory file next = kmalloc(file_ino->i_size); if(next == NULL) { file_ptr = NULL; kfree(file_ino); break; } inode_read_at(d,file_ino,next,file_ino->i_size,0); // free temporary memory and switch directory kfree(file_ino); kfree(cur); cur = next; } } // file found if(file_ptr != NULL && file_ptr->inode != 0){ found = kmalloc(sizeof(struct directory)); memcpy(found,file_ptr,sizeof(struct directory)); } kfree(cur); kfree(path_copy); return found; }