/** * rename from_file to to_file * works for dirs as well as files * cannot rename to something that already exists * @param from_file * @param to_file * @return 1 on success, 0 on failure */ int mfs_rename_file(char *from_file, char *to_file) { int from_dir_block; int to_dir_block; int from_dir_index; int to_dir_index; int reuse_block = -1; int reuse_index = -1; if (get_dir_ent(from_file, &from_dir_block, &from_dir_index, &reuse_block, &reuse_index) && !get_dir_ent(to_file, &to_dir_block, &to_dir_index, &reuse_block, &reuse_index)) { set_filename(mfs_file_system[from_dir_block].u.dir_data.dir_ent[from_dir_index].name, get_basename(to_file)); return 1; } return 0; }
/** * open a file * @param filename is the name of the file to open * @param mode is MFS_MODE_READ or MFS_MODE_WRITE or MFS_MODE_CREATE * this function should be used for FILEs and not DIRs * no error checking (is this FILE and not DIR?) is done for MFS_MODE_READ * MFS_MODE_CREATE automatically creates a FILE and not a DIR * MFS_MODE_WRITE fails if the specified file is a DIR * @return index of file in array mfs_open_files or -1 */ int mfs_file_open(const char *filename, int mode) { int dir_block; int dir_index; int current_index; int reuse_block = -1; int reuse_index = -1; //xil_printf("In mfs_file_open\r\n"); if (mfs_num_open_files >= MFS_MAX_OPEN_FILES) {/* cannot open any more files */ //xil_printf("case 1\r\n"); return -1; } if (mode == MFS_MODE_READ || mode == MFS_MODE_WRITE) { /* look for existing file */ if (get_dir_ent(filename, &dir_block, &dir_index, &reuse_block, &reuse_index)) { /* found it */ if (mode == MFS_MODE_WRITE && mfs_file_system[mfs_file_system[dir_block].u.dir_data.dir_ent[dir_index].index].block_type != MFS_BLOCK_TYPE_FILE) { /* cannot open anything other than FILE for write */ //xil_printf("case 2\r\n"); return -1; } mfs_num_open_files++; current_index = get_first_free_ftab_index(); mfs_open_files[current_index].first_block = mfs_file_system[dir_block].u.dir_data.dir_ent[dir_index].index; mfs_open_files[current_index].current_block = mfs_open_files[current_index].first_block; mfs_open_files[current_index].mode = mode; mfs_open_files[current_index].offset = 0; return current_index; } else { //file/dir not found, open it in create mode if (mode == MFS_MODE_WRITE) mode = MFS_MODE_CREATE; } } if (mode == MFS_MODE_CREATE) { /* create a new file */ dir_block = create_file(filename, MFS_BLOCK_TYPE_FILE); if (dir_block == 0) { /* failed to create the file */ //xil_printf("case 3\r\n"); return -1; } mfs_num_open_files++; current_index = get_first_free_ftab_index(); mfs_open_files[current_index].first_block = dir_block; mfs_open_files[current_index].current_block = dir_block; mfs_open_files[current_index].mode = MFS_MODE_WRITE; mfs_open_files[current_index].offset = 0; //xil_printf("case 4, current_index is %d\r\n",current_index); return current_index; } //xil_printf("case 5\r\n"); return -1; }
/** * modify global mfs_current_dir to index of newdir if it exists * mfs_current_dir is not modified otherwise * @param newdir is the name of the new directory * @return 1 for success and 0 for failure */ int mfs_change_dir(const char *newdir) { /* search current dir for newdir and change current dir if found */ /* return 1 for success, 0 for failure */ int new_dir_block; int new_dir_index; int reuse_block = -1; int reuse_index = -1; if (get_dir_ent(newdir, &new_dir_block, &new_dir_index, &reuse_block, &reuse_index)) { mfs_current_dir = mfs_file_system[new_dir_block].u.dir_data.dir_ent[new_dir_index].index; return 1; } return 0; }
/** * check if a file exists * @param filename is the name of the file * @return 0 if filename is not a file in the current directory * @return 1 if filename is a file in the current directory * @return 2 if filename is a directory in the current directory */ int mfs_exists_file(char *filename) { int dir_block; int dir_index; int file_block; int reuse_block = -1; int reuse_index = -1; if (get_dir_ent(filename, &dir_block, &dir_index, &reuse_block, &reuse_index)) { file_block = mfs_file_system[dir_block].u.dir_data.dir_ent[dir_index].index; if (mfs_file_system[file_block].block_type == MFS_BLOCK_TYPE_DIR) return 2; else if (mfs_file_system[file_block].block_type == MFS_BLOCK_TYPE_FILE) return 1; else return 0; } return 0; }
/** * delete a file * @param filename is the name of the file to be deleted * delete the data blocks corresponding to the file and then delete the * file entry from its directory * @return 1 on success, 0 on failure * delete will not work on a directory unless the directory is empty */ int mfs_delete_file (char *filename) { int dir_block; int dir_index; int entry_index; int first_dir_block; int reuse_block = -1; int reuse_index = -1; if (!get_dir_ent(filename, &dir_block, &dir_index, &reuse_block, &reuse_index)) { /* file does not exist */ return 0 ; /* cannot delete file if it does not exist */ } entry_index = mfs_file_system[dir_block].u.dir_data.dir_ent[dir_index].index; if (delete_data_in_file(entry_index)) { /* now delete the file entry from the directory */ mfs_file_system[dir_block].u.dir_data.dir_ent[dir_index].deleted = 'y'; mfs_file_system[dir_block].u.dir_data.num_deleted += 1; first_dir_block = get_first_dir_block(dir_block); if (dir_block != first_dir_block) mfs_file_system[first_dir_block].u.dir_data.num_deleted += 1; } return 1; }
int load(char* fn, void* data, size_t ds){ struct fs *the_fs = malloc(sizeof(struct fs)); int ret = 5; load_fs(the_fs); struct dir_ent file_ent; if(get_dir_ent(&the_fs->root_dir, fn, &file_ent)) { ret = NOT_FOUND; goto error; } unsigned short addr = file_ent.file_addr; unsigned short next_addr = 0; size_t offset = 0; int cyl, sect; while(!get_next_addr(&the_fs->the_fat, addr, &next_addr) && offset < ds) { cyl = to_cylinder_number(addr); sect = to_sector_number(addr); read_sector(cyl, sect, data + offset); offset += BYTES_PER_SECTOR; addr = next_addr; } if(offset >= ds) { printf("looks like data cant hold the whole file!\n"); goto error; } cyl = to_cylinder_number(addr); sect = to_sector_number(addr); char leftover[BYTES_PER_SECTOR]; read_sector(cyl, sect, leftover); size_t to_read = (ds - offset > BYTES_PER_SECTOR) ? BYTES_PER_SECTOR-1 : ds - offset; memcpy(data + offset, leftover, to_read); ret = 0; error: free(the_fs); return ret; }
int save(char* fn, void* data, size_t ds){ struct fs *the_fs = malloc(sizeof(struct fs)); int ret = 5; load_fs(the_fs); struct dir_ent file_ent; unsigned short n = ds / BYTES_PER_SECTOR + 1; unsigned short *free_sectors = malloc(sizeof(unsigned short) * n); if(!get_dir_ent(&the_fs->root_dir, fn, &file_ent)) { ret = NAME_CONFLICT; goto error; }; if(getn_free_sectors(&the_fs->the_fat, n, free_sectors)) { //printf("Looks like there aren't %d sectors available!\n", n); ret = NO_SPACE; goto error; } // now we actually store our file size_t offset = 0; unsigned short addr, next_addr; int cyl, sect; addr = free_sectors[0]; // set the initial root_dir entry if(set_dir_ent(&the_fs->root_dir, fn, addr)) { printf("So we couldn't find an available space in our root_dir\n"); ret = NO_SPACE; goto error; } for(int i = 0; i < n-1; ++i) { addr = free_sectors[i]; next_addr = free_sectors[i+1]; cyl = to_cylinder_number(addr); sect = to_sector_number(addr); if(set_fat_entry_value(&the_fs->the_fat, addr, next_addr)) { printf("Apparently %d is not a valid address!\n", next_addr); goto error; } if(write_sector(cyl, sect, data + offset)) { printf("Something went wrong with write_sector\n"); goto error; } offset += BYTES_PER_SECTOR; } char leftover[BYTES_PER_SECTOR]; memcpy(leftover, data + offset, ds - offset); addr = free_sectors[n-1]; cyl = to_cylinder_number(addr); sect = to_sector_number(addr); if(set_fat_entry_value(&the_fs->the_fat, addr, END_OF_FILE)) { printf("We couldn't set the last addr to END_OF_FILE!\n"); goto error; } if(write_sector(cyl, sect, leftover)) { printf("Something went wrong with writing the last bit of data!\n"); goto error; } ret = 0; error: store_fs(the_fs); free(the_fs); free(free_sectors); return ret; }
/** * Create a new file or dir named filename * If a dir or file of the same name exists, return 0 * If there is no space on the file system to create file, return 0 * else create the new file or dir, add entry in current dir table * and return index of first block of file or dir * @param filename is name of file to create * @param file_type is either MFS_BLOCK_TYPE_DIR (for directory) or MFS_BLOCK_TYPE_FILE (for a regular file) * @return 1 for success and 0 for failure */ static int create_file(const char *filename, int file_type) { int new_dir_block; int new_dir_index; int new_entry_index; int new_block; int first_dir_block; int reuse_block = -1; int reuse_index = -1; int reusing = 0; if (get_dir_ent(filename, &new_dir_block, &new_dir_index, &reuse_block, &reuse_index)) { //xil_printf("Case 10\r\n"); /* file already exists */ return 0 ; /* cannot create file if it already exists */ } else if (new_dir_block == -1 || new_dir_index == -1) { /* file does not exist but path prefix does not exist either */ //xil_printf("Case 11\r\n"); return 0; /* cannot create file because its parent dir does not exist */ } else { /* create the file */ /* first check if there is a reusable entry */ if ((reuse_block != -1) && (reuse_index != -1)) { /* found an entry to reuse */ new_dir_index = reuse_index; new_dir_block = reuse_block; reusing = 1; } else { /* check if the current dir block is full and allocate a new dir block if needed */ if (new_dir_index == MFS_MAX_LOCAL_ENT) { /* create a new dir block linked from this one */ if (get_next_free_block(&new_block)) { /* found a free block */ mfs_file_system[new_block].prev_block = new_dir_block; mfs_file_system[new_block].next_block = 0; mfs_file_system[new_block].block_type = MFS_BLOCK_TYPE_DIR; mfs_file_system[new_block].u.dir_data.num_entries = 0; mfs_file_system[new_block].u.dir_data.num_deleted = 0; mfs_file_system[new_dir_block].next_block = new_block; new_dir_block = new_block; new_dir_index = 0; } else { /* no space for new block - return failure */ //xil_printf("Case 12\r\n"); return 0; } } } /* at this point new_dir_index and new_dir_block both point to the first free entry */ first_dir_block = get_first_dir_block(new_dir_block); if (!create_new_file(file_type, &new_entry_index, first_dir_block)) { /* cannot create new file */ //xil_printf("Case 13\r\n"); return 0; /* failure */ }; if (reusing != 1) { /* update number of entries in current block */ mfs_file_system[new_dir_block].u.dir_data.num_entries += 1; /* update number of entries in directory if it is different than current block */ if (new_dir_block != first_dir_block) mfs_file_system[first_dir_block].u.dir_data.num_entries += 1; } mfs_file_system[new_dir_block].u.dir_data.dir_ent[new_dir_index].index = new_entry_index; set_filename(mfs_file_system[new_dir_block].u.dir_data.dir_ent[new_dir_index].name, get_basename(filename)); mfs_file_system[new_dir_block].u.dir_data.dir_ent[new_dir_index].deleted = 'n'; //xil_printf("Case 14\r\n"); return new_entry_index; } }