// Used to check if the file is a fifo or not. unsigned int fs_is_fifo(int inode) { if(inode < 0) { return 0; } inode_read(inode, &n); return n.mode & EXT2_S_IFIFO; }
int fs_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { struct inode *ino = (struct inode *)fi->fh; ino->i_atime = time(NULL); return inode_read(ino, buf, size, offset); }
//******** cnopen ********************* //mode: FD_READ/FD_WRITE int16_t cnopen(dir_ptr* dir, const char* name, uint8_t mode) { stat_st stat_buf; if(cnstat(dir,name,&stat_buf) != 0) { if(mode == FD_WRITE) { check(cncreat(dir,name) == 0, "Could not create %s", name); } check(cnstat(dir,name,&stat_buf) == 0, "Could not stat %s", name); } //TODO: The fd bitmap is not 1 block long, hope we don't run out of fds int16_t fd = (int16_t)(uint16_t)find_free_bit((block*)fd_bm); set_bitmap((block*)fd_bm, fd); fd_tbl[fd].cursor = 0; fd_tbl[fd].state = mode; fd_tbl[fd].inode_id = stat_buf.inode_id; inode_read(stat_buf.inode_id, &fd_tbl[fd].inode); if(fd_tbl[fd].inode.blocks > 0) { fd_tbl[fd].data = calloc(fd_tbl[fd].inode.blocks,sizeof(block)); llread(&fd_tbl[fd].inode, fd_tbl[fd].data); } else { fd_tbl[fd].data = NULL; } return fd; error: return -1; }
//******** rmdir ******************** int8_t cnrmdir(const char* name) { char parent_name[512]; char entry_name[256]; dir_entry* entry; inode dir_inode; memset(&dir_inode, 0, sizeof(inode)); strcpy(parent_name, name); strcat(parent_name, "/.."); dir_ptr* parent = cnopendir(parent_name); check(parent != NULL, "Cannot open parent directory"); //Copy the entire directory minus the entry dir_ptr* new_parent = calloc(1,sizeof(dir_ptr)); new_parent->data = calloc(parent->inode_st.blocks, sizeof(block)); dir_entry* new_dir_entry = (dir_entry*)new_parent->data; new_parent->inode_st = parent->inode_st; new_parent->inode_id = parent->inode_id; new_parent->inode_st.size = 0; new_parent->index = 0; while((entry = cnreaddir(parent))) { memcpy(entry_name, entry->name, entry->name_len); entry_name[entry->name_len] = 0; if(strcmp(entry_name, name) == 0) //If this is the directory we want { inode_read(entry->inode, &dir_inode); check(dir_inode.size == 24, "Directory is not empty"); release_block(dir_inode.data0[0]); //Release target directory block release_inode(entry->inode); //Release target inode continue; } new_dir_entry->entry_len = entry->entry_len; new_dir_entry->name_len = entry->name_len; new_dir_entry->file_type = entry->file_type; new_dir_entry->inode = entry->inode; memcpy(new_dir_entry->name, entry->name, entry->name_len); new_parent->inode_st.size += entry->entry_len; new_parent->index += entry->entry_len; new_dir_entry = (dir_entry*)((uint8_t*)new_parent->data+new_parent->index); } inode_write(new_parent->inode_id, &new_parent->inode_st); llwrite(&new_parent->inode_st, new_parent->data); free(new_parent->data); free(new_parent); cnclosedir(parent); return 0; error: if(new_parent != NULL && new_parent->data != NULL) free(new_parent->data); if(new_parent != NULL) free(new_parent); if(parent != NULL) cnclosedir(parent); return -1; }
//******** inflatedir ***************** //Populates a dir_ptr from an iptr void inflatedir(dir_ptr* dir, iptr inode_id) { inode_read(inode_id,&dir->inode_st); dir->inode_id = inode_id; //Read the directory file for this inode dir->data = calloc(dir->inode_st.blocks, sizeof(block)); //Memory for all directory file blocks llread(&dir->inode_st, dir->data); //Read the directory file dir->index = 0; }
// Returns the inode's permissions unsigned int fs_getmod(char * filename) { int start_inode = current_ttyc()->pwd; int namenode = fs_indir(filename, start_inode); if (namenode) { inode_read(namenode, &n); return n.i_file_acl & 0777; } else { return ERR_NO_EXIST; } }
// Tells the current location char * fs_pwd() { int j = 1023; int i = 0; for(; i < 1024; ++i) { pwd_string[i] = 0; } int start_inode = current_ttyc()->pwd; inode_read(start_inode, &n); while(n._dir_inode != start_inode) { int _old_dirnode = n._dir_inode; char * name = fs_iname(start_inode, n._dir_inode); int k = strlen(name) - 2; for(; k >= 0; k--, j--) { pwd_string[j] = name[k]; } pwd_string[j] = '/'; j--; start_inode = _old_dirnode; inode_read(start_inode, &n); } if(j == 1023) { pwd_string[j] = '/'; } else { j++; } for(i = 0; j < 1024; i++,j++) { pwd_string[i] = pwd_string[j]; pwd_string[j] = 0; } return pwd_string; }
void remove_from_dir(int inode_id, inode parent, FILE *ufs, superblock spb) { uint16_t children[1024] = {0}; inode realoc; int i; int position = -1; int blocksize = spb.magic_number; int last = first_free_child(parent, ufs, spb, blocksize, children); for (i = 0; i < last; i++) { if (children[i] == inode_id) { position = i; } } if (last == -1) last = 1023; else last -= 1; if (position == -1) { printf("Error\n"); return; } // printf("Position %d last %d children %d\n", position, last, children[last]); write_to_dir(position, parent, children[last], spb, ufs); inode_read(parent.id, ufs, spb.magic_number, spb.root_inode, &parent); // printf("last one is %d\n",last); //inode_read(last, ufs, blocksize, spb.root_inode, &realoc); // inode_write(inode_id, ufs, blocksize, uint16_t first_inode_blk, realoc); // write_to_dir(inode_id, parent, last, spb, ufs); write_to_dir(last, parent, 0, spb, ufs); if ((last - (BLK_PER_IND-4))%(blocksize/2) == 0) { // printf("caiu aqui\n"); int block_in_vec = (BLK_PER_IND-4) + ((last - (BLK_PER_IND-4))/(blocksize/2)); inode_read(parent.id, ufs, spb.magic_number, spb.root_inode, &parent); parent.blocks[block_in_vec] = 0; inode_write(parent.id, ufs, blocksize, spb.root_inode, parent); } }
// Opens a link filetype unsigned int fs_open_link(char * name, char * target_name) { unsigned int folder_inode = current_ttyc()->pwd; int target_inode = fs_indir(target_name, folder_inode); if(target_inode > 0) { int result = fs_open_file(name, folder_inode, O_NEW, EXT2_S_IFLNK); if(result > 0) { inode_read(result, &n); n.data_blocks[0] = target_inode; inode_write(result, &n); result = fs_open_reg_file(target_name, folder_inode, O_RD); inode_read(result, &n); n.links++; inode_write(result, &n); return 1; } else { return result; } } else { return ERR_NO_EXIST; } }
// Gets info from the file void fs_finfo(char * filename, int * data) { int start_inode = current_ttyc()->pwd; int namenode = fs_indir(filename, start_inode); if(namenode) { inode_read(namenode, &n); data[0] = namenode; // Inode data[1] = n.blocks / 2; // Blocks data[2] = n.blocks / 2 * 1024; // Bytes data[3] = n.i_file_acl; // Permissions data[4] = n.uid; // UID data[5] = n._dir_inode; // Directory inode } }
/** * Read from file f. */ int file_read(struct file *f, char *addr, int n) { int r; if(f->readable == 0) return -1; if(f->type == FD_INODE){ inode_lock(f->ip); if((r = inode_read(f->ip, addr, f->off, n)) > 0) f->off += r; inode_unlock(f->ip); return r; } KERN_PANIC("file_read"); }
//****** cncat ********************* int8_t cncat(const char* name, char* buf) { stat_st filestat; dir_ptr* dir = cnopendir("."); check(cnstat(dir, name, &filestat) == 0, "Can not stat file"); inode file_i; inode_read(filestat.inode_id, &file_i); int8_t fd = cnopen(dir,name,FD_READ); check(fd >= 0, "Can not open file"); cnread((uint8_t*)buf, file_i.size, fd); return 0; error: cnclosedir(dir); return -1; }
//******* cntree ************ void treedir(dir_ptr* dir, uint8_t indents, char** buf) { dir_entry* entry; inode entry_i; memset(&entry_i, 0, sizeof(inode)); int chars; //Write indent pattern char indent_str[256]; uint8_t indents_ptr = indents; while(indents_ptr > 0) { strcat(indent_str," "); indents_ptr--; } while((entry = cnreaddir(dir))) { char name_copy[256]; memset(name_copy, 0, 256); memcpy(name_copy, entry->name, entry->name_len); if(strcmp(name_copy,".") == 0) continue; if(strcmp(name_copy,"..") == 0) continue; inode_read(entry->inode,&entry_i); if(indents > 0) { strcpy(*buf,indent_str); *buf += strlen(indent_str); } memcpy(*buf, entry->name, entry->name_len); *buf += entry->name_len; chars = sprintf(*buf, " %s %u %s", (entry_i.type == ITYPE_FILE) ? "F":"D", entry_i.size, ctime((const time_t *)&entry_i.modified)); *buf += chars; if(entry->file_type == ITYPE_DIR) //Go to next indent level if a dir { cncd(name_copy); dir_ptr* next_dir = cnopendir("."); treedir(next_dir,indents+1,buf); cnclosedir(next_dir); cncd(".."); } } }
//****** cnexport **************** int8_t cnexport(const char* g_name, const char* h_name) { FILE* h_file; size_t h_size; char* buf; size_t result; int16_t g_file; stat_st statbuf; h_file = fopen(h_name, "wb"); check(h_file != NULL, "Can not open host file"); dir_ptr* cwd = cnopendir("."); g_file = cnopen(cwd, g_name, FD_READ); check(g_file >= 0, "Cannot open guest file for reading"); check(cnstat(cwd, g_name, &statbuf) == 0, "Cannot stat guest file"); inode g_inode; inode_read(statbuf.inode_id, &g_inode); h_size = g_inode.size; //buffer for whole file buf = calloc(h_size, sizeof(char)); //load file result = cnread((uint8_t*)buf, h_size, g_file); check(result == h_size, "Error reading from guest file"); //write the buffer to the host result = fwrite(buf, sizeof(char), h_size, h_file); check(result > 0, "Error writing to host file"); //close guest resources cnclose(g_file); cnclosedir(cwd); fclose(h_file); free(buf); return 0; error: //close guest resources cnclose(g_file); cnclosedir(cwd); fclose(h_file); free(buf); return -1; }
// Changes the permissions of the file unsigned int fs_chmod(char * filename, int perms) { int current_uid = current_ttyc()->uid; int start_inode = current_ttyc()->pwd; int namenode = fs_indir(filename, start_inode); if (namenode) { inode_read(namenode, &n); if (n.uid == current_uid || current_uid == 0) { n.i_file_acl = perms; inode_write(namenode, &n); } else { return ERR_PERMS; } return 1; } else { return ERR_NO_EXIST; } }
// Removes an entry from a folder unsigned int folder_rem_direntry(unsigned int file_inode, unsigned int folder_inode) { inode_read(folder_inode, &n); int index = 0; int max_log_block = n.blocks / 2; if (!max_log_block) { max_log_block = 1; } dir_op_offset = 0; block_clear(&b); dir_entry * old_dot = NULL; dir_entry * dot = NULL; // Iterates dir entries while (index < max_log_block + 1) { old_dot = dot; dot = iterate_dir_entry(&b); if (dot == NULL) { if (index == max_log_block) { break; } log_block_read(&n,&index); dir_op_offset = 0; dot = NULL; index++; } else { int i = 0; ; int match = file_inode == dot->inode; if (match) { if (old_dot != NULL) { old_dot->rec_len += dot->rec_len; dot->inode = 0; dot->name_len = 0; // Sets as deleted } else { dot->name_len = 0; // Sets as deleted } int to_write = index - 1; log_block_write(&n, &to_write); break; } } } return 0; }
// Tells the name of the inode, by reading it's parent char * fs_iname(int inode, int folder_inode) { inode_read(folder_inode, &n); *iname = 0; int index = 0; int max_log_block = n.blocks / 2; if (!max_log_block) { max_log_block = 1; } dir_op_offset = 0; block_clear(&b); dir_entry * old_dot = NULL; dir_entry * dot = NULL; // Iterates dir entries while (index < max_log_block + 1) { old_dot = dot; dot = iterate_dir_entry(&b); if (dot == NULL) { if (index == max_log_block) { break; } log_block_read(&n,&index); dir_op_offset = 0; dot = NULL; index++; } else { int i = 0; ; if (inode == dot->inode) { int match = 1; int i = 0; int len = dot->name_len; for(; i < len; ++i) { iname[i] = dot->name[i]; } iname[i] = 0; return iname; } } } return 0; }
// Changes the inode's owner unsigned int fs_chown(char * filename, char * username) { int new_uid = user_exists(username); int current_uid = current_ttyc()->uid; int start_inode = current_ttyc()->pwd; int namenode = fs_indir(filename, start_inode); if (namenode && new_uid != -1) { inode_read(namenode, &n); if (n.uid == current_uid || current_uid == 0) { n.uid = new_uid; inode_write(namenode, &n); } else { return ERR_PERMS; } return 1; } else { return ERR_NO_EXIST; } }
int fs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi) { struct inode *dir = (struct inode *)fi->fh; struct dirent dent; int r; while ((r = inode_read(dir, &dent, sizeof(dent), offset)) > 0) { offset += r; if (dent.d_name[0] == '\0') continue; if (filler(buf, dent.d_name, NULL, offset) != 0) return 0; } dir->i_atime = time(NULL); flush_block(dir); return 0; }
int fs_read (fs_t *fs, int index, int offset, void *buffer, int len) { // assert (fs != NULL); // assert (index >= 0 && index < INODE_ARRAY_SIZE); // assert (buffer != NULL); // assert (offset >= 0); // assert (len >= 0); index_node_t *inode = &fs->super_block->inodes[index]; // assert (inode->in_use == 1); // EOF if (offset >= inode->size) return 0; int to_read = inode->size - offset; to_read = to_read > len ? len : to_read; return inode_read (fs->super_block, index, offset, buffer, to_read); }
// Tells if an name is inside the folder entries unsigned int fs_indir(char * name, int folder_inode) { inode_read(folder_inode, &n); int index = 0; int max_log_block = n.blocks / 2; if (!max_log_block) { max_log_block = 1; } dir_op_offset = 0; block_clear(&b); dir_entry * old_dot = NULL; dir_entry * dot = NULL; // Iterates dir entries while (index < max_log_block + 1) { old_dot = dot; dot = iterate_dir_entry(&b); if (dot == NULL) { if (index == max_log_block) { break; } log_block_read(&n,&index); dir_op_offset = 0; dot = NULL; index++; } else { int i = 0; ; int name_len = strlen(name); if (name_len == dot->name_len) { int match = 1; for (;name[i] && match; i++) { match = name[i] == dot->name[i]; } if (match) { return dot->inode; } } } } return 0; }
// Changes the directory int fs_cd(char * name) { int start_inode = current_ttyc()->pwd; int namenode = fs_indir(name, start_inode); if (namenode) { inode_read(namenode, &n); if(n.mode & EXT2_S_IFLNK) { if (bitmap_read(bm_inodes, n.data_blocks[0] - 1)) current_ttyc()->pwd = n.data_blocks[0]; else { return ERR_NO_EXIST; } } else { current_ttyc()->pwd = namenode; } return 1; } else { return ERR_NO_EXIST; } }
// 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; }
// 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; }
// Removes an inode from the filesystem, documented in header unsigned int fs_rm(unsigned int inode, int inside_recursion) { inode_read(inode, &n); if(!(inode > 1)) { return ERR_PERMS; // Permissions check } if(!fs_has_perms(&n, ACTION_WRITE)) { return ERR_PERMS; // If you can't write you can't delete... } if (!inside_recursion) { // I'm not sure about this, but well... at least it's just a security flaw. inode_read(n._dir_inode, &n); if(!fs_has_perms(&n, ACTION_WRITE)) { return ERR_PERMS; // If you can't write on the parent folder you can't delete } inode_read(inode, &n); } int log_block = n.blocks / 2 + 1; // Logical block top int ph_block = 0; // Go from top to bottom to delete everything. while(log_block > 0) { log_block--; make_ph_block(&n, &ph_block, &log_block); if (n.mode & EXT2_S_IFDIR) { // If it's a directory... then... RECURSION! D: block entries; data_read_block(&entries, ph_block); int off = 0; dir_op_offset = 0; dir_entry * old_dot = NULL; dir_entry * dot = iterate_dir_entry(&entries); // Iterates dir entries while (dot != NULL) { if (dot == NULL) { break; } else { if (dot->name_len > 0 && dot->inode != inode && dot->inode != n._dir_inode) { // If we get an error we don't actually make anything :D, but we might delete other files. int _rm = fs_rm(dot->inode, 1); if(_rm < 0) { data_write_block(&entries, ph_block); bitmap_write(bm_blocks, ph_block - 1, 0); return _rm; } off = dir_op_offset; dot->name_len = 0; dir_op_offset = off; inode_read(inode, &n); } } old_dot = dot; dot = iterate_dir_entry(&entries); } data_write_block(&entries, ph_block); } bitmap_write(bm_blocks, ph_block - 1, 0); // This deletes the stuff actually delete_internal_inodes(log_block); // This deletes the EXT2 ugly but wise indirects. } // Delete the directory entry of the file. if (!inside_recursion) { inode_read(inode, &n); unsigned int folder_inode = n._dir_inode; inode_read(folder_inode, &n); folder_rem_direntry(inode, folder_inode); } bitmap_write(bm_inodes, inode - 1, 0); // Persist the directory liberation. fs_bitmaps_write_all(); // Persist in the FS. return 1; }
// Filesystem Initialization void fs_init() { int i = 0; for (; i < sizeof(fs_data) / 4; i += 4) { ((int*)&dat)[i] = 0; } fs_sb_read(); sb = (super_block *) &dat.head._super; gbdt = (group_descriptor *) &dat.head._descriptors; // If the magic number is on then the fs is already loaded. if(sb->s_magic == 0xEF53) { fs_gbdt_read(); fs_bitmaps_init(); if (_FS_DEBUG) { inode_read(1, &n); int index = 0; int max_log_block = n.blocks / 2; if (!max_log_block) { max_log_block = 1; } dir_op_offset = 0; block_clear(&b); while (index < max_log_block + 1) { dir_entry * dot = iterate_dir_entry(&b); if (dot == NULL) { if (index == max_log_block) { break; } log_block_read(&n,&index); dir_op_offset = 0; index++; } else { int len = dot->name_len, i = 0; for (; i < len; i++) { printf("%c", dot->name[i]); } printf("\n"); } } } fs_bitmaps_write_all(); fs_gbdt_write(); fs_sb_write(); } else { printf("Preparing to start FS\n"); printf("Starting SB\n"); fs_sb_init(); printf("Starting GBDT\n"); fs_gbdt_init(); printf("Starting Bitmaps\n"); fs_bitmaps_init(); printf("Creating /\n"); int slash_inode = fs_mkdir("/", 1); printf("Creating /dev\n"); int dev_inode = fs_mkdir("dev", slash_inode); printf("Creating /home\n"); int home_inode = fs_mkdir("home", slash_inode); printf("Creating /root\n"); int root_inode = fs_mkdir("root", slash_inode); printf("Creating /etc\n"); int etc_inode = fs_mkdir("etc", slash_inode); printf("Creating /tmp\n"); int tmp_inode = fs_mkdir("tmp", slash_inode); printf("Creating /tmp/testfile\n"); int f1 = fs_open_reg_file("testfile", tmp_inode, O_NEW); printf("FS ended...\n"); printf("\tFree Blocks: %d\t Total Blocks: %d\n", bitmap_block_count(bm_blocks, FS_DATA_BITMAP_SIZE, 0), FS_DATA_BITMAP_SIZE); printf("\tFree Inodes: %d\t Total Inodes: %d\n", bitmap_block_count(bm_inodes, FS_INODE_BITMAP_SIZE, 0), FS_INODE_BITMAP_SIZE); fs_bitmaps_write_all(); fs_gbdt_write(); fs_sb_write(); } }
// Used to move a file unsigned int fs_mv(char * name, char * newname, int from_inode) { int i1 = fs_open_file(name, from_inode, O_WR | O_RD, EXT2_S_IFREG); if(i1 < 0) { return i1; // If there's an error with the first name then there's nothing to do actually. } int i2 = fs_indir(newname, from_inode); if(i2 == 0) { folder_rem_direntry(i1, n._dir_inode); inode_read(from_inode, &n); int 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, i1, newname, &log_block); log_block_write(&n, &log_block); n.blocks = log_block * 2; inode_write(from_inode, &n); return 1; } else { inode_read(i2, &n); if(!fs_has_perms(&n, ACTION_READ)) { return ERR_PERMS; } if(!(n.mode & EXT2_S_IFDIR)) { return ERR_INVALID_TYPE; } if (fs_indir(name, i2)) { return ERR_REPEATED; } int 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, i1, name, &log_block); log_block_write(&n, &log_block); n.blocks = log_block * 2; inode_write(i2, &n); inode_read(i1, &n); folder_rem_direntry(i1, n._dir_inode); inode_read(i1, &n); folder_rem_direntry(n._dir_inode, i1); log_block_read(&n, &log_block); add_dir_entry(&n, EXT2_FT_DIR, i2, "..", &log_block); log_block_write(&n, &log_block); n._dir_inode = i2; inode_write(i1, &n); } return i1; }
// Used to copy a file unsigned int fs_cp(char * name, char * newname, int from_inode, int to_inode) { int i1 = fs_open_file(name, from_inode, O_RD, EXT2_S_IFREG); if(i1 < 0) { return i1; // If there's an error with the first name then there's nothing to do actually. } inode_read(i1, &n); int i2; if(!(n.mode & EXT2_S_IFDIR)) { i2 = fs_open_file(newname, to_inode, O_WR, n.mode & (~EXT2_S_IFDIR)); inode_read(i1, &n); if(i2 < 0) { i2 = fs_open_file(newname, to_inode, O_WR | O_NEW , n.mode & (~EXT2_S_IFDIR)); } if(i2 < 0) { return ERR_EXISTS; } } else { i2 = fs_mkdir(newname, to_inode); if(i2 < 0) { return ERR_EXISTS; } } inode_read(i1, &n); block data; unsigned long offset = 0; while(fs_read_file(i1, (void *) &data, sizeof(block), &offset) > 0) { if(n.mode & EXT2_S_IFDIR) { int off = 0; dir_op_offset = 0; dir_entry * old_dot = NULL; dir_entry * dot = iterate_dir_entry(&data); // Iterates dir entries while (dot != NULL) { if (dot == NULL) { break; } else { if (dot->name_len > 0 && dot->inode != i1 && dot->inode != n._dir_inode && i2 != 0) { int _cp = fs_cp(dot->name, dot->name, i1, i2); if(_cp < 0) { return _cp; } off = dir_op_offset; dot->name_len = 0; dir_op_offset = off; } } old_dot = dot; dot = iterate_dir_entry(&data); } inode_read(i1, &n); } else { fs_write_file(i2, (void *)&data, sizeof(block)); } } return i2; }
// 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; }