📄 isofs.c
字号:
/*** Copyright 2001, Travis Geiselbrecht. All rights reserved.** Distributed under the terms of the NewOS License.*//* Initial coding by Ithamar Adema, 2001 */#include <kernel/kernel.h>#include <kernel/vfs.h>#include <kernel/khash.h> // for vnode hash table handling#include <kernel/heap.h> // for kmalloc / kfree#include <kernel/lock.h> // for mutex handling#include <kernel/vm.h>#include <string.h>#include "isovol.h"//================================================================================// DEBUGGING FUNCTIONALITY//================================================================================#include <kernel/console.h> // for kprintf#include <kernel/debug.h>#define ISOFS_TRACE 0#if ISOFS_TRACE#define TRACE(x) kprintf x#else#define TRACE(x)#endif//================================================================================// PRIVATE STRUCTURES FUNCTIONALITY//================================================================================#define ISOFS_HASH_SIZE 16// our private filesystem structurestruct isofs { int fd; // filedescriptor for ISO9660 file/dev fs_id id; // vfs filesystem id mutex lock; // lock int next_vnode_id; // next available vnode id void *vnode_list_hash; // hashtable of all used vnodes struct isofs_vnode *root_vnode; // pointer to private vnode struct of root dir of fs // ISO9660 stuff char volumename[33];// name of volume size_t blocksize; // Size of an ISO sector long numblocks; // Number of sectors on ISO image};//--------------------------------------------------------------------------------struct isofs_cookie { struct isofs_stream *s; int oflags; union { struct { off_t pos; // Position in directory/file data } file; struct { struct isofs_vnode* ptr; } dir; } u;};//--------------------------------------------------------------------------------// our private stream structurestruct isofs_stream { stream_type type; // is this stream a directory or file? off_t desc_pos; // position in ISO of dir descriptor off_t data_pos; // position in ISO of dir data size_t data_len; // length of data struct isofs_vnode *dir_head; // Pointer to first entry in directory};//--------------------------------------------------------------------------------// our private vnode structurestruct isofs_vnode { struct isofs_vnode *all_next; // next ptr of the global vnode linked-list (for hash) vnode_id id; // our mapping back to vfs vnodes char *name; // name of this vnode struct isofs_vnode *parent; // vnode of parent (directory) struct isofs_vnode *dir_next; // vnode of next entry in parent struct isofs_stream stream; // private stream info bool scanned; // true if dir has been scanned, false if not};static void iso_scan_dir(struct isofs* fs, struct isofs_vnode* dir);//--------------------------------------------------------------------------------static unsigned int isofs_vnode_hash_func(void *_v, const void *_key, unsigned int range){ struct isofs_vnode *v = _v; // convenience ptr to our vnode structure const vnode_id *key = _key; // convenience ptr to vfs vnode ID if(v != NULL) // If we've got a private vnode structure return v->id % range; // use that to calc hash value else // else return (*key) % range; // use kernel vnode id}//--------------------------------------------------------------------------------static int isofs_vnode_compare_func(void *_v, const void *_key){ struct isofs_vnode *v = _v; // convenience ptr to our vnode structure const vnode_id *key = _key; // convenience ptr to vfs vnode ID if(v->id == *key) // If the passed kernel vnode ID == private vnode ID return 0; // we're the same! else // else return -1; // nope, not equal :(}//--------------------------------------------------------------------------------static struct isofs_vnode *isofs_create_vnode(struct isofs *fs, const char *name){ struct isofs_vnode *v; // private vnode structure to be created // try to allocate our private vnode structure v = kmalloc(sizeof(struct isofs_vnode)); if(v == NULL) // return NULL if not able to return NULL; // initialize our vnode structure memset(v, 0, sizeof(struct isofs_vnode)); v->id = fs->next_vnode_id++; // copy name of vnode v->name = kmalloc(strlen(name) + 1); if(v->name == NULL) { kfree(v); return NULL; } strcpy(v->name, name); // return newly allocated private vnode structure return v;}//--------------------------------------------------------------------------------static int isofs_delete_vnode(struct isofs *fs, struct isofs_vnode *v, bool force_delete){ // cant delete it if it's in a directory or is a directory // and has children//TODO:// if(!force_delete && ((v->stream.type == STREAM_TYPE_DIR && v->stream.u.dir.dir_head != NULL) || v->dir_next != NULL)) {// return ERR_NOT_ALLOWED;// } // remove it from the global hash table hash_remove(fs->vnode_list_hash, v); // free name if any if(v->name != NULL) kfree(v->name); // free vnode structure itself kfree(v); // Tell caller all is ok return 0;}//--------------------------------------------------------------------------------static int isofs_insert_in_dir(struct isofs_vnode *dir, struct isofs_vnode *v){ if(dir->stream.type != STREAM_TYPE_DIR) return ERR_INVALID_ARGS; v->dir_next = dir->stream.dir_head; dir->stream.dir_head = v; v->parent = dir; return 0;}//--------------------------------------------------------------------------------static struct isofs_vnode* isofs_find_in_dir(struct isofs *fs, struct isofs_vnode* dir, const char* path){ struct isofs_vnode *v; if(dir->stream.type != STREAM_TYPE_DIR) return NULL; iso_scan_dir(fs, dir); for(v = dir->stream.dir_head; v; v = v->dir_next) { if(strcmp(v->name, path) == 0) { return v; } } return NULL;}//================================================================================// ISO9660 FORMAT HANDLING//================================================================================#define ISODIRENTRYBUF_SIZE sizeof(iso_dir_entry)+32static struct isofs_vnode* iso_add_entry(struct isofs* fs, struct isofs_vnode* parent, iso_dir_entry* e, off_t desc_pos){ struct isofs_vnode* v; char name[33]; // Create ASCIIZ name strncpy(name, e->name, e->nameLength); name[e->nameLength] = '\0'; // Create initial vnode v = isofs_create_vnode(fs,name); // Fill in the stream member of the vnode v->stream.type = (e->flags & 2) ? STREAM_TYPE_DIR : STREAM_TYPE_FILE; v->stream.desc_pos = desc_pos; v->stream.data_pos = e->dataStartSector[ISO_LSB_INDEX] * fs->blocksize; v->stream.data_len = e->dataLength[ISO_LSB_INDEX]; // Insert it into the hierarchy if (parent != NULL) { isofs_insert_in_dir(parent,v); } else { v->parent = v; } // Insert it into our hashing table hash_insert(fs->vnode_list_hash, v); return v;}//--------------------------------------------------------------------------------static void iso_scan_dir(struct isofs* fs, struct isofs_vnode* dir){ char entryBuf[ISODIRENTRYBUF_SIZE]; iso_dir_entry* e; off_t start, end; int cnt = 0; if (dir->scanned) { return; } start = dir->stream.data_pos; end = start + dir->stream.data_len; do { sys_read(fs->fd, entryBuf, start, ISODIRENTRYBUF_SIZE); e = (iso_dir_entry*)&entryBuf[0]; if (e->recordLength == 0) { break; } else { // Check for . and .. entries and correct name if (cnt == 0 && e->nameLength <= 1 && e->name[0] < 32) { strcpy(e->name, "."); e->nameLength = 1; } else if (cnt == 1 && e->nameLength <= 1 && e->name[0] < 32) { strcpy(e->name, ".."); e->nameLength = 2; } iso_add_entry(fs, dir, e, start); start += e->recordLength; ++cnt; } } while( start < end ); dir->scanned = true;}//--------------------------------------------------------------------------------static void iso_init_volume(struct isofs* fs){ iso_volume_descriptor voldesc; iso_dir_entry* e; // Read ISO9660 volume descriptor sys_read(fs->fd, &voldesc, ISO_VD_START, sizeof(voldesc)); // Copy volume name strncpy(fs->volumename, voldesc.volumeID, 32); fs->volumename[32] = '\0'; // Copy block size + # of blocks fs->blocksize = voldesc.sectorSize[ISO_LSB_INDEX]; fs->numblocks = voldesc.numSectors[ISO_LSB_INDEX]; // Get pointer to root directory entry e = (iso_dir_entry*)&voldesc.rootDirEntry[0]; // Setup our root directory fs->root_vnode = iso_add_entry(fs, NULL, e, ISO_VD_START + voldesc.rootDirEntry - &voldesc.type);}//================================================================================// VFS DRIVER API IMPLEMENTATION//================================================================================static int isofs_mount(fs_cookie *_fs, fs_id id, const char *device, void *args, vnode_id *root_vnid){ struct isofs *fs; struct isofs_vnode *v; int err; TRACE(("isofs_mount: entry\n")); fs = kmalloc(sizeof(struct isofs)); if(fs == NULL) { err = ERR_NO_MEMORY; goto err; } fs->id = id; fs->next_vnode_id = 0; // Try to open the ISO file to read fs->fd = sys_open(device, 0); if (fs->fd < 0) { err = fs->fd; goto err1; } err = mutex_init(&fs->lock, "isofs_mutex"); if(err < 0) { goto err1; } // Create and setup hash table fs->vnode_list_hash = hash_init(ISOFS_HASH_SIZE, offsetof(struct isofs_vnode, all_next), &isofs_vnode_compare_func, &isofs_vnode_hash_func); if(fs->vnode_list_hash == NULL) { err = ERR_NO_MEMORY; goto err2; } // Read the ISO9660 info, and create root vnode iso_init_volume(fs); *root_vnid = fs->root_vnode->id; *_fs = fs; return 0; isofs_delete_vnode(fs, v, true); hash_uninit(fs->vnode_list_hash);err2: mutex_destroy(&fs->lock);err1: kfree(fs);err: return err;}//--------------------------------------------------------------------------------static int isofs_unmount(fs_cookie _fs){ struct isofs *fs = _fs; struct isofs_vnode *v; struct hash_iterator i; TRACE(("isofs_unmount: entry fs = 0x%x\n", fs)); // delete all of the vnodes hash_open(fs->vnode_list_hash, &i); while((v = (struct isofs_vnode *)hash_next(fs->vnode_list_hash, &i)) != NULL) { isofs_delete_vnode(fs, v, true); } hash_close(fs->vnode_list_hash, &i, false); hash_uninit(fs->vnode_list_hash); mutex_destroy(&fs->lock); sys_close(fs->fd); kfree(fs); return 0;}//--------------------------------------------------------------------------------static int isofs_sync(fs_cookie fs){ TRACE(("isofs_sync: entry\n")); return 0;}//--------------------------------------------------------------------------------static int isofs_lookup(fs_cookie _fs, fs_vnode _dir, const char *name, vnode_id *id){ struct isofs *fs = (struct isofs *)_fs; struct isofs_vnode *dir = (struct isofs_vnode *)_dir; struct isofs_vnode *v; struct isofs_vnode *v1; int err; TRACE(("isofs_lookup: entry dir 0x%x, name '%s'\n", dir, name)); if(dir->stream.type != STREAM_TYPE_DIR) return ERR_VFS_NOT_DIR; mutex_lock(&fs->lock); // look it up v = isofs_find_in_dir(fs, dir, name); if(!v) { err = ERR_NOT_FOUND; goto err; } err = vfs_get_vnode(fs->id, v->id, (fs_vnode *)&v1); if(err < 0) { goto err; } *id = v->id; err = NO_ERROR;err: mutex_unlock(&fs->lock); return err;}//--------------------------------------------------------------------------------static int isofs_getvnode(fs_cookie _fs, vnode_id id, fs_vnode *v, bool r){ struct isofs *fs = (struct isofs *)_fs; TRACE(("isofs_getvnode: asking for vnode 0x%x 0x%x, r %d\n", id, r)); if(!r) mutex_lock(&fs->lock); *v = hash_lookup(fs->vnode_list_hash, &id); if(!r) mutex_unlock(&fs->lock); TRACE(("isofs_getnvnode: looked it up at 0x%x\n", *v)); if(*v) return 0; else return ERR_NOT_FOUND;}//--------------------------------------------------------------------------------static int isofs_putvnode(fs_cookie _fs, fs_vnode _v, bool r){ struct isofs_vnode *v = (struct isofs_vnode *)_v; TOUCH(v); TRACE(("isofs_putvnode: entry on vnode 0x%x 0x%x, r %d\n", v->id, r)); return 0; // whatever}static int isofs_removevnode(fs_cookie _fs, fs_vnode _v, bool r){ struct isofs *fs = (struct isofs *)_fs; struct isofs_vnode *v = (struct isofs_vnode *)_v; int err; TRACE(("isofs_removevnode: remove 0x%x (0x%x 0x%x), r %d\n", v, v->id, r)); if(!r) mutex_lock(&fs->lock); if(v->dir_next) { // can't remove node if it's linked to the dir panic("isofs_removevnode: vnode %p asked to be removed is present in dir\n", v); } isofs_delete_vnode(fs, v, false); err = 0; if(!r) mutex_unlock(&fs->lock); return err;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -