⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pfat.c

📁 geekos 0.3.0简单的操作系统
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Pseudo-fat filesystem. * Copyright (c) 2003, Jeffrey K. Hollingsworth <hollings@cs.umd.edu> * Copyright (c) 2003,2004 David H. Hovemeyer <daveho@cs.umd.edu> * $Revision: 1.54 $ * * This is free software.  You are permitted to use, * redistribute, and modify it as specified in the file "COPYING". */#include <limits.h>#include <geekos/errno.h>#include <geekos/screen.h>#include <geekos/string.h>#include <geekos/malloc.h>#include <geekos/ide.h>#include <geekos/blockdev.h>#include <geekos/bitset.h>#include <geekos/vfs.h>#include <geekos/list.h>#include <geekos/synch.h>#include <geekos/pfat.h>/* * History: * 13-Nov-2003: Converted to use new block device API. * 17-Dec-2003: Rewrite to conform to new VFS layer * 19-Feb-2004: Cache and share PFAT_File objects, instead of *   allocating them repeatedly *//* * TODO: * - Support hierarchical directories *//* ---------------------------------------------------------------------- * Private functions * ---------------------------------------------------------------------- */#define PAGEFILE_FILENAME "/pagefile.bin"int debugPFAT = 0;#define Debug(args...) if (debugPFAT) Print("PFAT: " args)struct PFAT_File;DEFINE_LIST(PFAT_File_List, PFAT_File);/* * In-memory information describing a mounted PFAT filesystem. * This is kept in the fsInfo field of the Mount_Point. */struct PFAT_Instance {    bootSector fsinfo;    int *fat;    directoryEntry *rootDir;    directoryEntry rootDirEntry;    struct Mutex lock;    struct PFAT_File_List fileList;};/* * In-memory information for a particular open file. * In particular, this object contains a cache of the contents * of the file. * Kept in fsInfo field of File. */struct PFAT_File {    directoryEntry *entry;		 /* Directory entry of the file */    ulong_t numBlocks;			 /* Number of blocks used by file */    char *fileDataCache;		 /* File data cache */    struct Bit_Set *validBlockSet;	 /* Which data blocks of cache are valid */    struct Mutex lock;			 /* Synchronize concurrent accesses */    DEFINE_LINK(PFAT_File_List, PFAT_File);};IMPLEMENT_LIST(PFAT_File_List, PFAT_File);/* * Copy file metadata from directory entry into * struct VFS_File_Stat object. */static void Copy_Stat(struct VFS_File_Stat *stat, directoryEntry *entry){    stat->size = entry->fileSize;    stat->isDirectory = entry->directory;    stat->isSetuid = 0;    memset(&stat->acls, '\0', sizeof(stat->acls));    stat->acls[0].uid = 0;    stat->acls[0].permission = O_READ;    if (!entry->readOnly)	stat->acls[0].permission |= O_WRITE;}/* * FStat function for PFAT files. */static int PFAT_FStat(struct File *file, struct VFS_File_Stat *stat){    struct PFAT_File *pfatFile = (struct PFAT_File*) file->fsData;    Copy_Stat(stat, pfatFile->entry);    return 0;}/* * Read function for PFAT files. */static int PFAT_Read(struct File *file, void *buf, ulong_t numBytes){    struct PFAT_File *pfatFile = (struct PFAT_File*) file->fsData;    struct PFAT_Instance *instance = (struct PFAT_Instance*) file->mountPoint->fsData;    ulong_t start = file->filePos;    ulong_t end = file->filePos + numBytes;    ulong_t startBlock, endBlock, curBlock;    ulong_t i;    /* Special case: can't handle reads longer than INT_MAX */    if (numBytes > INT_MAX)	return EINVALID;    /* Make sure request represents a valid range within the file */    if (start >= file->endPos || end > file->endPos || end < start) {	Debug("Invalid read position: filePos=%lu, numBytes=%lu, endPos=%lu\n",	    file->filePos, numBytes, file->endPos);	return EINVALID;    }    /*     * Now the complicated part; ensure that all blocks containing the     * data we need are in the file data cache.     */    startBlock = (start % SECTOR_SIZE) / SECTOR_SIZE;    endBlock = Round_Up_To_Block(end) / SECTOR_SIZE;    /*     * Traverse the FAT finding the blocks of the file.     * As we encounter requested blocks that aren't in the     * file data cache, we issue requests to read them.     */    curBlock = pfatFile->entry->firstBlock;    for (i = 0; i < endBlock; ++i) {	/* Are we at a valid block? */	if (curBlock == FAT_ENTRY_FREE || curBlock == FAT_ENTRY_EOF) {	    Print("Unexpected end of file in FAT at file block %lu\n", i);	    return EIO;  /* probable filesystem corruption */	}	/* Do we need to read this block? */	if (i >= startBlock) {	    int rc = 0;	    /* Only allow one thread at a time to read this block. */	    Mutex_Lock(&pfatFile->lock);	    if (!Is_Bit_Set(pfatFile->validBlockSet, i)) {		/* Read block into the file data cache */		Debug("Reading file block %lu (device block %lu)\n", i, curBlock);		rc = Block_Read(file->mountPoint->dev, curBlock, pfatFile->fileDataCache + i*SECTOR_SIZE);		if (rc == 0)		    /* Mark as having read this block */		    Set_Bit(pfatFile->validBlockSet, i);	    }	    /* Done attempting to fetch the block */	    Mutex_Unlock(&pfatFile->lock);	    if (rc != 0)		return rc;	}	/* Continue to next block */	ulong_t nextBlock = instance->fat[curBlock];	curBlock = nextBlock;    }    /*     * All cached data we need is up to date,     * so just copy it into the caller's buffer.     */    memcpy(buf, pfatFile->fileDataCache + start, numBytes);    Debug("Read satisfied!\n");    return numBytes;}/* * Write function for PFAT files. */static int PFAT_Write(struct File *file, void *buf, ulong_t numBytes){    /* Read only fs: writes not allowed */    return EACCESS;}/* * Seek function for PFAT files. */static int PFAT_Seek(struct File *file, ulong_t pos){    if (pos >= file->endPos)	return EINVALID;     file->filePos = pos;     return 0;}/* * Close function for PFAT files. */static int PFAT_Close(struct File *file){    /*     * The PFAT_File object caching the contents of the file     * will remain in the PFAT_Instance object, to speed up     * future accesses to this file.     */    return 0;}/* * Clone a file. * The clone will access the same underlying file as the * original, but read/write/seek operations, etc. will be distinct. * Returns 0 if successful, or an error code if unsuccessful. */static int PFAT_Clone(struct File *file, struct File **pClone){    int rc = 0;    struct File *clone;    /* Create a duplicate File object. */    clone = Allocate_File(file->ops, file->filePos, file->endPos, file->fsData, file->mode, file->mountPoint);    if (clone == 0) {	rc = ENOMEM;	goto done;    }    *pClone = clone;done:    return rc;}/* * File_Ops for PFAT files. */static struct File_Ops s_pfatFileOps = {    &PFAT_FStat,    &PFAT_Read,    &PFAT_Write,    &PFAT_Seek,    &PFAT_Close,    0, /* Read_Entry */    &PFAT_Clone,};static int PFAT_FStat_Dir(struct File *dir, struct VFS_File_Stat *stat){    /* FIXME: for now, there is only one directory */    struct PFAT_Instance *instance = (struct PFAT_Instance*) dir->mountPoint->fsData;    Copy_Stat(stat, &instance->rootDirEntry);    return 0;}/* * Close function for PFAT directories. */static int PFAT_Close_Dir(struct File *dir){    /* This is a no-op. */    return 0;}/* * Read a directory entry. */static int PFAT_Read_Entry(struct File *dir, struct VFS_Dir_Entry *entry){    directoryEntry *pfatDirEntry;    struct PFAT_Instance *instance = (struct PFAT_Instance*) dir->mountPoint->fsData;    if (dir->filePos >= dir->endPos)	return VFS_NO_MORE_DIR_ENTRIES; /* Reached the end of the directory. */    pfatDirEntry = &instance->rootDir[dir->filePos++];    /*     * Note: we don't need to bounds check here, because     * generic struct VFS_Dir_Entry objects have much more space for filenames     * than PFAT directoryEntry objects.     */    strncpy(entry->name, pfatDirEntry->fileName, sizeof(pfatDirEntry->fileName));    entry->name[sizeof(pfatDirEntry->fileName)] = '\0';    Copy_Stat(&entry->stats, pfatDirEntry);    return 0;}/* * File_Ops for PFAT directories. */static struct File_Ops s_pfatDirOps = {    &PFAT_FStat_Dir,    0, /* Read */    0, /* Write */    0, /* Seek */    &PFAT_Close_Dir,    &PFAT_Read_Entry,};/* * Look up a directory entry in a PFAT filesystem. */static directoryEntry *PFAT_Lookup(struct PFAT_Instance *instance, const char *path){    directoryEntry *rootDir = instance->rootDir;    bootSector *fsinfo = &instance->fsinfo;    int i;    KASSERT(*path == '/');    /* Special case: root directory. */    if (strcmp(path, "/") == 0)	return &instance->rootDirEntry;    /* Skip leading '/' character. */    ++path;    /*     * FIXME: Eventually, we should try to implement hierarchical     * directory structure.  For now, only the root directory     * is supported.     */    for (i = 0; i < fsinfo->rootDirectoryCount; ++i) {    	directoryEntry *entry = &rootDir[i];	if (strcmp(entry->fileName, path) == 0) {	    /* Found it! */	    Debug("Found matching dir entry for %s\n", path);	    return entry;	}    }    /* Not found. */    return 0;}/* * Get a PFAT_File object representing the file whose directory entry * is given. */static struct PFAT_File *Get_PFAT_File(struct PFAT_Instance *instance, directoryEntry *entry){    ulong_t numBlocks;    struct PFAT_File *pfatFile = 0;    char *fileDataCache = 0;    struct Bit_Set *validBlockSet = 0;    KASSERT(entry != 0);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -