size_t level_two(struct inode *inode, struct indirect_inode* first_level_block, size_t new_sectors) { struct indirect_inode second_level_block; char filler[BLOCK_SECTOR_SIZE]; if (inode->double_indirect_index == 0) { free_map_allocate(1, &outer_block->pointers[inode->indirect_index]); } else { block_read(fs_device, outer_block->pointers[inode->indirect_index], &second_level_block); } while (inode->double_indirect_index < INDIRECT_POINTERS && new_sectors != 0) { free_map_allocate(1, &second_level_block.pointers[inode->double_indirect_index]); block_write(fs_device, second_level_block.pointers[inode->double_indirect_index], filler); inode->double_indirect_index++; new_sectors--; } block_write(fs_device, outer_block->pointers[inode->indirect_index], &second_level_block); if (inode->double_indirect_index == INDIRECT_POINTERS) { inode->double_indirect_index = 0; inode->indirect_index++; } return new_sectors; }
/* allocate_sectors inode와 sectors를 받아서 어떤 한 파일이 sectors개수만큼 disk에서 할당받도록 해준다 두가지 경우가 있는데 아예 처음부터 새로 할당을 시작하는 경우와 원래 가지고 있던 부분에서 추가해서 할당하는 경우 */ static bool allocate_sectors(struct inode_disk *disk_inode, int sector , int cnt) { /* doubly indirect */ int i, j; static char zeros[512]; if(sector == 0) return true; struct sector_table *doubly_indirect_table; doubly_indirect_table = calloc(1, sizeof(struct sector_table)); if(cnt == 0) { if(!free_map_allocate(1, &disk_inode->doubly_indirect)) { return false; } } cache_read(disk_inode->doubly_indirect, doubly_indirect_table, 512, 0); for(i = 0; i < 128 && sector > 0; i++) { struct sector_table *indirect_table = calloc(1, sizeof(struct sector_table)); if(cnt == 0) { if(!free_map_allocate(1, &doubly_indirect_table->table[i])) return false; } cache_read(doubly_indirect_table->table[i], indirect_table, 512, 0); for(j = 0; j < 128 && sector > 0; j++) { if(cnt == 0) { if(free_map_allocate(1, &indirect_table->table[j])) { cache_write(indirect_table->table[j], zeros, 512, 0); } else { free(indirect_table); free(disk_inode); return false; } } else cnt--; sector--; } cache_write(doubly_indirect_table->table[i], indirect_table, 512, 0); free(indirect_table); } cache_write(disk_inode->doubly_indirect, doubly_indirect_table, 512, 0); free(doubly_indirect_table); return true; }
/* Initializes an inode with LENGTH bytes of data and writes the new inode to sector SECTOR on the file system device. Returns true if successful. Returns false if memory or disk allocation fails. */ bool inode_create (block_sector_t sector, off_t length) { struct inode_disk *disk_inode = NULL; bool success = false; ASSERT (length >= 0); /* If this assertion fails, the inode structure is not exactly one sector in size, and you should fix that. */ ASSERT (sizeof *disk_inode == BLOCK_SECTOR_SIZE); disk_inode = calloc (1, sizeof *disk_inode); if (disk_inode != NULL) { size_t sectors = bytes_to_sectors (length); disk_inode->length = length; disk_inode->magic = INODE_MAGIC; if (free_map_allocate (sectors, &disk_inode->start)) { block_write (fs_device, sector, disk_inode); if (sectors > 0) { static char zeros[BLOCK_SECTOR_SIZE]; size_t i; for (i = 0; i < sectors; i++) block_write (fs_device, disk_inode->start + i, zeros); } success = true; } free (disk_inode); } return success; }
/* 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. */ bool filesys_create (const char *name, off_t initial_size, bool isdir) { block_sector_t inode_sector = 0; // Get directory struct dir *dir = get_containing_dir(name); char *file_name = get_filename(name); // Get file name char* file_name = get_filename(name); bool success = false; if (strcmp(file_name, ".") != 0 && strcmp(file_name, "..") != 0) { success = (dir != NULL && free_map_allocate (1, &inode_sector) && inode_create (inode_sector, initial_size, isdir) && dir_add (dir, file_name, inode_sector)); } if (!success && inode_sector != 0) free_map_release (inode_sector, 1); dir_close (dir); free(file_name); return success; }
/* 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. */ bool filesys_create (const char *path, off_t initial_size) { block_sector_t inode_sector = 0; struct dir *dir = NULL; bool success = false; char *name = malloc (NAME_MAX + 1); if (name == NULL) goto done; if (!dir_follow_path (thread_current ()->cwd, path, &dir, name)) goto done; success = (dir != NULL && free_map_allocate (1, &inode_sector) && inode_create (inode_sector, initial_size) && dir_add (dir, name, inode_sector)); if (!success && inode_sector != 0) { cache_remove (fs_cache, inode_sector, 1); free_map_release (inode_sector, 1); } done: dir_close (dir); free (name); return success; }
/* Initializes an inode with LENGTH bytes of data and wirtes the new inode to sector SECTOR on the file system device. Returns true if successful. Returns false if memeory or disk allocation fails. */ bool inode_create (block_sector_t sector, off_t length){ struct inode_disk *disk_inode = NULL; bool success = false; ASSERT (length >= 0); /* If this assertion fails, the inode structure is not exactly one sector in size, and you should fix that */ ASSERT (sizeof *disk_inode == BLOCK_SECTOR_SIZE); disk_inode = calloc(1, sizeof *disk_inode); if (disk_inode != NULL){ size_t sectors = bytes_to_sectors (length); disk_inode->length = length; disk_inode->magic = INODE_MAGIC; if (free_map_allocate (sectors, &disk_inode->start)) { block_write(fs_device, sector, disk_inode); success = file_growth(disk_inode, sectors); free(disk_inode); } } return success; }
/* 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. */ bool filesys_create (const char *name, off_t initial_size) { block_sector_t inode_sector = 0; struct dir *dir; char parsed_name[NAME_MAX + 1]; if (*name == NULL || (strlen (name) > NAME_MAX)) { return false; } bool success = parse_path (name, &dir, parsed_name); if (!success) { return success; } struct inode *inode; success = (dir != NULL && free_map_allocate (1, &inode_sector) && inode_create (inode_sector, initial_size, false) && dir_add (dir, parsed_name, inode_sector) && dir_lookup (dir, ".", &inode)); if (!success && inode_sector != 0) free_map_release (inode_sector, 1); dir_close (dir); return success; }
/* Extends the INODE with LENGTH bytes. */ static bool inode_extend (struct inode *inode, off_t length) { struct inode_disk *disk; off_t free_length; size_t sectors; disk_sector_t sector; size_t i; lock_acquire (&inode->lock); disk = (struct inode_disk *) malloc (sizeof *disk); ASSERT (disk != NULL); cache_read (inode->sector, disk, 0, DISK_SECTOR_SIZE); free_length = disk->sector_count * DISK_SECTOR_SIZE - disk->length; sectors = bytes_to_sectors (length - free_length); for (i = 0; i < sectors; i++) { if (!free_map_allocate (1, §or) || !inode_append (inode, sector)) { lock_release (&inode->lock); return false; } } disk->length += length; cache_write (inode->sector, &disk->length, INODE_OFFSET_LENGTH, 4); lock_release (&inode->lock); free (disk); return true; }
/* 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. */ bool filesys_create (const char *name, off_t initial_size, enum file_type type) { block_sector_t inode_sector = 0; char * parse = parse_filename (name); //get the correct dir struct dir *dir = dir_lookup_rec (parse); bool success = (dir != NULL && free_map_allocate (1, &inode_sector) && inode_create (inode_sector, initial_size, type) && dir_add (dir, parse, inode_sector)); if (!success && inode_sector != 0) free_map_release (inode_sector, 1); if( success == true && type == FILE_DIR ) { //we want to add . and .. as well if it is a dir //open the created directory struct file * created = filesys_open(parse); struct dir * mydir = dir_open(file_get_inode (created)); //add . to it dir_add (mydir, ".", inode_sector); struct inode * parent = dir_get_inode (dir); block_sector_t inode_sector_parent = inode_id(parent); //add .. to it dir_add (mydir, "..", inode_sector_parent); dir_close(mydir); file_close(created); } dir_close (dir); return success; }
/* 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. */ bool filesys_create (const char *name, off_t initial_size,bool is_dir) { // printf("create start: %s\n",name); // printf("%s size: %d\n",name,initial_size); disk_sector_t inode_sector = 0; char *file_name = get_file_name(name); bool success=true; if( strcmp(file_name,"")==0 ) { return false; } // if( is_dir) // printf("mkdir!\n"); // printf("file name : %s\n",file_name); struct dir *dir = get_directory(name); // printf("sector of dir : %d\n", inode_get_inumber(dir_get_inode(dir))); // if( inode_get_parent(dir_get_inode(dir)) ==0 ) // { // printf("its on root directory!\n"); // } /* if(dir == NULL) { printf("no directory\n"); success=false; } if(!free_map_allocate(1,&inode_sector)) { printf("no free map\n"); success=false; } if(!inode_create(inode_sector,initial_size,is_dir)) { printf("inode create fail\n"); success=false; } if(!dir_add(dir,file_name,inode_sector)) { printf("dir add fail\n"); success=false; }*/ // printf("file name:%s\n",file_name); success = (dir != NULL && free_map_allocate (1, &inode_sector) && inode_create (inode_sector, initial_size, is_dir) && dir_add (dir, file_name, inode_sector)); if (!success && inode_sector != 0) { // printf("haha\n"); free_map_release (inode_sector, 1); } dir_close (dir); // printf("create end sector num : %d\n",inode_sector); free(file_name); return success; }
/* if offset is bigger than file_length, allocate new disk and update inode */ bool inode_update_file_length(struct inode_disk *inode_disk, off_t start_pos, off_t end_pos) { off_t size = end_pos - start_pos; off_t offset = start_pos; void *zeros = malloc(SECTOR_SIZE); int chunck_size; /* make zeros */ if(zeros == NULL) return false; memset(zeros, 0, SECTOR_SIZE); while( size > 0 ) { /* offset in the disk block */ int sector_ofs = offset % SECTOR_SIZE; /* caculate chunck size */ if( size >= SECTOR_SIZE) chunck_size = SECTOR_SIZE - sector_ofs; else { if(sector_ofs + size > SECTOR_SIZE) chunck_size = SECTOR_SIZE - sector_ofs; else chunck_size = size; } /* if sector_ofs is bigger than zero, already allocate disk block */ if(sector_ofs > 0 ) { } /* allocate new disk block */ else { struct sector_location sec_loc; block_sector_t sector_idx; /* allocate new disk block */ if(free_map_allocate(1, §or_idx) == true) { /* update disk block number */ locate_byte(offset, &sec_loc); register_sector(inode_disk, sector_idx, sec_loc); } else { free(zeros); return false; } /* init new disk block to 0 */ bc_write(sector_idx, zeros, 0, SECTOR_SIZE, 0); } /* advance */ size -= chunck_size; offset += chunck_size; } free(zeros); return true; }
/*! 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. */ bool filesys_create(const char *name, off_t initial_size) { block_sector_t inode_sector = 0; struct dir *dir = dir_open_root(); bool success = (dir != NULL && free_map_allocate(1, &inode_sector) && inode_create(inode_sector, initial_size) && dir_add(dir, name, inode_sector)); if (!success && inode_sector != 0) free_map_release(inode_sector, 1); dir_close(dir); return success; }
/* Creates directory. True if successful. */ bool filesys_mkdir (const char *dir) { bool success = false; /*The string *dir cannot be empty.*/ if (*dir == NULL) { return success; } /* Locates the directory where the new directory should be created. */ struct dir *create_dir; char parsed_name[NAME_MAX + 1]; parse_path (dir, &create_dir, parsed_name); block_sector_t sector; /*Find a free sector for the directory.*/ if (!free_map_allocate (1, §or)) { return success; } success = dir_create (sector, 16); if (!success) { free_map_release (sector, 1); return success; } success = dir_add (create_dir, parsed_name, sector); if (!success) { free_map_release (sector, 1); return success; } /* Get the dir struct of the directory that is just created and add "." and "..". */ struct inode *inode = inode_open (sector); struct dir *new_dir = dir_open (inode); ASSERT (inode != NULL); ASSERT (new_dir != NULL); dir_add (new_dir, ".", sector); dir_add (new_dir, "..", create_dir->inode->sector); dir_close (new_dir); dir_close (create_dir); return success; }
/* extend inode at sector sector with length bytes */ static bool inode_extend (struct inode* inode, off_t ext_length) { if(INODE_DEBUG || FILE_DEBUG) printf("INODE: extending inode %u by %i bytes\n", inode->sector, ext_length); lock_acquire(&inode->lock); bool success = true; /* local copy of disk inode */ struct inode_disk* id = malloc(sizeof(struct inode_disk)); cache_read(inode->sector, id, 0, sizeof(struct inode_disk)); /* free space left in bytes */ off_t free_space = id->sector_count * BLOCK_SECTOR_SIZE - id->length; /* needed sectors */ size_t sectors = bytes_to_sectors (ext_length - free_space); /* add sector to inode */ unsigned i; block_sector_t block_sector; for(i = 0; i < sectors; i++) { /* allocate one vector at a time */ if(free_map_allocate (1, &block_sector)) { /* add new block to inode */ inode_add_block(inode, block_sector); } /* not enough space on disk - abort */ else { printf("INODE: that should not happen.\n"); success = false; break; } } /* increment length and write back */ id->length += ext_length; cache_write(inode->sector, (void *) &id->length, INODE_OFFSET_LENGTH, 4); lock_release(&inode->lock); if(INODE_DEBUG || FILE_DEBUG) printf("INODE: completetd extending inode %u by %i bytes : %u\n", inode->sector, ext_length, (unsigned)success); return success; }
static bool allocate_zero_block (block_sector_t *res) { char *zero_block = calloc (1, BLOCK_SECTOR_SIZE); bool success = false; if (zero_block == NULL) return false; if (free_map_allocate (1, res)) { cache_write (fs_cache, *res, zero_block, 0, BLOCK_SECTOR_SIZE); success = true; } free (zero_block); return success; }
/* Creates a file named NAME with the given INITIAL_SIZE.*/ bool filesys_create (const char *name, off_t initial_size, bool isdir) { if (strlen(name) == 0) return false; block_sector_t inode_sector = 0; struct dir *dir_ = filesys_get_dir(name); char *name_ = filesys_get_name(name); bool success = false; if (strcmp (name_, "") == 0) goto done; success = (dir_ && free_map_allocate (1, &inode_sector) && inode_create (inode_sector, initial_size) && dir_add (dir_, name_, inode_sector, isdir)); struct inode *ninode = NULL; struct dir *ndir = NULL; bool success1 = true; if (success && isdir){ success1 = ((ninode = inode_open (inode_sector)) && (ndir = dir_open (ninode)) && dir_add (ndir, ".", inode_sector, true) && dir_add (ndir, "..",inode_get_inumber (dir_get_inode (dir_)), true)); } if (inode_sector != 0 && !success) free_map_release (inode_sector, 1); if (success && !success1) { success = false; printf("Failure: create dir: %s\n", name); dir_remove (dir_, name_); } done: dir_close (dir_); free(name_); if (!ndir && ninode){ inode_close(ninode); } else if (ndir) { dir_close(ndir); } return success; }
/* padding zeros from start_pos (inclusive) to end_pos (exclusive) */ bool zero_padding(struct inode *inode, struct inode_disk *id, off_t start_pos, off_t end_pos) { ASSERT(lock_held_by_current_thread (&inode->inode_lock)); static char zeros[BLOCK_SECTOR_SIZE]; /* padding the first partial sector */ if (start_pos % BLOCK_SECTOR_SIZE != 0) { block_sector_t eof_sector = byte_to_sector(inode, start_pos-1); off_t sector_ofs = start_pos % BLOCK_SECTOR_SIZE; size_t zero_bytes = BLOCK_SECTOR_SIZE - sector_ofs; cache_write(eof_sector, zeros, sector_ofs, zero_bytes); } /* padding full sectors until end_pos-1 */ int extra_sectors = (int)bytes_to_sectors(end_pos)- (int)bytes_to_sectors(start_pos); off_t* record_sectors=malloc(sizeof(off_t) * extra_sectors); off_t i,j; block_sector_t new_sector=-1; for(i=0;i<extra_sectors;i++){ if (!free_map_allocate (1, &new_sector)) { for(j=0;j<i;j++){ free_map_release(record_sectors[i],1); } free(record_sectors); return false; } if(!append_sector_to_inode(id,new_sector)){ for(j=0;j<i;j++){ free_map_release(record_sectors[i],1); } free(record_sectors); return false; } cache_write(new_sector, zeros, 0, BLOCK_SECTOR_SIZE); record_sectors[i]=new_sector; id->length += BLOCK_SECTOR_SIZE; } /*update the physical length info*/ id->length=end_pos; cache_write(inode->sector, id, 0, BLOCK_SECTOR_SIZE); free(record_sectors); return true; }
/* 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. */ bool filesys_create (const char *path, off_t initial_size) { char *name = get_filename (path); block_sector_t inode_sector = 0; struct dir *dir = dir_get (path); bool success = (dir != NULL && free_map_allocate (1, &inode_sector) && inode_create (inode_sector, initial_size, false) && dir_add (dir, name, inode_sector)); if (!success && inode_sector != 0) free_map_release (inode_sector, 1); dir_close (dir); free (name); return success; }
/* create directory file */ bool filesys_create_dir(const char *name) { struct dir *parent_dir; struct inode *parent_inode; struct inode *tmp; struct dir *new_dir; bool result = false; /* if dir name is NULL, return false*/ if(name == NULL) return result; /* copy name to cp_name */ char *cp_name = malloc( sizeof(char) * (strlen(name)+1) ); strlcpy(cp_name, name, strlen(name)+1 ); char *file_name; file_name = malloc( sizeof(char) * (strlen(name)+1) ); if(file_name == NULL) { free(cp_name); return result; } parent_dir = parse_path(cp_name, file_name); /* if already same name file exist in directory, return false*/ if(dir_lookup(parent_dir, file_name, &tmp) == true) return result; /* allocate bitmap */ block_sector_t sector_idx; free_map_allocate(1, §or_idx); /* create directory */ dir_create(sector_idx, 16); /* add new entry to parent directory */ dir_add(parent_dir, file_name, sector_idx); /* add entry '.' and '..' to directory */ new_dir = dir_open( inode_open(sector_idx) ); dir_add(new_dir,".",sector_idx); parent_inode = dir_get_inode(parent_dir); dir_add(new_dir,"..", inode_get_inumber(parent_inode)); free(cp_name); free(file_name); result = true; return result; }
/*! Creates the directory named dir. Return true if successful, but false * if dir already exists or if any directory name in dir, besides the last * one does not exist. */ bool _mkdir(const char* dir) { /* Inode for the new directory created. */ struct inode* next_inode; /* Parent directory. */ struct dir* cur_dir; /* Name of the directory. */ char name[15]; /* Sector number allocated to the new directory. */ block_sector_t sector; /* Check the validity of the pointer*/ if (!checkva(dir)) exit(-1); /* The compose the path to a final dir name and its parent directory. */ if (!decompose_dir(dir, name, &cur_dir)){ return false; } ASSERT(cur_dir != NULL); /* Allocate a new sector for this new directory; * Create a new directory */ if (!free_map_allocate(1, §or) || !dir_create(sector, 0, dir_get_inode(cur_dir)->sector)){ dir_close(cur_dir); return false; } /* Add the new directory to its parent directory. */ if (!dir_add(cur_dir, name, sector)){ free_map_release(sector, 1); dir_close(cur_dir); return false; } dir_close(cur_dir); return true; }
/* 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. */ bool filesys_create (const char *name, off_t initial_size) { block_sector_t inode_sector = 0; struct thread *cur = thread_current(); struct dir *dir; if(cur->current_directory == NULL) dir = dir_open_root (); else dir = dir_open_current(); bool success = (dir != NULL && free_map_allocate (1, &inode_sector) && inode_create (inode_sector, initial_size, false) && dir_add (dir, name, inode_sector)); if (!success && inode_sector != 0) free_map_release (inode_sector, 1); dir_close (dir); return success; }
/* 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. */ bool filesys_create (const char *name, off_t initial_size) { char *cp_name = malloc( sizeof(char) * (strlen(name) + 1) ); char *file_name = malloc( sizeof(char) * (strlen(name) + 1) ); if( cp_name == NULL || file_name == NULL) return false; strlcpy(cp_name, name, strlen(name)+1); block_sector_t inode_sector = 0; struct dir *dir = parse_path (cp_name, file_name); bool success = (dir != NULL && free_map_allocate (1, &inode_sector) && inode_create (inode_sector, initial_size, IS_FILE) && dir_add (dir, file_name, inode_sector)); if (!success && inode_sector != 0) free_map_release (inode_sector, 1); dir_close (dir); free(cp_name); free(file_name); return success; }
/* Expands the inode. */ void inode_grow (struct inode *inode, off_t addition) { struct indirect_inode first_level_block; size_t new_sectors = bytes_to_data_sectors(addition) - \ bytes_to_data_sectors(inode->length); if (inode->double_indirect_index == 0 && inode->indirect_index == 0) { free_map_allocate(1, &inode->indirect table); } else { block_read(fs_device, inode->pointers[inode->direct_index], &first_level_block); } while (inode->indirect_index < INDIRECT_POINTERS && new_sectors != 0) { new_sectors = level_two(inode, &first_level_block, new_sectors); } block_write(fs_device, inode->pointers[inode->direct_index], &first_level_block); //get back addition - new_sectors * 512 inode -> length = addition - (new_sectors * BLOCK_SECTOR_SIZE); }
/* 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. */ bool filesys_create (const char *name, off_t initial_size, bool is_dir) { block_sector_t inode_sector = 0; /* Start of Project 4 */ bool success = false; struct dir *dir = dir_from_path (name); char* file_name = retrieve_file_name (name); if (strcmp(file_name, ".") != 0 && strcmp(file_name, "..") != 0) { success = (dir != NULL && free_map_allocate (1, &inode_sector) && inode_create (inode_sector, initial_size, is_dir) && dir_add (dir, file_name, inode_sector)); } free(file_name); /* End of Project 4 */ if (!success && inode_sector != 0) free_map_release (inode_sector, 1); dir_close (dir); return success; }
void updateBlock(struct inode * inode, off_t offset, block_sector_t new_sector) { block_sector_t bounce[128]; int sectors = offset/BLOCK_SECTOR_SIZE; block_read(fs_device,inode->data.start,bounce); if(sectors % 128 == 0 && (sectors/128 !=0)) { bounce[sectors/128] = new_sector; // printf("new added sector : %d to bounce[%d]\n",new_sector,sectors/128); block_write(fs_device,inode->data.start,bounce); free_map_allocate(1,&new_sector); } if(new_sector != 0) { int inner_sector = bounce[sectors/128]; block_read(fs_device,inner_sector,bounce); bounce[sectors%128] = new_sector; block_write(fs_device,inner_sector,bounce); } }
/* 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. */ bool filesys_create (const char *name, off_t initial_size, uint32_t is_dir) { block_sector_t inode_sector = (block_sector_t) -1; struct inode *inode = NULL; struct dir *search_dir = get_cwd(name); if (search_dir == NULL) { return false; } char *part = malloc(NAME_MAX + 1); if (part == NULL) { return false; } memset(part, 0, NAME_MAX + 1); int retrieved_next_part; for (retrieved_next_part = get_next_part(part, &name); retrieved_next_part > 0; retrieved_next_part = get_next_part(part, &name)) { if (dir_lookup (search_dir, part, &inode)) { if (!inode_is_dir(inode)) { break; } else { dir_close(search_dir); search_dir = dir_open(inode); if (search_dir == NULL) { free(part); return false; } } } else { inode = NULL; break; } } if (inode != NULL || get_next_part(part, &name) != 0) { if (inode != NULL && !inode_is_dir(inode)) { inode_close(inode); } dir_close(search_dir); free(part); return false; } bool success = false; if (is_dir) { block_sector_t parent_sector = inode_get_inumber(dir_get_inode(search_dir)); success = (search_dir != NULL && free_map_allocate (1, &inode_sector) && dir_create (inode_sector, initial_size, parent_sector) && dir_add (search_dir, part, inode_sector)); } else { success = (search_dir != NULL && free_map_allocate (1, &inode_sector) && inode_create (inode_sector, initial_size, is_dir) && dir_add (search_dir, part, inode_sector)); } if (!success) free_map_release (inode_sector, 1); dir_close (search_dir); free(part); return success; }
/* set the new_sector to the first non-allocated sector in the inode * must acquire inode lock before calling it */ bool append_sector_to_inode(struct inode_disk *id, block_sector_t new_sector) { int sectors = (int)bytes_to_sectors(id->length); static struct indirect_block ib; static struct indirect_block db; if (sectors <= DIRECT_INDEX_NUM) { if (sectors < DIRECT_INDEX_NUM) { /*within direct index part*/ id->direct_idx[sectors] = new_sector; } else { /*use up direct index part, start using single indirect index*/ if (!free_map_allocate (1, &id->single_idx)) { return false; } ib.sectors[0] = new_sector; cache_write(id->single_idx, &ib, 0, BLOCK_SECTOR_SIZE); } } else if (sectors <= DIRECT_INDEX_NUM+INDEX_PER_SECTOR) { if (sectors < DIRECT_INDEX_NUM+INDEX_PER_SECTOR) { /*within single indirect index part*/ cache_read(id->single_idx, INVALID_SECTOR_ID, &ib, 0, BLOCK_SECTOR_SIZE); ib.sectors[sectors-DIRECT_INDEX_NUM] = new_sector; cache_write(id->single_idx, &ib, 0, BLOCK_SECTOR_SIZE); } else { /*use up single indirect index part, start using * double indirect index*/ if (!free_map_allocate (1, &id->double_idx)) { return false; } static struct indirect_block single_ib; if (!free_map_allocate (1, &db.sectors[0])) { free_map_release (id->double_idx, 1); return false; } single_ib.sectors[0] = new_sector; cache_write(db.sectors[0], &single_ib, 0, BLOCK_SECTOR_SIZE); cache_write(id->double_idx, &db, 0, BLOCK_SECTOR_SIZE); } } else { size_t sectors_left=sectors - DIRECT_INDEX_NUM - INDEX_PER_SECTOR; if(sectors_left%INDEX_PER_SECTOR ==0){ /*on the edge of one double indirect index, need * to allocate another single indirect index in * the double indirect index*/ cache_read(id->double_idx, INVALID_SECTOR_ID, &db, 0, BLOCK_SECTOR_SIZE); if (!free_map_allocate (1, &db.sectors[sectors_left/INDEX_PER_SECTOR])) { return false; } ib.sectors[0]=new_sector; cache_write(db.sectors[sectors_left/INDEX_PER_SECTOR], &ib, 0, BLOCK_SECTOR_SIZE); cache_write(id->double_idx, &db, 0, BLOCK_SECTOR_SIZE); }else{ cache_read(id->double_idx, INVALID_SECTOR_ID, &db, 0, BLOCK_SECTOR_SIZE); cache_read(db.sectors[sectors_left/INDEX_PER_SECTOR], INVALID_SECTOR_ID, &ib, 0, BLOCK_SECTOR_SIZE); ib.sectors[sectors_left%INDEX_PER_SECTOR]=new_sector; cache_write(db.sectors[sectors_left/INDEX_PER_SECTOR], &ib, 0, BLOCK_SECTOR_SIZE); } } return true; }
/* add sector block_sector to inode inode */ static void inode_add_block(struct inode* inode, block_sector_t block_sector) { ASSERT(lock_held_by_current_thread(&inode->lock)); //if(INODE_DEBUG && INODE_PRINT) inode_print(inode); /* local copy of disks inode */ struct inode_disk* id = malloc(sizeof(struct inode_disk)); cache_read(inode->sector, id, 0, sizeof(struct inode_disk)); /* direct block sectors */ if(id->sector_count < INODE_DIRECT_BLOCKS) { if(INODE_DEBUG) printf("INODE: adding block %u to direct block sectors of %u @ position %u\n", block_sector, inode->sector, id->sector_count); /* add to direct blocks */ id->direct_block_sectors[id->sector_count] = block_sector; } /* indirect block sector */ else if (id->sector_count < INODE_DIRECT_BLOCKS + INODE_INDIRECT_BLOCKS) { if(INODE_DEBUG) printf("INODE: adding block %u to indirect block sector of %u\n", block_sector, inode->sector); /* offset in indirect list */ off_t offset = id->sector_count - INODE_DIRECT_BLOCKS; /* create indirect block if this is * the first element in the indirect list */ if(offset == 0) { /* empty block */ void *zero = malloc(BLOCK_SECTOR_SIZE); /* create indirect block */ block_sector_t indirect_bs; free_map_allocate (1, &indirect_bs); /* save to disks inode */ id->indirect_block_sector = indirect_bs; /* write back empty indirect sector */ cache_write(indirect_bs, zero, 0, BLOCK_SECTOR_SIZE); } ASSERT(id->indirect_block_sector != 0); /* add sector to indirect sector list */ cache_write(id->indirect_block_sector, (void *) &block_sector, offset * sizeof(block_sector_t), sizeof(block_sector_t)); } /* doubly indirect sector */ else if (id->sector_count < INODE_DIRECT_BLOCKS + INODE_INDIRECT_BLOCKS + INODE_DOUBLY_DIRECT_BLOCKS) { if(INODE_DEBUG) printf("INODE: adding block %u to doubly indirect block sector of %u\n", block_sector, inode->sector); /* count of all doubly indirect block sectors */ off_t entry_cnt = id->sector_count - (INODE_DIRECT_BLOCKS + INODE_INDIRECT_BLOCKS); /* offset in the doubly indirect list */ off_t offset_doubly_indirect = entry_cnt / INODE_INDIRECT_BLOCKS; /* offset in the indirect list */ off_t offset_indirect = entry_cnt % INODE_INDIRECT_BLOCKS; //printf("INODE DIB: entries {%i} offset dib {%i} offset ib {%i}\n", entry_cnt, offset_doubly_indirect, offset_indirect); /* create doubly indirect block if this is * the first element in the doubly indirect list */ if(entry_cnt == 0) { /* empty block */ void *zero = malloc(BLOCK_SECTOR_SIZE); /* create doubly indirect block sector */ block_sector_t di_block_sector; free_map_allocate (1, &di_block_sector); /* save to disks inode */ id->doubly_indirect_block_sector = di_block_sector; /* write back empty indirect sector */ cache_write(di_block_sector, zero, 0, BLOCK_SECTOR_SIZE); } /* create indirect block sector if this is the first entry */ if(offset_indirect == 0) { /* empty block */ void *zero = malloc(BLOCK_SECTOR_SIZE); /* create indirect block sector */ block_sector_t indirect_block_sector; free_map_allocate (1, &indirect_block_sector); /* initialize empty indirect block sector */ cache_write(indirect_block_sector, zero, 0, BLOCK_SECTOR_SIZE); /* save indirect block sector to doubly indirect block sector */ cache_write(id->doubly_indirect_block_sector, (void *) &indirect_block_sector, offset_doubly_indirect * sizeof(block_sector_t), sizeof(block_sector_t)); //printf("added indirect block %u @ sector %u offset %i\n", indirect_block_sector, id->doubly_indirect_block_sector, offset_doubly_indirect * sizeof(block_sector_t)); } ASSERT(id->doubly_indirect_block_sector != 0); /* fetch indirect block sector number */ block_sector_t indirect_block_sector; cache_read(id->doubly_indirect_block_sector, (void *) &indirect_block_sector, offset_doubly_indirect * sizeof(block_sector_t), sizeof(block_sector_t)); //printf("INODE-IDS: %u\n", indirect_block_sector); ASSERT(indirect_block_sector != 0); /* add block sector number to indirect block sector */ cache_write(indirect_block_sector, (void *) &block_sector, offset_indirect * sizeof(block_sector_t), sizeof(block_sector_t)); //printf("done\n"); } else { /* something went horribly wrong. */ ASSERT(false); } /* increment sector count and write back */ id->sector_count++; cache_write(inode->sector, (void *) id, 0, BLOCK_SECTOR_SIZE); free(id); //if(INODE_DEBUG && INODE_PRINT) inode_print(inode); }
/* Initializes an inode with LENGTH bytes of data and writes the new inode to sector SECTOR on the file system device. Returns true if successful. Returns false if memory or disk allocation fails. */ bool inode_create (block_sector_t sector, off_t length, bool is_dir) { struct inode_disk *disk_inode = NULL; ASSERT (length >= 0); /* If this assertion fails, the inode structure is not exactly one sector in size, and you should fix that. */ ASSERT (sizeof *disk_inode == BLOCK_SECTOR_SIZE); disk_inode = calloc (1, sizeof *disk_inode); if (disk_inode != NULL) { int sectors = (int)bytes_to_sectors (length); disk_inode->length = length; disk_inode->magic = INODE_MAGIC; disk_inode->is_dir = is_dir; int i; block_sector_t sector_idx = 0; static char zeros[BLOCK_SECTOR_SIZE]; bool allocate_failed = false; /* allocate sectors for data and write all zeros to sectors*/ int direct_sector_num = sectors < DIRECT_INDEX_NUM ? sectors : DIRECT_INDEX_NUM; int indirect_sector_num = (sectors-DIRECT_INDEX_NUM) < INDEX_PER_SECTOR ? (sectors - DIRECT_INDEX_NUM) : INDEX_PER_SECTOR; int double_indirect_sector_num = sectors - DIRECT_INDEX_NUM - INDEX_PER_SECTOR; /* allocate direct sectors */ for (i = 0; i < direct_sector_num; i++) { if (free_map_allocate (1, §or_idx)) { disk_inode->direct_idx[i] = sector_idx; cache_write(sector_idx, zeros, 0, BLOCK_SECTOR_SIZE); } else { allocate_failed = true; break; } } /* release allocated direct sectors when failed to allocate */ if (allocate_failed) { free_map_release_direct(disk_inode, i); free (disk_inode); return false; } static struct indirect_block ib; /* allocate single indirect sectors */ if(indirect_sector_num > 0){ if (!free_map_allocate (1, &disk_inode->single_idx)) { free_map_release_all_direct(disk_inode); free (disk_inode); return false; } for (i = 0; i < indirect_sector_num; i++) { if (free_map_allocate (1, §or_idx)) { ib.sectors[i] = sector_idx; cache_write(sector_idx, zeros, 0, BLOCK_SECTOR_SIZE); } else { allocate_failed = true; break; } } /* release all direct sectors and allocated single indirect * sectors when failed to allocate */ if (allocate_failed) { free_map_release_all_direct(disk_inode); free_map_release_single_indirect(&ib, i); free_map_release(disk_inode->single_idx, 1); free (disk_inode); return false; } cache_write(disk_inode->single_idx, &ib, 0, BLOCK_SECTOR_SIZE); } /* allocate double indirect sectors */ if(double_indirect_sector_num > 0){ if (!free_map_allocate (1, &disk_inode->double_idx)) { free_map_release_all_direct(disk_inode); free_map_release_all_single_indirect(&ib); free_map_release (disk_inode->single_idx, 1); free (disk_inode); return false; } off_t double_level_end_idx = (double_indirect_sector_num-1) / INDEX_PER_SECTOR; off_t single_level_end_idx = (double_indirect_sector_num-1) % INDEX_PER_SECTOR; int i, j; /*double indirect index block*/ static struct indirect_block db; /*buffer the single indirect index block in double * indirect index block*/ static struct indirect_block single_ib; /* allocate all full single indirect block */ for (i = 0; i < double_level_end_idx; i++) { if (!free_map_allocate (1, &db.sectors[i])){ free_map_release_all_direct(disk_inode); free_map_release_all_single_indirect(&ib); free_map_release (disk_inode->single_idx, 1); free_map_release_double_indirect (&db, i, 0); free_map_release (disk_inode->double_idx, 1); free (disk_inode); return false; } /* fully allocate the whole single indirect block */ for (j = 0; j < INDEX_PER_SECTOR; j++) { if (free_map_allocate (1, §or_idx)) { single_ib.sectors[j] = sector_idx; cache_write(sector_idx, zeros, 0, BLOCK_SECTOR_SIZE); } else { allocate_failed = true; break; } } if (allocate_failed) { free_map_release_all_direct(disk_inode); free_map_release_all_single_indirect(&ib); free_map_release (disk_inode->single_idx, 1); free_map_release_double_indirect (&db, i, j); free_map_release (disk_inode->double_idx, 1); free (disk_inode); return false; } cache_write(db.sectors[i], &single_ib, 0, BLOCK_SECTOR_SIZE); } /* allocate the last partial/full single indirect block */ if (!free_map_allocate (1, &db.sectors[double_level_end_idx])){ free_map_release_all_direct(disk_inode); free_map_release_all_single_indirect(&ib); free_map_release (disk_inode->single_idx, 1); free_map_release_double_indirect (&db, double_level_end_idx, 0); free_map_release (disk_inode->double_idx, 1); free (disk_inode); return false; } /* partially or fully (depend on single_level_end_idx) * allocate the last single indirect block */ for (j = 0; j <= single_level_end_idx; j++) { if (free_map_allocate (1, §or_idx)) { single_ib.sectors[j] = sector_idx; cache_write(sector_idx, zeros, 0, BLOCK_SECTOR_SIZE); } else { allocate_failed = true; break; } } if (allocate_failed) { free_map_release_all_direct(disk_inode); free_map_release_all_single_indirect(&ib); free_map_release (disk_inode->single_idx, 1); free_map_release_double_indirect (&db, double_level_end_idx, j); free_map_release (disk_inode->double_idx, 1); free (disk_inode); return false; } cache_write(db.sectors[double_level_end_idx], &single_ib, 0, BLOCK_SECTOR_SIZE); /* update inode_disk(metadata) after successfully * allocate all necessary sectors */ cache_write(disk_inode->double_idx, &db, 0, BLOCK_SECTOR_SIZE); } /* write inode_disk(metadata) to sector */ cache_write(sector, disk_inode, 0, BLOCK_SECTOR_SIZE); free (disk_inode); return true; } return false; }
/* Returns actual new length of the inode. It may differ from the given new_length if an error occurs. */ off_t dinode_extend (struct inode_disk *dinode, off_t new_length) { static char zeros[BLOCK_SECTOR_SIZE] = {0}; size_t new_data_sectors = bytes_to_total_sectors(new_length) - bytes_to_total_sectors(dinode->length); /* Contraction is not allowed.*/ ASSERT (new_data_sectors >= 0); /* Extension in the same sector only modifies dinode->length information */ if (new_data_sectors == 0) goto done; /* Extension to direct block */ while (dinode->dir_cnt < DIR_BLOCKS) { dinode->dir_cnt++; free_map_allocate (1, &dinode->direct[dinode->dir_cnt-1]); block_write(fs_device, dinode->direct[dinode->dir_cnt-1], zeros); new_data_sectors--; if (new_data_sectors == 0) goto done; } /* Extension to single indirect block */ while (dinode->indir_cnt < INDIR_BLOCKS) { struct indir_block block; /* No indirect block exists or current indirect block is full. */ if (dinode->indir_cnt == 0 || dinode->indir_curr_usage == INDIR_BLOCK_PTRS) { dinode->indir_cnt++; free_map_allocate(1, &dinode->indirect[dinode->indir_cnt-1]); dinode->indir_curr_usage = 0; } block_read(fs_device, dinode->indirect[dinode->indir_cnt-1], &block); while (dinode->indir_curr_usage < INDIR_BLOCK_PTRS) { dinode->indir_curr_usage++; free_map_allocate(1, &block.ptr[dinode->indir_curr_usage-1]); block_write(fs_device, block.ptr[dinode->indir_curr_usage-1], zeros); new_data_sectors--; if (new_data_sectors == 0) break; } block_write(fs_device, dinode->indirect[dinode->indir_cnt-1], &block); if (new_data_sectors == 0) goto done; } /* Extension to double indirect block */ while (dinode->dindir_cnt < DINDIR_BLOCKS) { struct indir_block d_block, block; /* No double indirect block exists or current block is full. */ if (dinode->dindir_cnt == 0 || dinode->dindir_curr_usage == INDIR_BLOCK_PTRS) { dinode->dindir_cnt++; free_map_allocate(1, &dinode->dindirect[dinode->dindir_cnt-1]); dinode->dindir_curr_usage = 0; } block_read(fs_device, dinode->dindirect[dinode->dindir_cnt-1], &d_block); /* We've just got the level 1 block, so now we have to get the level 2 block. */ while (dinode->dindir_curr_usage < INDIR_BLOCK_PTRS) { /* No level 2 block exists or current level 2 block is full. */ if (dinode->dindir_curr_usage == 0 || dinode->dindir_lv2_curr_usage == INDIR_BLOCK_PTRS) { dinode->dindir_curr_usage++; free_map_allocate(1, &d_block.ptr[dinode->dindir_curr_usage-1]); dinode->dindir_lv2_curr_usage = 0; } block_read(fs_device, d_block.ptr[dinode->dindir_curr_usage-1], &block); /* We've just got the level 2 block, so now we have to get the actual data block. */ while (dinode->dindir_lv2_curr_usage < INDIR_BLOCK_PTRS) { dinode->dindir_lv2_curr_usage++; free_map_allocate(1, &block.ptr[dinode->dindir_lv2_curr_usage-1]); block_write(fs_device, block.ptr[dinode->dindir_lv2_curr_usage-1], zeros); new_data_sectors--; if (new_data_sectors == 0) break; } /* writing back the level 2 block */ block_write(fs_device, d_block.ptr[dinode->dindir_curr_usage-1], &block); if (new_data_sectors == 0) break; } /* writing back the level 1 block */ block_write(fs_device, dinode->dindirect[dinode->dindir_cnt-1], &d_block); if (new_data_sectors == 0) goto done; } /* Immediately write back because there's no buffer cache. */ /* This failure may happen when the given file size exceeds the maximum. */ dinode->length = new_length - new_data_sectors*BLOCK_SECTOR_SIZE; block_write (fs_device, dinode->sector, dinode); return dinode->length; done: dinode->length = new_length; block_write (fs_device, dinode->sector, dinode); return new_length; }