/* Closes INODE and writes it to disk. If this was the last reference to INODE, frees its memory. If INODE was also a removed inode, frees its blocks. */ void inode_close (struct inode *inode) { /* Ignore null pointer. */ if (inode == NULL) return; /* Release resources if this was the last opener. */ if (--inode->open_cnt == 0) { lock_acquire (&inode->lock); /* Remove from inode list and release lock. */ list_remove (&inode->elem); /* Deallocate blocks if removed. */ if (inode->removed) { inode_clear (inode); free_map_release (inode->sector, 1); } lock_release (&inode->lock); free (inode); } }
// Reads from a file, f_offset must be kept in the client to remember the last point read unsigned int fs_read_file(int inode, char * data, int size, unsigned long * f_offset) { inode_clear(&n); // Clear inode to take off the trash inode_read(inode, &n); // Read the current inode int log_block = * f_offset / FS_BLOCK_SIZE; // Current logical block int block_index = * f_offset % FS_BLOCK_SIZE; // Current block index int top_log_block = n.blocks / 2; // Maximum logical block int i = 0; if (!top_log_block && n.mode & EXT2_S_IFDIR) { top_log_block = 1; // Directory hack } // If we match the conditions, start reading if (log_block < top_log_block || log_block == top_log_block && block_index < n._last_write_offset) { log_block_read(&n, &log_block); char * block = (char *) &b; // Read iteratively and easy :) for (; i < size; i++, block_index++) { data[i] = block[block_index]; if (top_log_block == log_block && block_index == n._last_write_offset - 1) { break; // If it's a top, get out } if (block_index == FS_BLOCK_SIZE - 1) { log_block++; log_block_read(&n, &log_block); block_index = -1; } } * f_offset += i; } else { return 0; // Bad offset given } return i; }
// Writes to a file, as simple as unix unsigned int fs_write_file(int inode, char * data, int size) { inode_clear(&n); // Clear the inode to take off the trash inode_read(inode, &n); // Read the current inode. int log_block = n.blocks / 2; block_clear(&b); // Prepare to read the data, clear it. int i = 0; int block_index = n._last_write_offset; log_block_read(&n, &log_block); // Set up the point where we'll write char * block = (char *) &b; // Write until we reach end for (; i < size; i++) { block[block_index] = data[i]; if (block_index == FS_BLOCK_SIZE - 1) { log_block_write(&n, &log_block); log_block++; // Iterate if necessary. log_block_read(&n, &log_block); block_index = 0; } else { block_index++; } } n._last_write_offset = block_index; log_block_write(&n, &log_block); // Save the last bits n.blocks = log_block * 2; // Update the inodes inode_write(inode,&n); fs_bitmaps_write_all(); // Persist the changes in the FS return i; }
// Makes a new directory unsigned int fs_mkdir(char * name, unsigned int parent_inode) { unsigned int inode_id = 0; if ((inode_id = fs_indir(name, parent_inode))) { return 0; } inode_id = bitmap_first_valued(bm_inodes, FS_INODE_BITMAP_SIZE, 0) + 1; if (!parent_inode) { parent_inode = inode_id; } int log_block; if (parent_inode != inode_id) { inode_read(parent_inode, &n); if(!fs_has_perms(&n, ACTION_WRITE)) { return ERR_PERMS; } log_block = n.blocks / 2; block_clear(&b); dir_op_offset = 0; log_block_read(&n, &log_block); add_dir_entry(&n, EXT2_FT_DIR, inode_id, name, &log_block); log_block_write(&n, &log_block); inode_write(parent_inode, &n); } bitmap_write(bm_inodes, inode_id - 1, 1); inode_clear(&n); if(!fs_done) { n.uid = 0; } else { n.uid = current_ttyc()->uid; } n.mode = EXT2_S_IFDIR; n.size = 0; n.blocks = 0; // Beware! This represents the SECTORS! log_block = n.blocks / 2; block_clear(&b); dir_op_offset = 0; add_dir_entry(&n, EXT2_FT_DIR, inode_id, ".", &log_block); add_dir_entry(&n, EXT2_FT_DIR, parent_inode, "..", &log_block); log_block_write(&n, &log_block); n.blocks = (log_block) * 2; n.i_file_acl = 511; n._dir_inode = parent_inode; n._last_write_offset = dir_op_offset; inode_write(inode_id, &n); fs_bitmaps_write_all(); return inode_id; }
// Opens a file unsigned int fs_open_file(char * name, unsigned int folder_inode, int mode, int type) { unsigned int inode_id = 0; if(strcmp(name, "/") == 0 && strlen(name) == strlen("/")) { return 1; // root } if(name[0] == 0) { inode_id = current_ttyc()->pwd; } else { inode_id = fs_indir(name, folder_inode); } if (inode_id) { if (mode & O_CREAT) { int _rm_res = fs_rm(inode_id, 0); if(_rm_res < 0) { return _rm_res; } } else if(mode & O_NEW) { inode_read(inode_id, &n); if(n.mode == EXT2_S_IFLNK) { return n.data_blocks[0]; } return inode_id; } else { inode_read(inode_id, &n); int can = 1; if((mode & O_RD) && !fs_has_perms(&n, ACTION_READ)) { can = 0; } if((mode & O_WR) && !fs_has_perms(&n, ACTION_WRITE)) { can = 0; } if(can || !fs_done) { if(n.mode == EXT2_S_IFLNK) { return n.data_blocks[0]; } return inode_id; } else { return ERR_PERMS; } } } else if (!(mode & (O_NEW | O_CREAT))) { return ERR_NO_EXIST; } inode_id = bitmap_first_valued(bm_inodes, FS_INODE_BITMAP_SIZE, 0) + 1; if (!folder_inode) { folder_inode = inode_id; } int log_block; if (folder_inode != inode_id) { inode_read(folder_inode, &n); if(!fs_has_perms(&n, ACTION_WRITE)) { return ERR_PERMS; } log_block = n.blocks / 2; block_clear(&b); dir_op_offset = 0; log_block_read(&n, &log_block); add_dir_entry(&n, EXT2_FT_DIR, inode_id, name, &log_block); log_block_write(&n, &log_block); inode_write(folder_inode, &n); } bitmap_write(bm_inodes, inode_id - 1, 1); inode_clear(&n); if(!fs_done) { n.uid = 0; } else { n.uid = current_ttyc()->uid; } n.mode = type; n.size = 0; n.blocks = 0; // Beware! This represents the SECTORS! n._last_write_offset = 0; n.i_file_acl = 511; n._dir_inode = folder_inode; inode_write(inode_id, &n); inode_clear(&n); if(n.mode == EXT2_S_IFLNK) { return n.data_blocks[0]; } return inode_id; }