bool filesys_create (const char *path, off_t initial_size, enum FILE_TYPE type, uint32_t permission){ struct block *d = NULL; struct ext2_meta_data *meta = NULL; char *parent = NULL, *name = NULL; struct directory *parent_dir = NULL; struct file *parent_file = NULL; struct directory *directory_data = NULL; struct directory *last_entry = NULL; uint32_t file_size = 0, bytes_read = 0; uint32_t inode_num; struct inode inode; int err, i; bool success = false; ASSERT(path != NULL && initial_size >= 0); // Get device d = block_get_role (BLOCK_FILESYS); ASSERT(d != NULL); meta = ext2_get_meta(d); ASSERT(meta != NULL && meta->sb != NULL); // Check if file already exists! directory_data = dir_lookup(d,path); if(directory_data != NULL){ // file exists printf("File %s exists!.\n",path); goto cleanup; } // Split path filesys_split_path(path, &parent, &name); ASSERT(parent != NULL && name != NULL); // Get parent directory parent_dir = dir_lookup(d,parent); if(parent_dir == NULL){ printf("Directory %s does not exist.\n",parent); goto cleanup; } // Check file type if(parent_dir -> file_type != EXT2_FT_DIR){ printf("Path %s is not a directory.\n",parent); goto cleanup; } // Get directory file parent_file = filesys_open(parent); if(parent_file == NULL) goto cleanup; // Get parent directory data file_size = parent_file->inode->i_size; directory_data = kmalloc(file_size); bytes_read = file_read(parent_file,directory_data,file_size); if(bytes_read != file_size) goto cleanup; // Get last entry last_entry = directory_data; do { last_entry = dir_get_next(last_entry); } while (last_entry != NULL && last_entry->inode != 0 && (uint8_t*)last_entry+last_entry->rec_len < (uint8_t*)directory_data+file_size); // check if pointer passed file limit if(last_entry == NULL || (uint8_t*)last_entry >= (uint8_t*)directory_data+file_size) goto cleanup; // Get free inode inode_num = freemap_get_inode(); if(inode_num == FREEMAP_GET_ERROR) goto cleanup; // Recalibrate record length if(last_entry->inode != 0){ last_entry->rec_len = sizeof(struct directory) - (UINT8_MAX - last_entry->name_len); // Align 4 bytes i = last_entry->rec_len % 4; if(i > 0) last_entry->rec_len += (4-i); } // Goto new last entry last_entry = dir_get_next(last_entry); if(last_entry == NULL || (uint8_t*)last_entry >= (uint8_t*)directory_data+file_size) goto cleanup; // Create inode memset(&inode,0,sizeof(struct inode)); inode.i_mode = EXT2_S_IFREG | permission; inode.i_links_count = 1; err = inode_resize(&inode,initial_size); if(err < 0) goto cleanup; // Write inode to disk ext2_write_inode(d,inode_num,&inode); // Create file entry memset(last_entry,0,sizeof(struct directory)); last_entry->inode = inode_num; last_entry->name_len = strlen(name); if(last_entry->name_len > UINT8_MAX) last_entry->name_len = UINT8_MAX; memcpy(last_entry->name,name, last_entry->name_len); switch(type){ case FILESYS_REGULAR: last_entry -> file_type = EXT2_FT_REG_FILE; break; case FILESYS_DIRECTORY: last_entry -> file_type = EXT2_FT_DIR; break; default: last_entry -> file_type = EXT2_FT_UNKNOWN; break; }; last_entry->rec_len = ext2_get_block_size(meta->sb) - (uint32_t)((uintptr_t)last_entry - (uintptr_t) directory_data); // Write directory file file_write_at(parent_file,directory_data,file_size,0); // file created successfully. success = true; cleanup: // close file if(parent_file != NULL) file_close(parent_file); // release memory if(parent != NULL) kfree(parent); if(name != NULL) kfree(name); if(parent_dir != NULL) kfree(parent_dir); if(directory_data != NULL) kfree(directory_data); return success; }
bool ext2_add_entry( PEXT2_FILESYS Ext2Sys, ULONG parent, ULONG inode, int filetype, char *name ) { PEXT2_DIR_ENTRY2 dir = NULL, newdir = NULL; EXT2_INODE parent_inode; ULONG dwRet; char *buf; int rec_len; bool bRet = false; rec_len = EXT2_DIR_REC_LEN(strlen(name)); if (!ext2_load_inode(Ext2Sys, parent, &parent_inode)) { return false; } buf = (char *)RtlAllocateHeap(RtlGetProcessHeap(), 0, parent_inode.i_size); if (!ext2_read_inode(Ext2Sys, parent, 0, buf, parent_inode.i_size, &dwRet)) { return false; } dir = (PEXT2_DIR_ENTRY2) buf; while ((char *)dir < buf + parent_inode.i_size) { if ((dir->inode == 0 && dir->rec_len >= rec_len) || (dir->rec_len >= dir->name_len + rec_len) ) { if (dir->inode) { newdir = (PEXT2_DIR_ENTRY2) ((PUCHAR)dir + EXT2_DIR_REC_LEN(dir->name_len)); newdir->rec_len = dir->rec_len - EXT2_DIR_REC_LEN(dir->name_len); dir->rec_len = EXT2_DIR_REC_LEN(dir->name_len); dir = newdir; } dir->file_type = filetype; dir->inode = inode; dir->name_len = strlen(name); memcpy(dir->name, name, strlen(name)); bRet = true; break; } dir = (PEXT2_DIR_ENTRY2) (dir->rec_len + (PUCHAR) dir); } if (bRet) return ext2_write_inode(Ext2Sys, parent, 0, buf, parent_inode.i_size, &dwRet); return bRet; }
bool filesys_remove (const char *path){ struct block *d = NULL; struct ext2_meta_data *meta = NULL; char *parent = NULL, *name = NULL; struct directory *parent_dir = NULL; struct file *parent_file = NULL, *file = NULL; struct directory *directory_data = NULL; struct directory *file_entry = NULL, *last_entry = NULL; uint32_t file_size = 0, bytes_read = 0; bool success = false; ASSERT(path != NULL && strlen(path) > 0); // Get device d = block_get_role (BLOCK_FILESYS); ASSERT(d != NULL); meta = ext2_get_meta(d); ASSERT(meta != NULL && meta->sb != NULL); // open file file = filesys_open(path); if(file == NULL){ // file does not exists printf("filesys_remove: %s does not exist!.\n",path); goto cleanup; } //Check file type if(file->dir->file_type != EXT2_FT_REG_FILE){ printf("filesys_remove %s is not a regular file.\n",path); goto cleanup; } // Split path filesys_split_path(path, &parent, &name); ASSERT(parent != NULL && name != NULL); // Get parent directory parent_dir = dir_lookup(d,parent); if(parent_dir == NULL){ printf("Directory %s does not exist.\n",parent); goto cleanup; } // Check parent type if(parent_dir -> file_type != EXT2_FT_DIR){ printf("Path %s is not a directory.\n",parent); goto cleanup; } // Get directory file parent_file = filesys_open(parent); if(parent_file == NULL) goto cleanup; // Get parent directory data file_size = parent_file->inode->i_size; directory_data = kmalloc(file_size); bytes_read = file_read(parent_file,directory_data,file_size); if(bytes_read != file_size) goto cleanup; // Get file directory entry file_entry = directory_data; while (file_entry != NULL && memcmp(file_entry->name,name,file_entry->name_len) != 0 && (uint8_t*)file_entry+file_entry->rec_len < (uint8_t*)directory_data+file_size){ last_entry = file_entry; file_entry = dir_get_next(file_entry); } // check if file entry if found. if( (uint8_t*)file_entry >= (uint8_t*)directory_data+file_size || memcmp(file_entry->name,name,file_entry->name_len) != 0 ) goto cleanup; // Truncate file to zero length // Aka. Free blocks file_truncate(file,0); // Zero inode memset(file->inode,0,sizeof(struct inode)); ext2_write_inode(d,file->dir->inode,file->inode); // Free inode freemap_free_inode(file_entry->inode); // Delete directory record // Use last entry record length to skip file entry if(last_entry->inode != 0) last_entry->rec_len += file_entry->rec_len; // Write directory file file_write_at(parent_file,directory_data,file_size,0); // file deleted successfully. success = true; cleanup: // close file if(file != NULL) file_close(file); if(parent_file != NULL) file_close(parent_file); // release memory if(parent != NULL) kfree(parent); if(name != NULL) kfree(name); if(parent_dir != NULL) kfree(parent_dir); if(directory_data != NULL) kfree(directory_data); return success; }