📄 pfat.c
字号:
/* * 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 + -