From: John Hodge Date: Wed, 17 Mar 2010 06:08:43 +0000 (+0800) Subject: Various changes, most of them involving the FAT and Ext2 Drivers, adding write support X-Git-Tag: rel0.06~274 X-Git-Url: https://git.ucc.asn.au/?a=commitdiff_plain;h=923a9dc473851ec2bb1c94021bbf139724e7e8a5;hp=f4646f2b6d64e42d1eec1d97877ae23eac6863f6;p=tpg%2Facess2.git Various changes, most of them involving the FAT and Ext2 Drivers, adding write support - FAT Now has rudimentary write support (file size still isn't updated) - Added InitRD to the tree - Slight changes to the Module build system - Set modules to use -O3 and fixed the bugs that showed --- diff --git a/Kernel/Makefile.BuildNum b/Kernel/Makefile.BuildNum index c43737f4..db4b72be 100644 --- a/Kernel/Makefile.BuildNum +++ b/Kernel/Makefile.BuildNum @@ -1 +1 @@ -BUILD_NUM = 1526 +BUILD_NUM = 1531 diff --git a/Kernel/vfs/fs/fat.c b/Kernel/vfs/fs/fat.c deleted file mode 100644 index 32bff8d8..00000000 --- a/Kernel/vfs/fs/fat.c +++ /dev/null @@ -1,909 +0,0 @@ -/* - * Acess 2 - * FAT12/16/32 Driver Version (Incl LFN) - */ -#define DEBUG 0 -#define VERBOSE 1 - -#define CACHE_FAT 1 //!< Caches the FAT in memory -#define USE_LFN 1 //!< Enables the use of Long File Names - -#include -#include -#include -#include "fs_fat.h" - - -// === TYPES === -#if USE_LFN -typedef struct s_lfncache { - Uint Inode, Impl; - int id; - char Name[256]; - struct s_lfncache *Next; -} t_lfncache; -#endif - -// === PROTOTYPES === - int FAT_Install(char **Arguments); -tVFS_Node *FAT_InitDevice(char *device, char **options); -void FAT_Unmount(tVFS_Node *Node); -Uint64 FAT_Read(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer); -Uint64 FAT_Write(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer); -char *FAT_ReadDir(tVFS_Node *dirNode, int dirpos); -tVFS_Node *FAT_FindDir(tVFS_Node *dirNode, char *file); - int FAT_Mknod(tVFS_Node *Node, char *Name, Uint Flags); - int FAT_Relink(tVFS_Node *node, char *OldName, char *NewName); -void FAT_CloseFile(tVFS_Node *node); - -// === SEMI-GLOBALS === -MODULE_DEFINE(0, 0x51 /*v0.80*/, VFAT, FAT_Install, NULL, NULL); -tFAT_VolInfo gFAT_Disks[8]; - int giFAT_PartCount = 0; -#if USE_LFN -t_lfncache *fat_lfncache; -#endif -tVFS_Driver gFAT_FSInfo = { - "fat", 0, FAT_InitDevice, FAT_Unmount, NULL - }; - -// === CODE === -/** - * \fn int FAT_Install(char **Arguments) - * \brief - */ -int FAT_Install(char **Arguments) -{ - VFS_AddDriver( &gFAT_FSInfo ); - return MODULE_ERR_OK; -} - -/** - * \fn tVFS_Node *FAT_InitDevice(char *Device, char **options) - * \brief Reads the boot sector of a disk and prepares the structures for it - */ -tVFS_Node *FAT_InitDevice(char *Device, char **options) -{ - fat_bootsect *bs; - int i; - Uint32 FATSz, RootDirSectors, TotSec, CountofClusters; - tVFS_Node *node = NULL; - tFAT_VolInfo *diskInfo = &gFAT_Disks[giFAT_PartCount]; - - //Temporary Pointer - bs = &diskInfo->bootsect; - - //Open device and read boot sector - diskInfo->fileHandle = VFS_Open(Device, VFS_OPENFLAG_READ|VFS_OPENFLAG_WRITE); - if(diskInfo->fileHandle == -1) { - Warning("FAT_InitDisk - Unable to open device '%s'", Device); - return NULL; - } - - VFS_ReadAt(diskInfo->fileHandle, 0, 512, bs); - - if(bs->bps == 0 || bs->spc == 0) { - Warning("FAT_InitDisk - Error in FAT Boot Sector\n"); - return NULL; - } - - //FAT Type Determining - // From Microsoft FAT Specifcation - RootDirSectors = ((bs->files_in_root*32) + (bs->bps - 1)) / bs->bps; - - if(bs->fatSz16 != 0) FATSz = bs->fatSz16; - else FATSz = bs->spec.fat32.fatSz32; - - if(bs->totalSect16 != 0) TotSec = bs->totalSect16; - else TotSec = bs->totalSect32; - - CountofClusters = (TotSec - (bs->resvSectCount + (bs->fatCount * FATSz) + RootDirSectors)) / bs->spc; - - if(CountofClusters < 4085) - diskInfo->type = FAT12; - else if(CountofClusters < 65525) - diskInfo->type = FAT16; - else - diskInfo->type = FAT32; - - #if VERBOSE - { - char *sFatType, *sSize; - Uint iSize = CountofClusters * bs->spc / 2; - - switch(diskInfo->type) - { - case FAT12: sFatType = "FAT12"; break; - case FAT16: sFatType = "FAT16"; break; - case FAT32: sFatType = "FAT32"; break; - default: sFatType = "UNKNOWN"; break; - } - if(iSize <= 2*1024) { - sSize = "KiB"; - } - else if(iSize <= 2*1024*1024) { - sSize = "MiB"; - iSize >>= 10; - } - else { - sSize = "GiB"; - iSize >>= 20; - } - Log("[FAT ] '%s' %s, %i %s", Device, sFatType, iSize, sSize); - } - #endif - - //Get Name - if(diskInfo->type == FAT32) { - for(i=0;i<11;i++) - diskInfo->name[i] = (bs->spec.fat32.label[i] == ' ' ? '\0' : bs->spec.fat32.label[i]); - } - else { - for(i=0;i<11;i++) - diskInfo->name[i] = (bs->spec.fat16.label[i] == ' ' ? '\0' : bs->spec.fat16.label[i]); - } - diskInfo->name[11] = '\0'; - - //Compute Root directory offset - if(diskInfo->type == FAT32) - diskInfo->rootOffset = bs->spec.fat32.rootClust; - else - diskInfo->rootOffset = (FATSz * bs->fatCount) / bs->spc; - - diskInfo->clusterCount = CountofClusters; - - diskInfo->firstDataSect = bs->resvSectCount + (bs->fatCount * FATSz) + RootDirSectors; - - //Allow for Caching the FAT - #if CACHE_FAT - { - Uint32 Ofs; - diskInfo->FATCache = (Uint32*)malloc(sizeof(Uint32)*CountofClusters); - if(diskInfo->FATCache == NULL) { - Warning("FAT_InitDisk - Heap Exhausted\n"); - return NULL; - } - Ofs = bs->resvSectCount*512; - if(diskInfo->type == FAT12) { - Uint32 val; - int j; - char buf[1536]; - for(i=0;ifileHandle, Ofs, 3*512, buf); - Ofs += 3*512; - } - val = *((int*)(buf+j*3)); - diskInfo->FATCache[i*2] = val & 0xFFF; - diskInfo->FATCache[i*2+1] = (val>>12) & 0xFFF; - } - } - if(diskInfo->type == FAT16) { - Uint16 buf[256]; - for(i=0;ifileHandle, Ofs, 512, buf); - Ofs += 512; - } - diskInfo->FATCache[i] = buf[i&255]; - } - } - if(diskInfo->type == FAT32) { - Uint32 buf[128]; - for(i=0;ifileHandle, Ofs, 512, buf); - Ofs += 512; - } - diskInfo->FATCache[i] = buf[i&127]; - } - } - LOG("FAT Fully Cached"); - } - #endif /*CACHE_FAT*/ - - //Initalise inode cache for FAT - diskInfo->inodeHandle = Inode_GetHandle(); - LOG("Inode Cache handle is %i", diskInfo->inodeHandle); - - // == VFS Interface - node = &diskInfo->rootNode; - node->Inode = diskInfo->rootOffset; - node->Size = bs->files_in_root; // Unknown - To be set on readdir - node->ImplInt = giFAT_PartCount; - - node->ReferenceCount = 1; - - node->UID = 0; node->GID = 0; - node->NumACLs = 1; - node->ACLs = &gVFS_ACL_EveryoneRWX; - node->Flags = VFS_FFLAG_DIRECTORY; - node->CTime = node->MTime = node->ATime = now(); - - node->Read = node->Write = NULL; - node->ReadDir = FAT_ReadDir; - node->FindDir = FAT_FindDir; - node->Relink = FAT_Relink; - node->MkNod = FAT_Mknod; - //node->Close = FAT_CloseDevice; - - giFAT_PartCount ++; - return node; -} - -/** - * \fn void FAT_Unmount(tVFS_Node *Node) - * \brief Closes a mount and marks it as free - */ -void FAT_Unmount(tVFS_Node *Node) -{ - // Close Disk Handle - VFS_Close( gFAT_Disks[Node->ImplInt].fileHandle ); - // Clear Node Cache - Inode_ClearCache(gFAT_Disks[Node->ImplInt].inodeHandle); - // Mark as unused - gFAT_Disks[Node->ImplInt].fileHandle = -2; - return; -} - -/** - * \fn static Uint32 FAT_int_GetFatValue(tFAT_VolInfo *Disk, Uint32 cluster) - * \brief Fetches a value from the FAT - */ -static Uint32 FAT_int_GetFatValue(tFAT_VolInfo *Disk, Uint32 cluster) -{ - Uint32 val = 0; - #if !CACHE_FAT - Uint32 ofs = Disk->bootsect.resvSectCount*512; - #endif - ENTER("pDisk xCluster", Disk, cluster); - #if CACHE_FAT - val = Disk->FATCache[cluster]; - if(Disk->type == FAT12 && val == EOC_FAT12) val = -1; - if(Disk->type == FAT16 && val == EOC_FAT16) val = -1; - if(Disk->type == FAT32 && val == EOC_FAT32) val = -1; - #else - if(Disk->type == FAT12) { - VFS_ReadAt(Disk->fileHandle, ofs+(cluster>>1)*3, 3, &val); - val = (cluster&1 ? val&0xFFF : val>>12); - if(val == EOC_FAT12) val = -1; - } else if(Disk->type == FAT16) { - VFS_ReadAt(Disk->fileHandle, ofs+cluster*2, 2, &val); - if(val == EOC_FAT16) val = -1; - } else { - VFS_ReadAt(Disk->fileHandle, ofs+cluster*4, 4, &val); - if(val == EOC_FAT32) val = -1; - } - #endif /*CACHE_FAT*/ - LEAVE('x', val); - return val; -} - -/* Reads a cluster's data - */ -static void FAT_int_ReadCluster(int Handle, Uint32 Cluster, int Length, void *Buffer) -{ - ENTER("iHandle xCluster iLength pBuffer", Handle, Cluster, Length, Buffer); - //Log("Cluster = %i (0x%x)", Cluster, Cluster); - VFS_ReadAt( - gFAT_Disks[Handle].fileHandle, - (gFAT_Disks[Handle].firstDataSect + (Cluster-2)*gFAT_Disks[Handle].bootsect.spc ) - * gFAT_Disks[Handle].bootsect.bps, - Length, - Buffer - ); - LEAVE('-'); -} - -/** - * \fn Uint64 FAT_Read(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer) - * \brief Reads data from a specified file - */ -Uint64 FAT_Read(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer) -{ - int preSkip, count; - int handle = node->ImplInt; - int i, cluster, pos; - int bpc; - void *tmpBuf; - tFAT_VolInfo *disk = &gFAT_Disks[node->ImplInt]; - - ENTER("Xoffset Xlength pbuffer", offset, length, buffer); - - // Calculate and Allocate Bytes Per Cluster - bpc = disk->bootsect.spc * disk->bootsect.bps; - tmpBuf = (void*) malloc(bpc); - LOG("malloc'd %i bytes", bpc); - - // Cluster is stored in Inode Field - cluster = node->Inode; - - // Sanity Check offset - if(offset > node->Size) { - //LOG("Reading past EOF (%i > %i)", offset, node->Size); - LEAVE('i', 0); - return 0; - } - // Clamp Size - if(offset + length > node->Size) { - //LOG("Reading past EOF (%lli + %lli > %lli), clamped to %lli", - // offset, length, node->Size, node->Size - offset); - length = node->Size - offset; - } - - // Single Cluster including offset - if(length + offset < bpc) - { - FAT_int_ReadCluster(handle, cluster, bpc, tmpBuf); - memcpy( buffer, (void*)( tmpBuf + offset%bpc ), length ); - free(tmpBuf); - LEAVE('i', 1); - return length; - } - - preSkip = offset / bpc; - - //Skip previous clusters - for(i=preSkip;i--;) { - cluster = FAT_int_GetFatValue(disk, cluster); - if(cluster == -1) { - Warning("FAT_Read - Offset is past end of cluster chain mark"); - LEAVE('i', 0); - return 0; - } - } - - // Get Count of Clusters to read - count = ((offset%bpc+length) / bpc) + 1; - - // Get buffer Position after 1st cluster - pos = bpc - offset%bpc; - - // Read 1st Cluster - FAT_int_ReadCluster(handle, cluster, bpc, tmpBuf); - memcpy( - buffer, - (void*)( tmpBuf + (bpc-pos) ), - (pos < length ? pos : length) - ); - - if (count == 1) { - free(tmpBuf); - LEAVE('i', 1); - return length; - } - - cluster = FAT_int_GetFatValue(disk, cluster); - - #if DEBUG - LOG("pos=%i\n", pos); - LOG("Reading the rest of the clusters\n"); - #endif - - - //Read the rest of the cluster data - for( i = 1; i < count-1; i++ ) - { - FAT_int_ReadCluster(handle, cluster, bpc, tmpBuf); - memcpy((void*)(buffer+pos), tmpBuf, bpc); - pos += bpc; - cluster = FAT_int_GetFatValue(disk, cluster); - if(cluster == -1) { - Warning("FAT_Read - Read past End of Cluster Chain"); - free(tmpBuf); - LEAVE('i', 0); - return 0; - } - } - - FAT_int_ReadCluster(handle, cluster, bpc, tmpBuf); - memcpy((void*)(buffer+pos), tmpBuf, length-pos); - - #if DEBUG - LOG("Free tmpBuf(0x%x) and Return\n", tmpBuf); - #endif - - free(tmpBuf); - LEAVE('X', length); - return length; -} - -/** - * \fn Uint64 FAT_Write(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer) - */ -Uint64 FAT_Write(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer) -{ - return 0; -} - -/** - * \fn static void FAT_int_ProperFilename(char *dest, char *src) - * \brief Converts a FAT directory entry name into a proper filename - */ -static void FAT_int_ProperFilename(char *dest, char *src) -{ - int a, b; - - for( a = 0; a < 8; a++) { - if(src[a] == ' ') break; - dest[a] = src[a]; - } - b = a; - a = 8; - if(src[8] != ' ') - dest[b++] = '.'; - for( ; a < 11; a++, b++) { - if(src[a] == ' ') break; - dest[b] = src[a]; - } - dest[b] = '\0'; - #if DEBUG - //Log("FAT_int_ProperFilename: dest='%s'", dest); - #endif -} - -/** - * \fn char *FAT_int_CreateName(tVFS_Node *parent, fat_filetable *ft, char *LongFileName) - * \brief Converts either a LFN or a 8.3 Name into a proper name - */ -char *FAT_int_CreateName(tVFS_Node *parent, fat_filetable *ft, char *LongFileName) -{ - char *ret; - int len; - #if USE_LFN - if(LongFileName && LongFileName[0] != '\0') - { - len = strlen(LongFileName); - ret = malloc(len+1); - strcpy(ret, LongFileName); - } - else - { - #endif - ret = (char*) malloc(13); - memset(ret, 13, '\0'); - FAT_int_ProperFilename(ret, ft->name); - #if USE_LFN - } - #endif - return ret; -} - -/** - * \fn tVFS_Node *FAT_int_CreateNode(tVFS_Node *parent, fat_filetable *ft, char *LongFileName) - * \brief Creates a tVFS_Node structure for a given file entry - */ -tVFS_Node *FAT_int_CreateNode(tVFS_Node *parent, fat_filetable *ft, char *LongFileName) -{ - tVFS_Node node = {0}; - tVFS_Node *ret; - - ENTER("pParent pFT sLongFileName", parent, ft, LongFileName); - - // Set Other Data - node.Inode = ft->cluster | (ft->clusterHi<<16); - node.Size = ft->size; - LOG("ft->size = %i", ft->size); - node.ImplInt = parent->ImplInt; - node.UID = 0; node.GID = 0; - node.NumACLs = 1; - node.ACLs = &gVFS_ACL_EveryoneRWX; // RWXRWXRWX - - node.Flags = 0; - if(ft->attrib & ATTR_DIRECTORY) node.Flags |= VFS_FFLAG_DIRECTORY; - if(ft->attrib & ATTR_READONLY) node.Flags |= VFS_FFLAG_READONLY; - - node.ATime = timestamp(0,0,0, - ((ft->adate&0x1F)-1), //Days - ((ft->adate&0x1E0)-1), //Months - 1980+((ft->adate&0xFF00)>>8)); //Years - - node.CTime = ft->ctimems * 10; //Miliseconds - node.CTime += timestamp( - (ft->ctime&0x1F)<<1, //Seconds - ((ft->ctime&0x3F0)>>5), //Minutes - ((ft->ctime&0xF800)>>11), //Hours - ((ft->cdate&0x1F)-1), //Days - ((ft->cdate&0x1E0)-1), //Months - 1980+((ft->cdate&0xFF00)>>8)); //Years - - node.MTime = timestamp( - (ft->mtime&0x1F)<<1, //Seconds - ((ft->mtime&0x3F0)>>5), //Minuites - ((ft->mtime&0xF800)>>11), //Hours - ((ft->mdate&0x1F)-1), //Days - ((ft->mdate&0x1E0)-1), //Months - 1980+((ft->mdate&0xFF00)>>8)); //Years - - if(node.Flags & VFS_FFLAG_DIRECTORY) { - node.ReadDir = FAT_ReadDir; - node.FindDir = FAT_FindDir; - node.MkNod = FAT_Mknod; - node.Size = -1; - } else { - node.Read = FAT_Read; - node.Write = FAT_Write; - } - node.Close = FAT_CloseFile; - node.Relink = FAT_Relink; - - ret = Inode_CacheNode(gFAT_Disks[parent->ImplInt].inodeHandle, &node); - LEAVE('p', ret); - return ret; -} - -#if USE_LFN -/** - \fn char *FAT_int_GetLFN(tVFS_Node *node) - \brief Return pointer to LFN cache entry - */ -char *FAT_int_GetLFN(tVFS_Node *node) -{ - t_lfncache *tmp; - tmp = fat_lfncache; - while(tmp) - { - if(tmp->Inode == node->Inode && tmp->Impl == node->ImplInt) - return tmp->Name; - tmp = tmp->Next; - } - tmp = malloc(sizeof(t_lfncache)); - tmp->Inode = node->Inode; - tmp->Impl = node->ImplInt; - memset(tmp->Name, 0, 256); - - tmp->Next = fat_lfncache; - fat_lfncache = tmp; - - return tmp->Name; -} - -/** - \fn void FAT_int_DelLFN(tVFS_Node *node) - \brief Delete a LFN cache entry -*/ -void FAT_int_DelLFN(tVFS_Node *node) -{ - t_lfncache *tmp; - - if(!fat_lfncache) return; - - if(!fat_lfncache->Next) - { - tmp = fat_lfncache; - fat_lfncache = tmp->Next; - free(tmp); - return; - } - tmp = fat_lfncache; - while(tmp && tmp->Next) - { - if(tmp->Inode == node->Inode && tmp->Impl == node->ImplInt) - { - free(tmp->Next); - tmp->Next = tmp->Next->Next; - return; - } - tmp = tmp->Next; - } -} -#endif - -/** - \fn char *FAT_ReadDir(tVFS_Node *dirNode, int dirPos) - \param dirNode Node structure of directory - \param dirPos Directory position -**/ -char *FAT_ReadDir(tVFS_Node *dirNode, int dirpos) -{ - fat_filetable fileinfo[16]; //Sizeof=32, 16 per sector - int a=0; - tFAT_VolInfo *disk = &gFAT_Disks[dirNode->ImplInt&7]; - Uint32 cluster, offset; - int preSkip; - char *ret; - #if USE_LFN - char *lfn = NULL; - #endif - - ENTER("pDirNode iDirPos", dirNode, dirpos); - - // Get Byte Offset and skip - offset = dirpos * sizeof(fat_filetable); - preSkip = offset / (512 * disk->bootsect.spc); - LOG("disk->bootsect.spc = %i", disk->bootsect.spc); - LOG("dirNode->size = %i", dirNode->Size); - cluster = dirNode->Inode; // Cluster ID - - // Do Cluster Skip - // - Pre FAT32 had a reserved area for the root. - if( disk->type == FAT32 || cluster != disk->rootOffset ) - { - //Skip previous clusters - for(a=preSkip;a--;) { - cluster = FAT_int_GetFatValue(disk, cluster); - // Check for end of cluster chain - if(cluster == -1) { LEAVE('n'); return NULL;} - } - } - - // Bounds Checking (Used to spot heap overflows) - if(cluster > disk->clusterCount + 2) - { - Warning("FAT_ReadDir - Cluster ID is over cluster count (0x%x>0x%x)", - cluster, disk->clusterCount+2); - LEAVE('n'); - return NULL; - } - - LOG("cluster=0x%x, dirpos=%i", cluster, dirpos); - - // Compute Offsets - // - Pre FAT32 cluster base (in sectors) - if( cluster == disk->rootOffset && disk->type != FAT32 ) - offset = disk->bootsect.resvSectCount + cluster*disk->bootsect.spc; - else - { // FAT32 cluster base (in sectors) - offset = disk->firstDataSect; - offset += (cluster - 2) * disk->bootsect.spc; - } - // Sector in cluster - if(disk->bootsect.spc != 1) - offset += (dirpos / 16) % disk->bootsect.spc; - // Offset in sector - a = dirpos % 16; - - LOG("offset=%i, a=%i", offset, a); - - // Read Sector - VFS_ReadAt(disk->fileHandle, offset*512, 512, fileinfo); // Read Dir Data - - LOG("name[0] = 0x%x", (Uint8)fileinfo[a].name[0]); - //Check if this is the last entry - if( fileinfo[a].name[0] == '\0' ) { - dirNode->Size = dirpos; - LOG("End of list"); - LEAVE('n'); - return NULL; // break - } - - // Check for empty entry - if( (Uint8)fileinfo[a].name[0] == 0xE5 ) { - LOG("Empty Entry"); - LEAVE('p', VFS_SKIP); - return VFS_SKIP; // Skip - } - - #if USE_LFN - // Get Long File Name Cache - lfn = FAT_int_GetLFN(dirNode); - if(fileinfo[a].attrib == ATTR_LFN) - { - fat_longfilename *lfnInfo; - int len; - - lfnInfo = (fat_longfilename *) &fileinfo[a]; - if(lfnInfo->id & 0x40) memset(lfn, 0, 256); - // Get the current length - len = strlen(lfn); - - // Sanity Check (FAT implementations should not allow >255 bytes) - if(len + 13 > 255) return VFS_SKIP; - // Rebase all bytes - for(a=len+1;a--;) lfn[a+13] = lfn[a]; - - // Append new bytes - lfn[ 0] = lfnInfo->name1[0]; lfn[ 1] = lfnInfo->name1[1]; - lfn[ 2] = lfnInfo->name1[2]; lfn[ 3] = lfnInfo->name1[3]; - lfn[ 4] = lfnInfo->name1[4]; - lfn[ 5] = lfnInfo->name2[0]; lfn[ 6] = lfnInfo->name2[1]; - lfn[ 7] = lfnInfo->name2[2]; lfn[ 8] = lfnInfo->name2[3]; - lfn[ 9] = lfnInfo->name2[4]; lfn[10] = lfnInfo->name2[5]; - lfn[11] = lfnInfo->name3[0]; lfn[12] = lfnInfo->name3[1]; - LEAVE('p', VFS_SKIP); - return VFS_SKIP; - } - #endif - - //Check if it is a volume entry - if(fileinfo[a].attrib & 0x08) { - LEAVE('p', VFS_SKIP); - return VFS_SKIP; - } - // Ignore . and .. - if(fileinfo[a].name[0] == '.') { - LEAVE('p', VFS_SKIP); - return VFS_SKIP; - } - - LOG("name='%c%c%c%c%c%c%c%c.%c%c%c'\n", - fileinfo[a].name[0], fileinfo[a].name[1], fileinfo[a].name[2], fileinfo[a].name[3], - fileinfo[a].name[4], fileinfo[a].name[5], fileinfo[a].name[6], fileinfo[a].name[7], - fileinfo[a].name[8], fileinfo[a].name[9], fileinfo[a].name[10] ); - - #if USE_LFN - //node = FAT_int_CreateNode(dirNode, &fileinfo[a], lfn); - ret = FAT_int_CreateName(dirNode, &fileinfo[a], lfn); - lfn[0] = '\0'; - #else - //node = FAT_int_CreateNode(dirNode, &fileinfo[a], NULL); - ret = FAT_int_CreateName(dirNode, &fileinfo[a], NULL); - #endif - - LEAVE('s', ret); - return ret; -} - -/** - * \fn tVFS_Node *FAT_FindDir(tVFS_Node *node, char *name) - * \brief Finds an entry in the current directory - */ -tVFS_Node *FAT_FindDir(tVFS_Node *node, char *name) -{ - fat_filetable fileinfo[16]; - char tmpName[11]; - #if USE_LFN - fat_longfilename *lfnInfo; - char *lfn = NULL; - int lfnPos=255, lfnId = -1; - #endif - int i=0; - tVFS_Node *tmpNode; - Uint64 diskOffset; - tFAT_VolInfo *disk = &gFAT_Disks[node->ImplInt]; - Uint32 dirCluster; - Uint32 cluster; - - ENTER("pnode sname", node, name); - - // Fast Returns - if(!name || name[0] == '\0') { - LEAVE('n'); - return NULL; - } - - #if USE_LFN - lfn = FAT_int_GetLFN(node); - #endif - - dirCluster = node->Inode; - // Seek to Directory - if( dirCluster == disk->rootOffset && disk->type != FAT32 ) - diskOffset = (disk->bootsect.resvSectCount+dirCluster*disk->bootsect.spc) << 9; - else - diskOffset = (disk->firstDataSect+(dirCluster-2)*disk->bootsect.spc) << 9; - - for(;;i++) - { - // Load sector - if((i & 0xF) == 0) { - //Log("FAT_FindDir: diskOffset = 0x%x", diskOffset); - VFS_ReadAt(disk->fileHandle, diskOffset, 512, fileinfo); - diskOffset += 512; - } - - //Check if the files are free - if(fileinfo[i&0xF].name[0] == '\0') break; //Free and last - if(fileinfo[i&0xF].name[0] == '\xE5') goto loadCluster; //Free - - - #if USE_LFN - // Long File Name Entry - if(fileinfo[i&0xF].attrib == ATTR_LFN) - { - lfnInfo = (fat_longfilename *) &fileinfo[i&0xF]; - if(lfnInfo->id & 0x40) { - memset(lfn, 0, 256); - lfnPos = 255; - } - lfn[lfnPos--] = lfnInfo->name3[1]; lfn[lfnPos--] = lfnInfo->name3[0]; - lfn[lfnPos--] = lfnInfo->name2[5]; lfn[lfnPos--] = lfnInfo->name2[4]; - lfn[lfnPos--] = lfnInfo->name2[3]; lfn[lfnPos--] = lfnInfo->name2[2]; - lfn[lfnPos--] = lfnInfo->name2[1]; lfn[lfnPos--] = lfnInfo->name2[0]; - lfn[lfnPos--] = lfnInfo->name1[4]; lfn[lfnPos--] = lfnInfo->name1[3]; - lfn[lfnPos--] = lfnInfo->name1[2]; lfn[lfnPos--] = lfnInfo->name1[1]; - lfn[lfnPos--] = lfnInfo->name1[0]; - if((lfnInfo->id&0x3F) == 1) - { - memcpy(lfn, lfn+lfnPos+1, 256-lfnPos); - lfnId = i+1; - } - } - else - { - // Remove LFN if it does not apply - if(lfnId != i) lfn[0] = '\0'; - #endif - // Get Real Filename - FAT_int_ProperFilename(tmpName, fileinfo[i&0xF].name); - - LOG("tmpName = '%s'", tmpName); - - //Only Long name is case sensitive, 8.3 is not - #if USE_LFN - if(strucmp(tmpName, name) == 0 || strcmp(lfn, name) == 0) { - #else - if(strucmp(tmpName, name) == 0) { - #endif - cluster = fileinfo[i&0xF].cluster | (fileinfo[i&0xF].clusterHi << 16); - tmpNode = Inode_GetCache(disk->inodeHandle, cluster); - if(tmpNode == NULL) // Node is not cached - { - #if USE_LFN - tmpNode = FAT_int_CreateNode(node, &fileinfo[i&0xF], lfn); - #else - tmpNode = FAT_int_CreateNode(node, &fileinfo[i&0xF], NULL); - #endif - } - #if USE_LFN - lfn[0] = '\0'; - #endif - LEAVE('p', tmpNode); - return tmpNode; - } - #if USE_LFN - } - #endif - - loadCluster: - //Load Next cluster? - if( ((i+1) >> 4) % disk->bootsect.spc == 0 && ((i+1) & 0xF) == 0) - { - if( dirCluster == disk->rootOffset && disk->type != FAT32 ) - continue; - dirCluster = FAT_int_GetFatValue(disk, dirCluster); - if(dirCluster == -1) break; - diskOffset = (disk->firstDataSect+(dirCluster-2)*disk->bootsect.spc)*512; - } - } - - LEAVE('n'); - return NULL; -} - -/** - * \fn int FAT_Mknod(tVFS_Node *Node, char *Name, Uint Flags) - * \brief Create a new node - */ -int FAT_Mknod(tVFS_Node *Node, char *Name, Uint Flags) -{ - return 0; -} - -/** - * \fn int FAT_Relink(tVFS_Node *Node, char *OldName, char *NewName) - * \brief Rename / Delete a file - */ -int FAT_Relink(tVFS_Node *Node, char *OldName, char *NewName) -{ - return 0; -} - -/** - * \fn void FAT_CloseFile(tVFS_Node *Node) - * \brief Close an open file - */ -void FAT_CloseFile(tVFS_Node *Node) -{ - if(Node == NULL) return ; - - Inode_UncacheNode(gFAT_Disks[Node->ImplInt].inodeHandle, Node->Inode); - #if USE_LFN - if( !Inode_GetCache(gFAT_Disks[Node->ImplInt].inodeHandle, Node->Inode) - && Node->Flags & VFS_FFLAG_DIRECTORY) - FAT_int_DelLFN(Node); - else // Get Cache references the node, so dereference it - Inode_UncacheNode(gFAT_Disks[Node->ImplInt].inodeHandle, Node->Inode); - #endif - return ; -} - -/** - * \fn void fat_install() - * \brief Add the FAT Filesystem to the VFS - */ -void fat_install() -{ - VFS_AddDriver( &gFAT_FSInfo ); -} diff --git a/Kernel/vfs/fs/fs_fat.h b/Kernel/vfs/fs/fs_fat.h deleted file mode 100644 index a4f7f7b7..00000000 --- a/Kernel/vfs/fs/fs_fat.h +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Acess2 - * FAT12/16/32 Driver - * vfs/fs/fs_fat.h - */ -#ifndef _FS_FAT_H_ -#define _FS_FAT_H_ - -// === On Disk Structures === -/** - * \struct fat_bootsect_s - * \brief Bootsector format - */ -struct fat_bootsect_s -{ - Uint8 jmp[3]; //!< Jump Instruction - char oemname[8]; //!< OEM Name. Typically MSDOS1.1 - Uint16 bps; //!< Bytes per Sector. Assumed to be 512 - Uint8 spc; //!< Sectors per Cluster - Uint16 resvSectCount; //!< Number of reserved sectors at beginning of volume - Uint8 fatCount; //!< Number of copies of the FAT - Uint16 files_in_root; //!< Count of files in the root directory - Uint16 totalSect16; //!< Total sector count (FAT12/16) - Uint8 mediaDesc; //!< Media Desctiptor - Uint16 fatSz16; //!< FAT Size (FAT12/16) - Uint16 spt; //!< Sectors per track. Ignored (Acess uses LBA) - Uint16 heads; //!< Heads. Ignored (Acess uses LBA) - Uint32 hiddenCount; //!< ??? - Uint32 totalSect32; //!< Total sector count (FAT32) - union { - struct { - Uint8 drvNum; //!< Drive Number. BIOS Drive ID (E.g. 0x80) - Uint8 resv; //!< Reserved byte - Uint8 bootSig; //!< Boot Signature. ??? - Uint32 volId; //!< Volume ID - char label[11]; //!< Disk Label - char fsType[8]; //!< FS Type. ??? - } __attribute__((packed)) fat16; //!< FAT16 Specific information - struct { - Uint32 fatSz32; //!< 32-Bit FAT Size - Uint16 extFlags; //!< Extended flags - Uint16 fsVer; //!< Filesystem Version - Uint32 rootClust; //!< Root Cluster ID - Uint16 fsInfo; //!< FS Info. ??? - Uint16 backupBS; //!< Backup Bootsector Sector Offset - char resv[12]; //!< Reserved Data - Uint8 drvNum; //!< Drive Number - char resv2; //!< Reserved Data - Uint8 bootSig; //!< Boot Signature. ??? - Uint32 volId; //!< Volume ID - char label[11]; //!< Disk Label - char fsType[8]; //!< Filesystem Type. ??? - } __attribute__((packed)) fat32; //!< FAT32 Specific Information - }__attribute__((packed)) spec; //!< Non Shared Data - char pad[512-90]; //!< Bootsector Data (Code/Boot Signature 0xAA55) -} __attribute__((packed)); - -/** - \struct fat_filetable_s - \brief Format of a 8.3 file entry on disk -*/ -struct fat_filetable_s { - char name[11]; //!< 8.3 Name - Uint8 attrib; //!< File Attributes. - Uint8 ntres; //!< Reserved for NT - Set to 0 - Uint8 ctimems; //!< 10ths of a second ranging from 0-199 (2 seconds) - Uint16 ctime; //!< Creation Time - Uint16 cdate; //!< Creation Date - Uint16 adate; //!< Accessed Data. No Time feild though - Uint16 clusterHi; //!< High Cluster. 0 for FAT12 and FAT16 - Uint16 mtime; //!< Last Modified Time - Uint16 mdate; //!< Last Modified Date - Uint16 cluster; //!< Low Word of First cluster - Uint32 size; //!< Size of file -} __attribute__((packed)); - -/** - \struct fat_longfilename_s - \brief Format of a long file name entry on disk -*/ -struct fat_longfilename_s { - Uint8 id; //!< ID of entry. Bit 6 is set for last entry - Uint16 name1[5]; //!< 5 characters of name - Uint8 attrib; //!< Attributes. Must be ATTR_LFN - Uint8 type; //!< Type. ??? - Uint8 checksum; //!< Checksum - Uint16 name2[6]; //!< 6 characters of name - Uint16 firstCluster; //!< Used for non LFN compatability. Set to 0 - Uint16 name3[2]; //!< Last 2 characters of name -} __attribute__((packed)); - -/** - * \name File Attributes - * \brief Flag values for ::fat_filetable_s.attrib - * \{ - */ -#define ATTR_READONLY 0x01 //!< Read-only file -#define ATTR_HIDDEN 0x02 //!< Hidden File -#define ATTR_SYSTEM 0x04 //!< System File -#define ATTR_VOLUMEID 0x08 //!< Volume ID (Deprecated) -#define ATTR_DIRECTORY 0x10 //!< Directory -/** - * \brief File needs archiving - * \note User set flag, no significance to the FS driver - */ -#define ATTR_ARCHIVE 0x20 -/** - * \brief Meta Attribute - * - * If ::fat_filetable_s.attrib equals ATTR_LFN the file is a LFN entry - */ -#define ATTR_LFN (ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUMEID) -/** - * \} - */ - -/** - * \brief Internal IDs for FAT types - */ -enum eFatType -{ - FAT12, //!< FAT12 Volume - FAT16, //!< FAT16 Volume - FAT32, //!< FAT32 Volume -}; - -/** - * \name End of Cluster marks - * \brief FAT values that indicate the end of a cluster chain in - * different versions. - * \{ - */ -#define EOC_FAT12 0x0FFF //!< FAT-12 Mark -#define EOC_FAT16 0xFFFF //!< FAT-16 Mark -#define EOC_FAT32 0x0FFFFFF //!< FAT-32 Mark -/** - * \} - */ - -typedef struct fat_bootsect_s fat_bootsect; -typedef struct fat_filetable_s fat_filetable; -typedef struct fat_longfilename_s fat_longfilename; - -// === Memory Structures === -/** - * \struct drv_fat_volinfo_s - * \brief Representation of a volume in memory - */ -struct drv_fat_volinfo_s -{ - int fileHandle; //!< File Handle - int type; //!< FAT Type. See eFatType - char name[12]; //!< Volume Name (With NULL Terminator) - Uint32 firstDataSect; //!< First data sector - Uint32 rootOffset; //!< Root Offset (clusters) - Uint32 clusterCount; //!< Total Cluster Count - fat_bootsect bootsect; //!< Boot Sector - tVFS_Node rootNode; //!< Root Node - int inodeHandle; //!< Inode Cache Handle - #if CACHE_FAT - Uint32 *FATCache; //!< FAT Cache - #endif -}; - -typedef struct drv_fat_volinfo_s tFAT_VolInfo; - -#endif diff --git a/Makefile.cfg b/Makefile.cfg index 348206fb..a12ea151 100644 --- a/Makefile.cfg +++ b/Makefile.cfg @@ -23,12 +23,13 @@ ifeq ($(ARCHDIR),) ARCHDIR = x86 endif -FILESYSTEMS = fat +FILESYSTEMS = DRIVERS = MODULES = Storage/ATA Storage/FDD MODULES += Network/NE2000 MODULES += Display/BochsGA -MODULES += Filesystems/FS_Ext2 +MODULES += Filesystems/Ext2 +MODULES += Filesystems/FAT MODULES += IPStack DYNMODS = USB Interfaces/UDI diff --git a/Modules/Display/Makefile.tpl b/Modules/Display/Makefile.tpl index 80c6d4dd..b5431609 100644 --- a/Modules/Display/Makefile.tpl +++ b/Modules/Display/Makefile.tpl @@ -1 +1,3 @@ +CATEGORY = Video + -include ../../Makefile.tpl diff --git a/Modules/Filesystems/Ext2/Makefile b/Modules/Filesystems/Ext2/Makefile new file mode 100644 index 00000000..471ba49e --- /dev/null +++ b/Modules/Filesystems/Ext2/Makefile @@ -0,0 +1,7 @@ +# +# + +OBJ = ext2.o read.o dir.o write.o +NAME = Ext2 + +-include ../Makefile.tpl diff --git a/Modules/Filesystems/Ext2/dir.c b/Modules/Filesystems/Ext2/dir.c new file mode 100644 index 00000000..0ab3ed39 --- /dev/null +++ b/Modules/Filesystems/Ext2/dir.c @@ -0,0 +1,229 @@ +/* + * Acess OS + * Ext2 Driver Version 1 + */ +/** + * \file dir.c + * \brief Second Extended Filesystem Driver + * \todo Implement file full write support + */ +#define DEBUG 1 +#define VERBOSE 0 +#include "ext2_common.h" + + +// === PROTOTYPES === +char *Ext2_ReadDir(tVFS_Node *Node, int Pos); +tVFS_Node *Ext2_FindDir(tVFS_Node *Node, char *FileName); + int Ext2_MkNod(tVFS_Node *Node, char *Name, Uint Flags); +tVFS_Node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeId, char *Name); + +// === CODE === +/** + \fn char *Ext2_ReadDir(tVFS_Node *Node, int Pos) + \brief Reads a directory entry +*/ +char *Ext2_ReadDir(tVFS_Node *Node, int Pos) +{ + tExt2_Inode inode; + char namebuf[EXT2_NAME_LEN+1]; + tExt2_DirEnt dirent; + Uint64 Base; // Block's Base Address + int block = 0, ofs = 0; + int entNum = 0; + tExt2_Disk *disk = Node->ImplPtr; + Uint size; + + ENTER("pNode iPos", Node, Pos); + + // Read directory's inode + //Ext2_int_GetInode(Node, &inode); + Ext2_int_ReadInode(disk, Node->Inode, &inode); + size = inode.i_size; + + LOG("inode.i_block[0] = 0x%x", inode.i_block[0]); + + // Find Entry + // Get First Block + // - Do this ourselves as it is a simple operation + Base = inode.i_block[0] * disk->BlockSize; + while(Pos -- && size > 0) + { + VFS_ReadAt( disk->FD, Base+ofs, sizeof(tExt2_DirEnt), &dirent); + ofs += dirent.rec_len; + size -= dirent.rec_len; + entNum ++; + + if(ofs >= disk->BlockSize) { + block ++; + if( ofs > disk->BlockSize ) { + Warning("[EXT2] Directory Entry %i of inode %i extends over a block boundary, ignoring", + entNum-1, Node->Inode); + } + ofs = 0; + Base = Ext2_int_GetBlockAddr( disk, inode.i_block, block ); + } + } + + // Check for the end of the list + if(size <= 0) { + LEAVE('n'); + return NULL; + } + + // Read Entry + VFS_ReadAt( disk->FD, Base+ofs, sizeof(tExt2_DirEnt), &dirent ); + //LOG("dirent.inode = %i", dirent.inode); + //LOG("dirent.rec_len = %i", dirent.rec_len); + //LOG("dirent.name_len = %i", dirent.name_len); + VFS_ReadAt( disk->FD, Base+ofs+sizeof(tExt2_DirEnt), dirent.name_len, namebuf ); + namebuf[ dirent.name_len ] = '\0'; // Cap off string + + + // Ignore . and .. (these are done in the VFS) + if( (namebuf[0] == '.' && namebuf[1] == '\0') + || (namebuf[0] == '.' && namebuf[1] == '.' && namebuf[2]=='\0')) { + LEAVE('p', VFS_SKIP); + return VFS_SKIP; // Skip + } + + LEAVE('s', namebuf); + // Create new node + return strdup(namebuf); +} + +/** + \fn tVFS_Node *Ext2_FindDir(tVFS_Node *node, char *filename) + \brief Gets information about a file + \param node vfs node - Parent Node + \param filename String - Name of file + \return VFS Node of file +*/ +tVFS_Node *Ext2_FindDir(tVFS_Node *Node, char *Filename) +{ + tExt2_Disk *disk = Node->ImplPtr; + tExt2_Inode inode; + char namebuf[EXT2_NAME_LEN+1]; + tExt2_DirEnt dirent; + Uint64 Base; // Block's Base Address + int block = 0, ofs = 0; + int entNum = 0; + Uint size; + + // Read directory's inode + Ext2_int_ReadInode(disk, Node->Inode, &inode); + size = inode.i_size; + + // Get First Block + // - Do this ourselves as it is a simple operation + Base = inode.i_block[0] * disk->BlockSize; + // Find File + while(size > 0) + { + VFS_ReadAt( disk->FD, Base+ofs, sizeof(tExt2_DirEnt), &dirent); + VFS_ReadAt( disk->FD, Base+ofs+sizeof(tExt2_DirEnt), dirent.name_len, namebuf ); + namebuf[ dirent.name_len ] = '\0'; // Cap off string + // If it matches, create a node and return it + if(strcmp(namebuf, Filename) == 0) + return Ext2_int_CreateNode( disk, dirent.inode, namebuf ); + // Increment pointers + ofs += dirent.rec_len; + size -= dirent.rec_len; + entNum ++; + + // Check for end of block + if(ofs >= disk->BlockSize) { + block ++; + if( ofs > disk->BlockSize ) { + Warning("[EXT2 ] Directory Entry %i of inode %i extends over a block boundary, ignoring", + entNum-1, Node->Inode); + } + ofs = 0; + Base = Ext2_int_GetBlockAddr( disk, inode.i_block, block ); + } + } + + return NULL; +} + +/** + * \fn int Ext2_MkNod(tVFS_Node *Parent, char *Name, Uint Flags) + * \brief Create a new node + */ +int Ext2_MkNod(tVFS_Node *Parent, char *Name, Uint Flags) +{ + return 0; +} + +// ---- INTERNAL FUNCTIONS ---- +/** + * \fn vfs_node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeID, char *Name) + * \brief Create a new VFS Node + */ +tVFS_Node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeID, char *Name) +{ + tExt2_Inode inode; + tVFS_Node retNode; + tVFS_Node *tmpNode; + + if( !Ext2_int_ReadInode(Disk, InodeID, &inode) ) + return NULL; + + if( (tmpNode = Inode_GetCache(Disk->CacheID, InodeID)) ) + return tmpNode; + + + // Set identifiers + retNode.Inode = InodeID; + retNode.ImplPtr = Disk; + + // Set file length + retNode.Size = inode.i_size; + + // Set Access Permissions + retNode.UID = inode.i_uid; + retNode.GID = inode.i_gid; + retNode.NumACLs = 3; + retNode.ACLs = VFS_UnixToAcessACL(inode.i_mode & 0777, inode.i_uid, inode.i_gid); + + // Set Function Pointers + retNode.Read = Ext2_Read; + retNode.Write = Ext2_Write; + retNode.Close = Ext2_CloseFile; + + switch(inode.i_mode & EXT2_S_IFMT) + { + // Symbolic Link + case EXT2_S_IFLNK: + retNode.Flags = VFS_FFLAG_SYMLINK; + break; + // Regular File + case EXT2_S_IFREG: + retNode.Flags = 0; + retNode.Size |= (Uint64)inode.i_dir_acl << 32; + break; + // Directory + case EXT2_S_IFDIR: + retNode.ReadDir = Ext2_ReadDir; + retNode.FindDir = Ext2_FindDir; + retNode.MkNod = Ext2_MkNod; + //retNode.Relink = Ext2_Relink; + retNode.Flags = VFS_FFLAG_DIRECTORY; + break; + // Unknown, Write protect and hide it to be safe + default: + retNode.Flags = VFS_FFLAG_READONLY;//|VFS_FFLAG_HIDDEN; + break; + } + + // Check if the file should be hidden + //if(Name[0] == '.') retNode.Flags |= VFS_FFLAG_HIDDEN; + + // Set Timestamps + retNode.ATime = now(); + retNode.MTime = inode.i_mtime * 1000; + retNode.CTime = inode.i_ctime * 1000; + + // Save in node cache and return saved node + return Inode_CacheNode(Disk->CacheID, &retNode); +} diff --git a/Modules/Filesystems/Ext2/ext2.c b/Modules/Filesystems/Ext2/ext2.c new file mode 100644 index 00000000..c2c2df9c --- /dev/null +++ b/Modules/Filesystems/Ext2/ext2.c @@ -0,0 +1,330 @@ +/* + * Acess OS + * Ext2 Driver Version 1 + */ +/** + * \file fs/ext2.c + * \brief Second Extended Filesystem Driver + * \todo Implement file full write support + */ +#define DEBUG 1 +#define VERBOSE 0 +#include "ext2_common.h" +#include + +// === PROTOTYPES === + int Ext2_Install(char **Arguments); +// Interface Functions +tVFS_Node *Ext2_InitDevice(char *Device, char **Options); +void Ext2_Unmount(tVFS_Node *Node); +void Ext2_CloseFile(tVFS_Node *Node); +// Internal Helpers + int Ext2_int_GetInode(tVFS_Node *Node, tExt2_Inode *Inode); +Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum); +Uint32 Ext2_int_AllocateInode(tExt2_Disk *Disk, Uint32 Parent); +void Ext2_int_UpdateSuperblock(tExt2_Disk *Disk); + +// === SEMI-GLOBALS === +MODULE_DEFINE(0, 0x5B /*v0.90*/, FS_Ext2, Ext2_Install, NULL); +tExt2_Disk gExt2_disks[6]; + int giExt2_count = 0; +tVFS_Driver gExt2_FSInfo = { + "ext2", 0, Ext2_InitDevice, Ext2_Unmount, NULL + }; + +// === CODE === + +/** + * \fn int Ext2_Install(char **Arguments) + * \brief Install the Ext2 Filesystem Driver + */ +int Ext2_Install(char **Arguments) +{ + VFS_AddDriver( &gExt2_FSInfo ); + return MODULE_ERR_OK; +} + +/** + \fn tVFS_Node *Ext2_InitDevice(char *Device, char **Options) + \brief Initializes a device to be read by by the driver + \param Device String - Device to read from + \param Options NULL Terminated array of option strings + \return Root Node +*/ +tVFS_Node *Ext2_InitDevice(char *Device, char **Options) +{ + tExt2_Disk *disk; + int fd; + int groupCount; + tExt2_SuperBlock sb; + tExt2_Inode inode; + + ENTER("sDevice pOptions", Device, Options); + + // Open Disk + fd = VFS_Open(Device, VFS_OPENFLAG_READ|VFS_OPENFLAG_WRITE); //Open Device + if(fd == -1) { + Warning("[EXT2 ] Unable to open '%s'", Device); + LEAVE('n'); + return NULL; + } + + // Read Superblock at offset 1024 + VFS_ReadAt(fd, 1024, 1024, &sb); // Read Superblock + + // Sanity Check Magic value + if(sb.s_magic != 0xEF53) { + Warning("[EXT2 ] Volume '%s' is not an EXT2 volume", Device); + VFS_Close(fd); + LEAVE('n'); + return NULL; + } + + // Get Group count + groupCount = DivUp(sb.s_blocks_count, sb.s_blocks_per_group); + LOG("groupCount = %i", groupCount); + + // Allocate Disk Information + disk = malloc(sizeof(tExt2_Disk) + sizeof(tExt2_Group)*groupCount); + if(!disk) { + Warning("[EXT2 ] Unable to allocate disk structure"); + VFS_Close(fd); + LEAVE('n'); + return NULL; + } + disk->FD = fd; + memcpy(&disk->SuperBlock, &sb, 1024); + disk->GroupCount = groupCount; + + // Get an inode cache handle + disk->CacheID = Inode_GetHandle(); + + // Get Block Size + LOG("s_log_block_size = 0x%x", sb.s_log_block_size); + disk->BlockSize = 1024 << sb.s_log_block_size; + + // Read Group Information + VFS_ReadAt( + disk->FD, + sb.s_first_data_block * disk->BlockSize + 1024, + sizeof(tExt2_Group)*groupCount, + disk->Groups + ); + + #if VERBOSE + LOG("Block Group 0"); + LOG(".bg_block_bitmap = 0x%x", disk->Groups[0].bg_block_bitmap); + LOG(".bg_inode_bitmap = 0x%x", disk->Groups[0].bg_inode_bitmap); + LOG(".bg_inode_table = 0x%x", disk->Groups[0].bg_inode_table); + LOG("Block Group 1"); + LOG(".bg_block_bitmap = 0x%x", disk->Groups[1].bg_block_bitmap); + LOG(".bg_inode_bitmap = 0x%x", disk->Groups[1].bg_inode_bitmap); + LOG(".bg_inode_table = 0x%x", disk->Groups[1].bg_inode_table); + #endif + + // Get root Inode + Ext2_int_ReadInode(disk, 2, &inode); + + // Create Root Node + memset(&disk->RootNode, 0, sizeof(tVFS_Node)); + disk->RootNode.Inode = 2; // Root inode ID + disk->RootNode.ImplPtr = disk; // Save disk pointer + disk->RootNode.Size = -1; // Fill in later (on readdir) + disk->RootNode.Flags = VFS_FFLAG_DIRECTORY; + + disk->RootNode.ReadDir = Ext2_ReadDir; + disk->RootNode.FindDir = Ext2_FindDir; + //disk->RootNode.Relink = Ext2_Relink; + + // Complete root node + disk->RootNode.UID = inode.i_uid; + disk->RootNode.GID = inode.i_gid; + disk->RootNode.NumACLs = 1; + disk->RootNode.ACLs = &gVFS_ACL_EveryoneRW; + + #if DEBUG + LOG("inode.i_size = 0x%x", inode.i_size); + LOG("inode.i_block[0] = 0x%x", inode.i_block[0]); + #endif + + LEAVE('p', &disk->RootNode); + return &disk->RootNode; +} + +/** + * \fn void Ext2_Unmount(tVFS_Node *Node) + * \brief Close a mounted device + */ +void Ext2_Unmount(tVFS_Node *Node) +{ + tExt2_Disk *disk = Node->ImplPtr; + + VFS_Close( disk->FD ); + Inode_ClearCache( disk->CacheID ); + memset(disk, 0, sizeof(tExt2_Disk)+disk->GroupCount*sizeof(tExt2_Group)); + free(disk); +} + +/** + * \fn void Ext2_CloseFile(tVFS_Node *Node) + * \brief Close a file (Remove it from the cache) + */ +void Ext2_CloseFile(tVFS_Node *Node) +{ + tExt2_Disk *disk = Node->ImplPtr; + Inode_UncacheNode(disk->CacheID, Node->Inode); + return ; +} + +//================================== +//= INTERNAL FUNCTIONS = +//================================== +/** + * \fn int Ext2_int_ReadInode(tExt2_Disk *Disk, Uint InodeId, tExt2_Inode *Inode) + * \brief Read an inode into memory + */ +int Ext2_int_ReadInode(tExt2_Disk *Disk, Uint32 InodeId, tExt2_Inode *Inode) +{ + int group, subId; + + //ENTER("pDisk iInodeId pInode", Disk, InodeId, Inode); + + if(InodeId == 0) return 0; + + InodeId --; // Inodes are numbered starting at 1 + + group = InodeId / Disk->SuperBlock.s_inodes_per_group; + subId = InodeId % Disk->SuperBlock.s_inodes_per_group; + + //LOG("group=%i, subId = %i", group, subId); + + // Read Inode + VFS_ReadAt(Disk->FD, + Disk->Groups[group].bg_inode_table * Disk->BlockSize + sizeof(tExt2_Inode)*subId, + sizeof(tExt2_Inode), + Inode); + + //LEAVE('i', 1); + return 1; +} + +/** + * \brief Write a modified inode out to disk + */ +int Ext2_int_WriteInode(tExt2_Disk *Disk, Uint32 InodeId, tExt2_Inode *Inode) +{ + int group, subId; + ENTER("pDisk iInodeId pInode", Disk, InodeId, Inode); + + if(InodeId == 0) return 0; + + InodeId --; // Inodes are numbered starting at 1 + + group = InodeId / Disk->SuperBlock.s_inodes_per_group; + subId = InodeId % Disk->SuperBlock.s_inodes_per_group; + + LOG("group=%i, subId = %i", group, subId); + + // Write Inode + VFS_WriteAt(Disk->FD, + Disk->Groups[group].bg_inode_table * Disk->BlockSize + sizeof(tExt2_Inode)*subId, + sizeof(tExt2_Inode), + Inode); + + LEAVE('i', 1); + return 1; +} + +/** + * \fn Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum) + * \brief Get the address of a block from an inode's list + * \param Disk Disk information structure + * \param Blocks Pointer to an inode's block list + * \param BlockNum Block index in list + */ +Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum) +{ + Uint32 *iBlocks; + int dwPerBlock = Disk->BlockSize / 4; + + // Direct Blocks + if(BlockNum < 12) + return (Uint64)Blocks[BlockNum] * Disk->BlockSize; + + // Single Indirect Blocks + iBlocks = malloc( Disk->BlockSize ); + VFS_ReadAt(Disk->FD, (Uint64)Blocks[12]*Disk->BlockSize, Disk->BlockSize, iBlocks); + + BlockNum -= 12; + if(BlockNum < dwPerBlock) + { + BlockNum = iBlocks[BlockNum]; + free(iBlocks); + return (Uint64)BlockNum * Disk->BlockSize; + } + + BlockNum -= dwPerBlock; + // Double Indirect Blocks + if(BlockNum < dwPerBlock*dwPerBlock) + { + VFS_ReadAt(Disk->FD, (Uint64)Blocks[13]*Disk->BlockSize, Disk->BlockSize, iBlocks); + VFS_ReadAt(Disk->FD, (Uint64)iBlocks[BlockNum/dwPerBlock]*Disk->BlockSize, Disk->BlockSize, iBlocks); + BlockNum = iBlocks[BlockNum%dwPerBlock]; + free(iBlocks); + return (Uint64)BlockNum * Disk->BlockSize; + } + + BlockNum -= dwPerBlock*dwPerBlock; + // Triple Indirect Blocks + VFS_ReadAt(Disk->FD, (Uint64)Blocks[14]*Disk->BlockSize, Disk->BlockSize, iBlocks); + VFS_ReadAt(Disk->FD, (Uint64)iBlocks[BlockNum/(dwPerBlock*dwPerBlock)]*Disk->BlockSize, Disk->BlockSize, iBlocks); + VFS_ReadAt(Disk->FD, (Uint64)iBlocks[(BlockNum/dwPerBlock)%dwPerBlock]*Disk->BlockSize, Disk->BlockSize, iBlocks); + BlockNum = iBlocks[BlockNum%dwPerBlock]; + free(iBlocks); + return (Uint64)BlockNum * Disk->BlockSize; +} + +/** + * \fn Uint32 Ext2_int_AllocateInode(tExt2_Disk *Disk, Uint32 Parent) + * \brief Allocate an inode (from the current group preferably) + * \param Disk EXT2 Disk Information Structure + * \param Parent Inode ID of the parent (used to locate the child nearby) + */ +Uint32 Ext2_int_AllocateInode(tExt2_Disk *Disk, Uint32 Parent) +{ +// Uint block = (Parent - 1) / Disk->SuperBlock.s_inodes_per_group; + return 0; +} + +/** + * \fn void Ext2_int_UpdateSuperblock(tExt2_Disk *Disk) + * \brief Updates the superblock + */ +void Ext2_int_UpdateSuperblock(tExt2_Disk *Disk) +{ + int bpg = Disk->SuperBlock.s_blocks_per_group; + int ngrp = Disk->SuperBlock.s_blocks_count / bpg; + int i; + + // Update Primary + VFS_WriteAt(Disk->FD, 1024, 1024, &Disk->SuperBlock); + + // Secondaries + // at Block Group 1, 3^n, 5^n, 7^n + + // 1 + if(ngrp <= 1) return; + VFS_WriteAt(Disk->FD, 1*bpg*Disk->BlockSize, 1024, &Disk->SuperBlock); + + // Powers of 3 + for( i = 3; i < ngrp; i *= 3 ) + VFS_WriteAt(Disk->FD, i*bpg*Disk->BlockSize, 1024, &Disk->SuperBlock); + + // Powers of 5 + for( i = 5; i < ngrp; i *= 5 ) + VFS_WriteAt(Disk->FD, i*bpg*Disk->BlockSize, 1024, &Disk->SuperBlock); + + // Powers of 7 + for( i = 7; i < ngrp; i *= 7 ) + VFS_WriteAt(Disk->FD, i*bpg*Disk->BlockSize, 1024, &Disk->SuperBlock); +} diff --git a/Modules/Filesystems/Ext2/ext2_common.h b/Modules/Filesystems/Ext2/ext2_common.h new file mode 100644 index 00000000..877b71d3 --- /dev/null +++ b/Modules/Filesystems/Ext2/ext2_common.h @@ -0,0 +1,46 @@ +/* + * Acess OS + * Ext2 Driver Version 1 + */ +/** + * \file ext2_common.h + * \brief Second Extended Filesystem Driver + */ +#ifndef _EXT2_COMMON_H +#define _EXT2_COMMON_H +#include +#include +#include "ext2fs.h" + +#define EXT2_UPDATE_WRITEBACK 1 + +// === STRUCTURES === +typedef struct { + int FD; + int CacheID; + tVFS_Node RootNode; + + tExt2_SuperBlock SuperBlock; + int BlockSize; + + int GroupCount; + tExt2_Group Groups[]; +} tExt2_Disk; + +// === FUNCTIONS === +// --- Common --- +extern void Ext2_CloseFile(tVFS_Node *Node); +extern Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum); +extern void Ext2_int_UpdateSuperblock(tExt2_Disk *Disk); +extern int Ext2_int_ReadInode(tExt2_Disk *Disk, Uint32 InodeId, tExt2_Inode *Inode); +extern int Ext2_int_WriteInode(tExt2_Disk *Disk, Uint32 InodeId, tExt2_Inode *Inode); +// --- Dir --- +extern char *Ext2_ReadDir(tVFS_Node *Node, int Pos); +extern tVFS_Node *Ext2_FindDir(tVFS_Node *Node, char *FileName); +extern int Ext2_MkNod(tVFS_Node *Node, char *Name, Uint Flags); +// --- Read --- +extern Uint64 Ext2_Read(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer); +// --- Write --- +extern Uint64 Ext2_Write(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer); + +#endif diff --git a/Modules/Filesystems/Ext2/ext2fs.h b/Modules/Filesystems/Ext2/ext2fs.h new file mode 100644 index 00000000..8fd87ce4 --- /dev/null +++ b/Modules/Filesystems/Ext2/ext2fs.h @@ -0,0 +1,156 @@ +/** + * Acess2 + * \file ext2fs.h + * \brief EXT2 Filesystem Driver + */ +#ifndef _EXT2FS_H_ +#define _EXT2FS_H_ + +/** + \name Inode Flag Values + \{ +*/ +#define EXT2_S_IFMT 0xF000 //!< Format Mask +#define EXT2_S_IFSOCK 0xC000 //!< Socket +#define EXT2_S_IFLNK 0xA000 //!< Symbolic Link +#define EXT2_S_IFREG 0x8000 //!< Regular File +#define EXT2_S_IFBLK 0x6000 //!< Block Device +#define EXT2_S_IFDIR 0x4000 //!< Directory +#define EXT2_S_IFCHR 0x2000 //!< Character Device +#define EXT2_S_IFIFO 0x1000 //!< FIFO +#define EXT2_S_ISUID 0x0800 //!< SUID +#define EXT2_S_ISGID 0x0400 //!< SGID +#define EXT2_S_ISVTX 0x0200 //!< sticky bit +#define EXT2_S_IRWXU 0700 //!< user access rights mask +#define EXT2_S_IRUSR 0400 //!< Owner Read +#define EXT2_S_IWUSR 0200 //!< Owner Write +#define EXT2_S_IXUSR 0100 //!< Owner Execute +#define EXT2_S_IRWXG 0070 //!< Group Access rights mask +#define EXT2_S_IRGRP 0040 //!< Group Read +#define EXT2_S_IWGRP 0020 //!< Group Write +#define EXT2_S_IXGRP 0010 //!< Group Execute +#define EXT2_S_IRWXO 0007 //!< Global Access rights mask +#define EXT2_S_IROTH 0004 //!< Global Read +#define EXT2_S_IWOTH 0002 //!< Global Write +#define EXT2_S_IXOTH 0001 //!< Global Execute +//! \} + +#define EXT2_NAME_LEN 255 //!< Maximum Name Length + +// === TYPEDEFS === +typedef struct ext2_inode_s tExt2_Inode; //!< Inode Type +typedef struct ext2_super_block_s tExt2_SuperBlock; //!< Superblock Type +typedef struct ext2_group_desc_s tExt2_Group; //!< Group Descriptor Type +typedef struct ext2_dir_entry_s tExt2_DirEnt; //!< Directory Entry Type + +// === STRUCTURES === +/** + * \brief EXT2 Superblock Structure + */ +struct ext2_super_block_s { + Uint32 s_inodes_count; //!< Inodes count + Uint32 s_blocks_count; //!< Blocks count + Uint32 s_r_blocks_count; //!< Reserved blocks count + Uint32 s_free_blocks_count; //!< Free blocks count + Uint32 s_free_inodes_count; //!< Free inodes count + Uint32 s_first_data_block; //!< First Data Block + Uint32 s_log_block_size; //!< Block size + Sint32 s_log_frag_size; //!< Fragment size + Uint32 s_blocks_per_group; //!< Number Blocks per group + Uint32 s_frags_per_group; //!< Number Fragments per group + Uint32 s_inodes_per_group; //!< Number Inodes per group + Uint32 s_mtime; //!< Mount time + Uint32 s_wtime; //!< Write time + Uint16 s_mnt_count; //!< Mount count + Sint16 s_max_mnt_count; //!< Maximal mount count + Uint16 s_magic; //!< Magic signature + Uint16 s_state; //!< File system state + Uint16 s_errors; //!< Behaviour when detecting errors + Uint16 s_pad; //!< Padding + Uint32 s_lastcheck; //!< time of last check + Uint32 s_checkinterval; //!< max. time between checks + Uint32 s_creator_os; //!< Formatting OS + Uint32 s_rev_level; //!< Revision level + Uint16 s_def_resuid; //!< Default uid for reserved blocks + Uint16 s_def_resgid; //!< Default gid for reserved blocks + Uint32 s_reserved[235]; //!< Padding to the end of the block +}; + +/** + * \struct ext2_inode_s + * \brief EXT2 Inode Definition + */ +struct ext2_inode_s { + Uint16 i_mode; //!< File mode + Uint16 i_uid; //!< Owner Uid + Uint32 i_size; //!< Size in bytes + Uint32 i_atime; //!< Access time + Uint32 i_ctime; //!< Creation time + Uint32 i_mtime; //!< Modification time + Uint32 i_dtime; //!< Deletion Time + Uint16 i_gid; //!< Group Id + Uint16 i_links_count; //!< Links count + Uint32 i_blocks; //!< Number of blocks allocated for the file + Uint32 i_flags; //!< File flags + union { + Uint32 linux_reserved1; //!< Linux: Reserved + Uint32 hurd_translator; //!< HURD: Translator + Uint32 masix_reserved1; //!< Masix: Reserved + } osd1; //!< OS dependent 1 + Uint32 i_block[15]; //!< Pointers to blocks + Uint32 i_version; //!< File version (for NFS) + Uint32 i_file_acl; //!< File ACL + Uint32 i_dir_acl; //!< Directory ACL / Extended File Size + Uint32 i_faddr; //!< Fragment address + union { + struct { + Uint8 l_i_frag; //!< Fragment number + Uint8 l_i_fsize; //!< Fragment size + Uint16 i_pad1; //!< Padding + Uint32 l_i_reserved2[2]; //!< Reserved + } linux2; + struct { + Uint8 h_i_frag; //!< Fragment number + Uint8 h_i_fsize; //!< Fragment size + Uint16 h_i_mode_high; //!< Mode High Bits + Uint16 h_i_uid_high; //!< UID High Bits + Uint16 h_i_gid_high; //!< GID High Bits + Uint32 h_i_author; //!< Creator ID + } hurd2; + struct { + Uint8 m_i_frag; //!< Fragment number + Uint8 m_i_fsize; //!< Fragment size + Uint16 m_pad1; //!< Padding + Uint32 m_i_reserved2[2]; //!< reserved + } masix2; + } osd2; //!< OS dependent 2 +}; + +/** + * \struct ext2_group_desc_s + * \brief EXT2 Group Descriptor + */ +struct ext2_group_desc_s { + Uint32 bg_block_bitmap; //!< Blocks bitmap block + Uint32 bg_inode_bitmap; //!< Inodes bitmap block + Uint32 bg_inode_table; //!< Inodes table block + Uint16 bg_free_blocks_count; //!< Free blocks count + Uint16 bg_free_inodes_count; //!< Free inodes count + Uint16 bg_used_dirs_count; //!< Directories count + Uint16 bg_pad; //!< Padding + Uint32 bg_reserved[3]; //!< Reserved +}; + +/** + * \brief EXT2 Directory Entry + * \note The name may take up less than 255 characters + */ +struct ext2_dir_entry_s { + Uint32 inode; //!< Inode number + Uint16 rec_len; //!< Directory entry length + Uint8 name_len; //!< Short Name Length + Uint8 type; //!< File Type + char name[]; //!< File name +}; + +#endif diff --git a/Modules/Filesystems/Ext2/read.c b/Modules/Filesystems/Ext2/read.c new file mode 100644 index 00000000..81f5ee64 --- /dev/null +++ b/Modules/Filesystems/Ext2/read.c @@ -0,0 +1,88 @@ +/* + * Acess OS + * Ext2 Driver Version 1 + */ +/** + * \file read.c + * \brief Second Extended Filesystem Driver + * \todo Implement file full write support + */ +#define DEBUG 1 +#define VERBOSE 0 +#include "ext2_common.h" + +// === PROTOTYPES === +Uint64 Ext2_Read(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer); + +// === CODE === +/** + * \fn Uint64 Ext2_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) + * \brief Read from a file + */ +Uint64 Ext2_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) +{ + tExt2_Disk *disk = Node->ImplPtr; + tExt2_Inode inode; + Uint64 base; + Uint block; + Uint64 remLen; + + ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer); + + // Get Inode + Ext2_int_ReadInode(disk, Node->Inode, &inode); + + // Sanity Checks + if(Offset >= inode.i_size) { + LEAVE('i', 0); + return 0; + } + if(Offset + Length > inode.i_size) + Length = inode.i_size - Offset; + + block = Offset / disk->BlockSize; + Offset = Offset / disk->BlockSize; + base = Ext2_int_GetBlockAddr(disk, inode.i_block, block); + if(base == 0) { + Warning("[EXT2 ] NULL Block Detected in INode 0x%llx", Node->Inode); + LEAVE('i', 0); + return 0; + } + + // Read only block + if(Length <= disk->BlockSize - Offset) + { + VFS_ReadAt( disk->FD, base+Offset, Length, Buffer); + LEAVE('X', Length); + return Length; + } + + // Read first block + remLen = Length; + VFS_ReadAt( disk->FD, base + Offset, disk->BlockSize - Offset, Buffer); + remLen -= disk->BlockSize - Offset; + Buffer += disk->BlockSize - Offset; + block ++; + + // Read middle blocks + while(remLen > disk->BlockSize) + { + base = Ext2_int_GetBlockAddr(disk, inode.i_block, block); + if(base == 0) { + Warning("[EXT2 ] NULL Block Detected in INode 0x%llx", Node->Inode); + LEAVE('i', 0); + return 0; + } + VFS_ReadAt( disk->FD, base, disk->BlockSize, Buffer); + Buffer += disk->BlockSize; + remLen -= disk->BlockSize; + block ++; + } + + // Read last block + base = Ext2_int_GetBlockAddr(disk, inode.i_block, block); + VFS_ReadAt( disk->FD, base, remLen, Buffer); + + LEAVE('X', Length); + return Length; +} diff --git a/Modules/Filesystems/Ext2/write.c b/Modules/Filesystems/Ext2/write.c new file mode 100644 index 00000000..ba8b61ce --- /dev/null +++ b/Modules/Filesystems/Ext2/write.c @@ -0,0 +1,369 @@ +/* + * Acess OS + * Ext2 Driver Version 1 + */ +/** + * \file write.c + * \brief Second Extended Filesystem Driver + * \todo Implement file full write support + */ +#define DEBUG 1 +#define VERBOSE 0 +#include "ext2_common.h" + +// === PROTOYPES === +Uint64 Ext2_Write(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer); +Uint32 Ext2_int_AllocateBlock(tExt2_Disk *Disk, Uint32 PrevBlock); +void Ext2_int_DeallocateBlock(tExt2_Disk *Disk, Uint32 Block); + int Ext2_int_AppendBlock(tExt2_Disk *Disk, tExt2_Inode *Inode, Uint32 Block); + +// === CODE === +/** + * \fn Uint64 Ext2_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) + * \brief Write to a file + */ +Uint64 Ext2_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) +{ + tExt2_Disk *disk = Node->ImplPtr; + tExt2_Inode inode; + Uint64 base; + Uint64 retLen; + Uint block; + Uint64 allocSize; + int bNewBlocks = 0; + + Debug_HexDump("Ext2_Write", Buffer, Length); + + Ext2_int_ReadInode(disk, Node->Inode, &inode); + + // Get the ammount of space already allocated + // - Round size up to block size + // - block size is a power of two, so this will work + allocSize = (inode.i_size + disk->BlockSize-1) & ~(disk->BlockSize-1); + + // Are we writing to inside the allocated space? + if( Offset > allocSize ) return 0; + + if( Offset < allocSize ) + { + // Will we go out of it? + if(Offset + Length > allocSize) { + bNewBlocks = 1; + retLen = allocSize - Offset; + } else + retLen = Length; + + // Within the allocated space + block = Offset / disk->BlockSize; + Offset %= disk->BlockSize; + base = Ext2_int_GetBlockAddr(disk, inode.i_block, block); + + // Write only block (if only one) + if(Offset + retLen <= disk->BlockSize) { + VFS_WriteAt(disk->FD, base+Offset, retLen, Buffer); + if(!bNewBlocks) return Length; + goto addBlocks; // Ugh! A goto, but it seems unavoidable + } + + // Write First Block + VFS_WriteAt(disk->FD, base+Offset, disk->BlockSize-Offset, Buffer); + Buffer += disk->BlockSize-Offset; + retLen -= disk->BlockSize-Offset; + block ++; + + // Write middle blocks + while(retLen > disk->BlockSize) + { + base = Ext2_int_GetBlockAddr(disk, inode.i_block, block); + VFS_WriteAt(disk->FD, base, disk->BlockSize, Buffer); + Buffer += disk->BlockSize; + retLen -= disk->BlockSize; + block ++; + } + + // Write last block + base = Ext2_int_GetBlockAddr(disk, inode.i_block, block); + VFS_WriteAt(disk->FD, base, retLen, Buffer); + if(!bNewBlocks) return Length; // Writing in only allocated space + } + else + base = Ext2_int_GetBlockAddr(disk, inode.i_block, allocSize/disk->BlockSize-1); + +addBlocks: + Warning("[EXT2 ] File extending is untested"); + + // Allocate blocks and copy data to them + retLen = Length - (allocSize-Offset); + while( retLen > disk->BlockSize ) + { + // Allocate a block + block = Ext2_int_AllocateBlock(disk, base/disk->BlockSize); + if(!block) return Length - retLen; + // Add it to this inode + if( !Ext2_int_AppendBlock(disk, &inode, block) ) { + Ext2_int_DeallocateBlock(disk, block); + goto ret; + } + // Copy data to the node + base = block * disk->BlockSize; + VFS_WriteAt(disk->FD, base, disk->BlockSize, Buffer); + // Update pointer and size remaining + inode.i_size += disk->BlockSize; + Buffer += disk->BlockSize; + retLen -= disk->BlockSize; + } + // Last block :D + block = Ext2_int_AllocateBlock(disk, base/disk->BlockSize); + if(!block) goto ret; + if( !Ext2_int_AppendBlock(disk, &inode, block) ) { + Ext2_int_DeallocateBlock(disk, block); + goto ret; + } + base = block * disk->BlockSize; + VFS_WriteAt(disk->FD, base, retLen, Buffer); + inode.i_size += retLen; + retLen = 0; + +ret: // Makes sure the changes to the inode are committed + Ext2_int_WriteInode(disk, Node->Inode, &inode); + return Length - retLen; +} + +/** + * \fn Uint32 Ext2_int_AllocateBlock(tExt2_Disk *Disk, Uint32 PrevBlock) + * \brief Allocate a block from the best possible location + * \param Disk EXT2 Disk Information Structure + * \param PrevBlock Previous block ID in the file + */ +Uint32 Ext2_int_AllocateBlock(tExt2_Disk *Disk, Uint32 PrevBlock) +{ + int bpg = Disk->SuperBlock.s_blocks_per_group; + Uint blockgroup = PrevBlock / bpg; + Uint bitmap[Disk->BlockSize/sizeof(Uint)]; + Uint bitsperblock = 8*Disk->BlockSize; + int i, j = 0; + Uint block; + + // Are there any free blocks? + if(Disk->SuperBlock.s_free_blocks_count == 0) return 0; + + if(Disk->Groups[blockgroup].bg_free_blocks_count > 0) + { + // Search block group's bitmap + for(i = 0; i < bpg; i++) + { + // Get the block in the bitmap block + j = i & (bitsperblock-1); + + // Read in if needed + if(j == 0) { + VFS_ReadAt( + Disk->FD, + (Uint64)Disk->Groups[blockgroup].bg_block_bitmap + i / bitsperblock, + Disk->BlockSize, + bitmap + ); + } + + // Fast Check + if( bitmap[j/32] == -1 ) { + j = (j + 31) & ~31; + continue; + } + + // Is the bit set? + if( bitmap[j/32] & (1 << (j%32)) ) + continue; + + // Ooh! We found one + break; + } + if( i < bpg ) { + Warning("[EXT2 ] Inconsistency detected, Group Free Block count is non-zero when no free blocks exist"); + goto checkAll; // Search the entire filesystem for a free block + // Goto needed for neatness + } + + // Mark as used + bitmap[j/32] |= (1 << (j%32)); + VFS_WriteAt( + Disk->FD, + (Uint64)Disk->Groups[blockgroup].bg_block_bitmap + i / bitsperblock, + Disk->BlockSize, + bitmap + ); + block = i; + Disk->Groups[blockgroup].bg_free_blocks_count --; + #if EXT2_UPDATE_WRITEBACK + //Ext2_int_UpdateBlockGroup(Disk, blockgroup); + #endif + } + else + { + checkAll: + Warning("[EXT2 ] TODO - Implement using blocks outside the current block group"); + return 0; + } + + // Reduce global count + Disk->SuperBlock.s_free_blocks_count --; + #if EXT2_UPDATE_WRITEBACK + Ext2_int_UpdateSuperblock(Disk); + #endif + + return block; +} + +/** + * \brief Deallocates a block + */ +void Ext2_int_DeallocateBlock(tExt2_Disk *Disk, Uint32 Block) +{ +} + +/** + * \brief Append a block to an inode + */ +int Ext2_int_AppendBlock(tExt2_Disk *Disk, tExt2_Inode *Inode, Uint32 Block) +{ + int nBlocks; + int dwPerBlock = Disk->BlockSize / 4; + Uint32 *blocks; + Uint32 id1, id2; + + nBlocks = (Inode->i_size + Disk->BlockSize - 1) / Disk->BlockSize; + + // Direct Blocks + if( nBlocks < 12 ) { + Inode->i_block[nBlocks] = Block; + return 0; + } + + blocks = malloc( Disk->BlockSize ); + if(!blocks) return 1; + + nBlocks -= 12; + // Single Indirect + if( nBlocks < dwPerBlock) + { + // Allocate/Get Indirect block + if( nBlocks == 0 ) { + Inode->i_block[12] = Ext2_int_AllocateBlock(Disk, Inode->i_block[0]); + if( !Inode->i_block[12] ) { + free(blocks); + return 1; + } + memset(blocks, 0, Disk->BlockSize); + } + else + VFS_ReadAt(Disk->FD, Inode->i_block[12]*Disk->BlockSize, Disk->BlockSize, blocks); + + blocks[nBlocks] = Block; + + VFS_WriteAt(Disk->FD, Inode->i_block[12]*Disk->BlockSize, Disk->BlockSize, blocks); + free(blocks); + return 0; + } + + nBlocks += dwPerBlock; + // Double Indirect + if( nBlocks < dwPerBlock*dwPerBlock ) + { + // Allocate/Get Indirect block + if( nBlocks == 0 ) { + Inode->i_block[13] = Ext2_int_AllocateBlock(Disk, Inode->i_block[0]); + if( !Inode->i_block[13] ) { + free(blocks); + return 1; + } + memset(blocks, 0, Disk->BlockSize); + } + else + VFS_ReadAt(Disk->FD, Inode->i_block[13]*Disk->BlockSize, Disk->BlockSize, blocks); + + // Allocate / Get Indirect lvl2 Block + if( nBlocks % dwPerBlock == 0 ) { + id1 = Ext2_int_AllocateBlock(Disk, Inode->i_block[0]); + if( !id1 ) { + free(blocks); + return 1; + } + blocks[nBlocks/dwPerBlock] = id1; + // Write back indirect 1 block + VFS_WriteAt(Disk->FD, Inode->i_block[13]*Disk->BlockSize, Disk->BlockSize, blocks); + memset(blocks, 0, Disk->BlockSize); + } + else { + id1 = blocks[nBlocks / dwPerBlock]; + VFS_ReadAt(Disk->FD, id1*Disk->BlockSize, Disk->BlockSize, blocks); + } + + blocks[nBlocks % dwPerBlock] = Block; + + VFS_WriteAt(Disk->FD, id1*Disk->BlockSize, Disk->BlockSize, blocks); + free(blocks); + return 0; + } + + nBlocks -= dwPerBlock*dwPerBlock; + // Triple Indirect + if( nBlocks < dwPerBlock*dwPerBlock*dwPerBlock ) + { + // Allocate/Get Indirect block + if( nBlocks == 0 ) { + Inode->i_block[14] = Ext2_int_AllocateBlock(Disk, Inode->i_block[0]); + if( !Inode->i_block[14] ) { + free(blocks); + return 1; + } + memset(blocks, 0, Disk->BlockSize); + } + else + VFS_ReadAt(Disk->FD, Inode->i_block[14]*Disk->BlockSize, Disk->BlockSize, blocks); + + // Allocate / Get Indirect lvl2 Block + if( (nBlocks/dwPerBlock) % dwPerBlock == 0 && nBlocks % dwPerBlock == 0 ) + { + id1 = Ext2_int_AllocateBlock(Disk, Inode->i_block[0]); + if( !id1 ) { + free(blocks); + return 1; + } + blocks[nBlocks/dwPerBlock] = id1; + // Write back indirect 1 block + VFS_WriteAt(Disk->FD, Inode->i_block[14]*Disk->BlockSize, Disk->BlockSize, blocks); + memset(blocks, 0, Disk->BlockSize); + } + else { + id1 = blocks[nBlocks / (dwPerBlock*dwPerBlock)]; + VFS_ReadAt(Disk->FD, id1*Disk->BlockSize, Disk->BlockSize, blocks); + } + + // Allocate / Get Indirect Level 3 Block + if( nBlocks % dwPerBlock == 0 ) { + id2 = Ext2_int_AllocateBlock(Disk, id1); + if( !id2 ) { + free(blocks); + return 1; + } + blocks[(nBlocks/dwPerBlock)%dwPerBlock] = id2; + // Write back indirect 1 block + VFS_WriteAt(Disk->FD, id1*Disk->BlockSize, Disk->BlockSize, blocks); + memset(blocks, 0, Disk->BlockSize); + } + else { + id2 = blocks[(nBlocks/dwPerBlock)%dwPerBlock]; + VFS_ReadAt(Disk->FD, id2*Disk->BlockSize, Disk->BlockSize, blocks); + } + + blocks[nBlocks % dwPerBlock] = Block; + + VFS_WriteAt(Disk->FD, id2*Disk->BlockSize, Disk->BlockSize, blocks); + free(blocks); + return 0; + } + + Warning("[EXT2 ] Inode %i cannot have a block appended to it, all indirects used"); + free(blocks); + return 1; +} diff --git a/Modules/Filesystems/FAT/Makefile b/Modules/Filesystems/FAT/Makefile new file mode 100644 index 00000000..dfa290b8 --- /dev/null +++ b/Modules/Filesystems/FAT/Makefile @@ -0,0 +1,7 @@ +# +# + +OBJ = fat.o +NAME = FAT + +-include ../Makefile.tpl diff --git a/Modules/Filesystems/FAT/fat.c b/Modules/Filesystems/FAT/fat.c new file mode 100644 index 00000000..f41b9ea0 --- /dev/null +++ b/Modules/Filesystems/FAT/fat.c @@ -0,0 +1,1128 @@ +/* + * Acess 2 + * FAT12/16/32 Driver Version (Incl LFN) + */ +#define DEBUG 0 +#define VERBOSE 1 + +#define CACHE_FAT 1 //!< Caches the FAT in memory +#define USE_LFN 1 //!< Enables the use of Long File Names + +#include +#include +#include +#include "fs_fat.h" + + +// === TYPES === +#if USE_LFN +typedef struct s_lfncache +{ + Uint Inode; + tFAT_VolInfo *Disk; + int id; + char Name[256]; + struct s_lfncache *Next; +} t_lfncache; +#endif + +// === PROTOTYPES === + int FAT_Install(char **Arguments); +tVFS_Node *FAT_InitDevice(char *device, char **options); +void FAT_Unmount(tVFS_Node *Node); + +Uint32 FAT_int_GetFatValue(tFAT_VolInfo *Disk, Uint32 Cluster); +Uint32 FAT_int_AllocateCluster(tFAT_VolInfo *Disk, Uint32 Previous); + +void FAT_int_ReadCluster(tFAT_VolInfo *Disk, Uint32 Cluster, int Length, void *Buffer); +void FAT_int_WriteCluster(tFAT_VolInfo *Disk, Uint32 Cluster, void *Buffer); + +Uint64 FAT_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer); +Uint64 FAT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer); +char *FAT_ReadDir(tVFS_Node *Node, int ID); +tVFS_Node *FAT_FindDir(tVFS_Node *Node, char *Name); + int FAT_Mknod(tVFS_Node *Node, char *Name, Uint Flags); + int FAT_Relink(tVFS_Node *node, char *OldName, char *NewName); +void FAT_CloseFile(tVFS_Node *node); + +// === SEMI-GLOBALS === +MODULE_DEFINE(0, (0<<8)|50 /*v0.50*/, VFAT, FAT_Install, NULL, NULL); +tFAT_VolInfo gFAT_Disks[8]; + int giFAT_PartCount = 0; +#if USE_LFN +t_lfncache *fat_lfncache; +#endif +tVFS_Driver gFAT_FSInfo = {"fat", 0, FAT_InitDevice, FAT_Unmount, NULL}; + +// === CODE === +/** + * \fn int FAT_Install(char **Arguments) + * \brief + */ +int FAT_Install(char **Arguments) +{ + VFS_AddDriver( &gFAT_FSInfo ); + return MODULE_ERR_OK; +} + +/** + * \fn tVFS_Node *FAT_InitDevice(char *Device, char **Options) + * \brief Reads the boot sector of a disk and prepares the structures for it + */ +tVFS_Node *FAT_InitDevice(char *Device, char **Options) +{ + fat_bootsect *bs; + int i; + Uint32 FATSz, RootDirSectors, TotSec; + tVFS_Node *node = NULL; + tFAT_VolInfo *diskInfo = &gFAT_Disks[giFAT_PartCount]; + + // Temporary Pointer + bs = &diskInfo->bootsect; + + //Open device and read boot sector + diskInfo->fileHandle = VFS_Open(Device, VFS_OPENFLAG_READ|VFS_OPENFLAG_WRITE); + if(diskInfo->fileHandle == -1) { + Warning("FAT_InitDisk - Unable to open device '%s'", Device); + return NULL; + } + + VFS_ReadAt(diskInfo->fileHandle, 0, 512, bs); + + if(bs->bps == 0 || bs->spc == 0) { + Warning("FAT_InitDisk - Error in FAT Boot Sector\n"); + return NULL; + } + + // FAT Type Determining + // - From Microsoft FAT Specifcation + RootDirSectors = ((bs->files_in_root*32) + (bs->bps - 1)) / bs->bps; + + if(bs->fatSz16 != 0) FATSz = bs->fatSz16; + else FATSz = bs->spec.fat32.fatSz32; + + if(bs->totalSect16 != 0) TotSec = bs->totalSect16; + else TotSec = bs->totalSect32; + + diskInfo->ClusterCount = (TotSec - (bs->resvSectCount + (bs->fatCount * FATSz) + RootDirSectors)) / bs->spc; + + if(diskInfo->ClusterCount < 4085) + diskInfo->type = FAT12; + else if(diskInfo->ClusterCount < 65525) + diskInfo->type = FAT16; + else + diskInfo->type = FAT32; + + #if VERBOSE + { + char *sFatType, *sSize; + Uint iSize = diskInfo->ClusterCount * bs->spc * bs->bps / 1024; + + switch(diskInfo->type) + { + case FAT12: sFatType = "FAT12"; break; + case FAT16: sFatType = "FAT16"; break; + case FAT32: sFatType = "FAT32"; break; + default: sFatType = "UNKNOWN"; break; + } + if(iSize <= 2*1024) { + sSize = "KiB"; + } + else if(iSize <= 2*1024*1024) { + sSize = "MiB"; + iSize >>= 10; + } + else { + sSize = "GiB"; + iSize >>= 20; + } + Log("[FAT ] '%s' %s, %i %s", Device, sFatType, iSize, sSize); + } + #endif + + // Get Name + if(diskInfo->type == FAT32) { + for(i=0;i<11;i++) + diskInfo->name[i] = (bs->spec.fat32.label[i] == ' ' ? '\0' : bs->spec.fat32.label[i]); + } + else { + for(i=0;i<11;i++) + diskInfo->name[i] = (bs->spec.fat16.label[i] == ' ' ? '\0' : bs->spec.fat16.label[i]); + } + diskInfo->name[11] = '\0'; + + // Compute Root directory offset + if(diskInfo->type == FAT32) + diskInfo->rootOffset = bs->spec.fat32.rootClust; + else + diskInfo->rootOffset = (FATSz * bs->fatCount) / bs->spc; + + diskInfo->firstDataSect = bs->resvSectCount + (bs->fatCount * FATSz) + RootDirSectors; + + //Allow for Caching the FAT + #if CACHE_FAT + { + Uint32 Ofs; + diskInfo->FATCache = (Uint32*)malloc(sizeof(Uint32)*diskInfo->ClusterCount); + if(diskInfo->FATCache == NULL) { + Warning("FAT_InitDisk - Heap Exhausted\n"); + return NULL; + } + Ofs = bs->resvSectCount*512; + if(diskInfo->type == FAT12) + { + Uint32 val; + int j; + char buf[1536]; + for(i = 0; i < diskInfo->ClusterCount/2; i++) { + j = i & 511; //%512 + if( j == 0 ) { + VFS_ReadAt(diskInfo->fileHandle, Ofs, 3*512, buf); + Ofs += 3*512; + } + val = *((int*)(buf+j*3)); + diskInfo->FATCache[i*2] = val & 0xFFF; + diskInfo->FATCache[i*2+1] = (val>>12) & 0xFFF; + } + } + else if(diskInfo->type == FAT16) + { + Uint16 buf[256]; + for(i=0;iClusterCount;i++) { + if( (i & 255) == 0 ) { + VFS_ReadAt(diskInfo->fileHandle, Ofs, 512, buf); + Ofs += 512; + } + diskInfo->FATCache[i] = buf[i&255]; + } + } + else if(diskInfo->type == FAT32) + { + Uint32 buf[128]; + for(i=0;iClusterCount;i++) { + if( (i & 127) == 0 ) { + VFS_ReadAt(diskInfo->fileHandle, Ofs, 512, buf); + Ofs += 512; + } + diskInfo->FATCache[i] = buf[i&127]; + } + } + LOG("FAT Fully Cached"); + } + #endif /*CACHE_FAT*/ + + diskInfo->BytesPerCluster = bs->spc * bs->bps; + + // Initalise inode cache for filesystem + diskInfo->inodeHandle = Inode_GetHandle(); + LOG("Inode Cache handle is %i", diskInfo->inodeHandle); + + // == VFS Interface + node = &diskInfo->rootNode; + node->Size = bs->files_in_root; + node->Inode = diskInfo->rootOffset; // 0:31 - Cluster, 32:63 - Parent Directory Cluster + node->ImplPtr = diskInfo; // Disk info pointer + node->ImplInt = 0; // 0:15 - Directory Index, 16: Dirty Flag + + node->ReferenceCount = 1; + + node->UID = 0; node->GID = 0; + node->NumACLs = 1; + node->ACLs = &gVFS_ACL_EveryoneRWX; + node->Flags = VFS_FFLAG_DIRECTORY; + node->CTime = node->MTime = node->ATime = now(); + + node->Read = node->Write = NULL; + node->ReadDir = FAT_ReadDir; + node->FindDir = FAT_FindDir; + node->Relink = FAT_Relink; + node->MkNod = FAT_Mknod; + //node->Close = FAT_Unmount; + + giFAT_PartCount ++; + return node; +} + +/** + * \brief Closes a mount and marks it as free + * \param Node Mount Root + * + * \todo Remove FAT Cache + * \todo Clear LFN Cache + * \todo Check that all files are closed and flushed + */ +void FAT_Unmount(tVFS_Node *Node) +{ + tFAT_VolInfo *disk = Node->ImplPtr; + + // Close Disk Handle + VFS_Close( disk->fileHandle ); + // Clear Node Cache + Inode_ClearCache(disk->inodeHandle); + // Mark as unused + disk->fileHandle = -2; + return; +} + +/* + * === FILE IO === + */ +/** + * \fn Uint32 FAT_int_GetFatValue(tFAT_VolInfo *Disk, Uint32 cluster) + * \brief Fetches a value from the FAT + */ +Uint32 FAT_int_GetFatValue(tFAT_VolInfo *Disk, Uint32 cluster) +{ + Uint32 val = 0; + #if !CACHE_FAT + Uint32 ofs = Disk->bootsect.resvSectCount*512; + #endif + ENTER("pDisk xCluster", Disk, cluster); + LOCK( &Disk->lFAT ); + #if CACHE_FAT + val = Disk->FATCache[cluster]; + if(Disk->type == FAT12 && val == EOC_FAT12) val = -1; + if(Disk->type == FAT16 && val == EOC_FAT16) val = -1; + if(Disk->type == FAT32 && val == EOC_FAT32) val = -1; + #else + if(Disk->type == FAT12) { + VFS_ReadAt(Disk->fileHandle, ofs+(cluster>>1)*3, 3, &val); + val = (cluster&1 ? val&0xFFF : val>>12); + if(val == EOC_FAT12) val = -1; + } else if(Disk->type == FAT16) { + VFS_ReadAt(Disk->fileHandle, ofs+cluster*2, 2, &val); + if(val == EOC_FAT16) val = -1; + } else { + VFS_ReadAt(Disk->fileHandle, ofs+cluster*4, 4, &val); + if(val == EOC_FAT32) val = -1; + } + #endif /*CACHE_FAT*/ + RELEASE( &Disk->lFAT ); + LEAVE('x', val); + return val; +} + +/** + * \brief Allocate a new cluster + */ +Uint32 FAT_int_AllocateCluster(tFAT_VolInfo *Disk, Uint32 Previous) +{ + Uint32 ret = Previous; + #if CACHE_FAT + Uint32 eoc; + + LOCK(Disk->lFAT); + for(ret = Previous; ret < Disk->ClusterCount; ret++) + { + if(Disk->FATCache[ret] == 0) + goto append; + } + for(ret = 0; ret < Previous; ret++) + { + if(Disk->FATCache[ret] == 0) + goto append; + } + + RELEASE(Disk->lFAT); + return 0; + +append: + switch(Disk->type) + { + case FAT12: eoc = EOC_FAT12; break; + case FAT16: eoc = EOC_FAT16; break; + case FAT32: eoc = EOC_FAT32; break; + default: return 0; + } + + Disk->FATCache[ret] = eoc; + Disk->FATCache[Previous] = ret; + + RELEASE(Disk->lFAT); + return ret; + #else + Uint32 val; + //Uint8 buf[512]; + Warning("[FAT ] TODO: Implement cluster allocation with non cached FAT"); + return 0; + + if(Disk->type == FAT12) { + VFS_ReadAt(Disk->fileHandle, ofs+(Previous>>1)*3, 3, &val); + if( Previous & 1 ) { + val &= 0xFFF000; + val |= ret; + } + else { + val &= 0xFFF; + val |= ret<<12; + } + VFS_WriteAt(Disk->fileHandle, ofs+(Previous>>1)*3, 3, &val); + + VFS_ReadAt(Disk->fileHandle, ofs+(Cluster>>1)*3, 3, &val); + if( Cluster & 1 ) { + val &= 0xFFF000; + val |= eoc; + } + else { + val &= 0x000FFF; + val |= eoc<<12; + } + VFS_WriteAt(Disk->fileHandle, ofs+(Cluster>>1)*3, 3, &val); + } else if(Disk->type == FAT16) { + VFS_ReadAt(Disk->fileHandle, ofs+Previous*2, 2, &ret); + VFS_ReadAt(Disk->fileHandle, ofs+Cluster*2, 2, &eoc); + } else { + VFS_ReadAt(Disk->fileHandle, ofs+Previous*4, 4, &ret); + VFS_ReadAt(Disk->fileHandle, ofs+Cluster*4, 4, &eoc); + } + return ret; + #endif +} + +/** + * \brief Read a cluster + */ +void FAT_int_ReadCluster(tFAT_VolInfo *Disk, Uint32 Cluster, int Length, void *Buffer) +{ + ENTER("pDisk xCluster iLength pBuffer", Disk, Cluster, Length, Buffer); + //Log("Cluster = %i (0x%x)", Cluster, Cluster); + VFS_ReadAt( + Disk->fileHandle, + (Disk->firstDataSect + (Cluster-2)*Disk->bootsect.spc ) + * Disk->bootsect.bps, + Length, + Buffer + ); + LEAVE('-'); +} + +/** + * \brief Write a cluster to disk + */ +void FAT_int_WriteCluster(tFAT_VolInfo *Disk, Uint32 Cluster, void *Buffer) +{ + ENTER("pDisk xCluster pBuffer", Disk, Cluster, Buffer); + VFS_ReadAt( + Disk->fileHandle, + (Disk->firstDataSect + (Cluster-2)*Disk->bootsect.spc ) + * Disk->bootsect.bps, + Disk->BytesPerCluster, + Buffer + ); + LEAVE('-'); +} + +/** + * \fn Uint64 FAT_Read(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer) + * \brief Reads data from a specified file + */ +Uint64 FAT_Read(tVFS_Node *Node, Uint64 offset, Uint64 length, void *buffer) +{ + int preSkip, count; + int i, cluster, pos; + int bpc; + void *tmpBuf; + tFAT_VolInfo *disk = Node->ImplPtr; + + ENTER("pNode Xoffset Xlength pbuffer", Node, offset, length, buffer); + + // Calculate and Allocate Bytes Per Cluster + bpc = disk->BytesPerCluster; + tmpBuf = (void*) malloc(bpc); + if( !tmpBuf ) return 0; + + // Cluster is stored in Inode Field + cluster = Node->Inode & 0xFFFFFFFF; + + // Sanity Check offset + if(offset > Node->Size) { + //LOG("Reading past EOF (%i > %i)", offset, node->Size); + LEAVE('i', 0); + return 0; + } + // Clamp Size + if(offset + length > Node->Size) { + //LOG("Reading past EOF (%lli + %lli > %lli), clamped to %lli", + // offset, length, node->Size, node->Size - offset); + length = Node->Size - offset; + } + + // Single Cluster including offset + if(length + offset < bpc) + { + FAT_int_ReadCluster(disk, cluster, bpc, tmpBuf); + memcpy( buffer, (void*)( tmpBuf + offset%bpc ), length ); + free(tmpBuf); + LEAVE('i', 1); + return length; + } + + preSkip = offset / bpc; + + //Skip previous clusters + for(i=preSkip;i--;) { + cluster = FAT_int_GetFatValue(disk, cluster); + if(cluster == -1) { + Warning("FAT_Read - Offset is past end of cluster chain mark"); + LEAVE('i', 0); + return 0; + } + } + + // Get Count of Clusters to read + count = ((offset%bpc+length) / bpc) + 1; + + // Get buffer Position after 1st cluster + pos = bpc - offset%bpc; + + // Read 1st Cluster + FAT_int_ReadCluster(disk, cluster, bpc, tmpBuf); + memcpy( + buffer, + (void*)( tmpBuf + (bpc-pos) ), + (pos < length ? pos : length) + ); + + if (count == 1) { + free(tmpBuf); + LEAVE('i', 1); + return length; + } + + cluster = FAT_int_GetFatValue(disk, cluster); + + #if DEBUG + LOG("pos=%i\n", pos); + LOG("Reading the rest of the clusters\n"); + #endif + + + //Read the rest of the cluster data + for( i = 1; i < count-1; i++ ) + { + FAT_int_ReadCluster(disk, cluster, bpc, tmpBuf); + memcpy((void*)(buffer+pos), tmpBuf, bpc); + pos += bpc; + cluster = FAT_int_GetFatValue(disk, cluster); + if(cluster == -1) { + Warning("FAT_Read - Read past End of Cluster Chain"); + free(tmpBuf); + LEAVE('i', 0); + return 0; + } + } + + FAT_int_ReadCluster(disk, cluster, bpc, tmpBuf); + memcpy((void*)(buffer+pos), tmpBuf, length-pos); + + #if DEBUG + LOG("Free tmpBuf(0x%x) and Return\n", tmpBuf); + #endif + + free(tmpBuf); + LEAVE('X', length); + return length; +} + +/** + * \brief Write to a file + * \param Node File Node + * \param Offset Offset within file + * \param Length Size of data to write + * \param Buffer Data source + */ +Uint64 FAT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) +{ + tFAT_VolInfo *disk = Node->ImplPtr; + void *tmpBuf; + int remLength = Length; + Uint32 cluster, tmpCluster; + int bNewCluster = 0; + + if(Offset > Node->Size) return 0; + + // Seek Clusters + cluster = Node->Inode & 0xFFFFFFFF; + while( Offset > disk->BytesPerCluster ) + { + cluster = FAT_int_GetFatValue( disk, cluster ); + if(cluster == -1) { + Warning("[FAT ] EOC Unexpectedly Reached"); + return 0; + } + Offset -= disk->BytesPerCluster; + } + if( Offset == disk->BytesPerCluster ) + { + Uint32 tmp = FAT_int_AllocateCluster(disk, cluster); + if(!tmp) return 0; + cluster = tmp; + Offset -= disk->BytesPerCluster; + } + + if( Offset + Length < disk->BytesPerCluster ) + { + tmpBuf = malloc( disk->BytesPerCluster ); + + // Read-Modify-Write + FAT_int_ReadCluster( disk, cluster, disk->BytesPerCluster, tmpBuf ); + memcpy( tmpBuf + Offset, Buffer, Length ); + FAT_int_WriteCluster( disk, cluster, tmpBuf ); + + free(tmpBuf); + return Length; + } + + // Clean up changes within a cluster + if( Offset ) + { + tmpBuf = malloc( disk->BytesPerCluster ); + + // Read-Modify-Write + FAT_int_ReadCluster( disk, cluster, disk->BytesPerCluster, tmpBuf ); + memcpy( tmpBuf + Offset, Buffer, disk->BytesPerCluster - Offset ); + FAT_int_WriteCluster( disk, cluster, tmpBuf ); + + free(tmpBuf); + + remLength -= disk->BytesPerCluster - Offset; + Buffer += disk->BytesPerCluster - Offset; + + // Get next cluster (allocating if needed) + tmpCluster = FAT_int_GetFatValue(disk, cluster); + if(tmpCluster == -1) { + tmpCluster = FAT_int_AllocateCluster(disk, cluster); + if( tmpCluster == 0 ) { + return Length - remLength; + } + } + cluster = tmpCluster; + } + + while( remLength > disk->BytesPerCluster ) + { + FAT_int_WriteCluster( disk, cluster, Buffer ); + Buffer += disk->BytesPerCluster; + + // Get next cluster (allocating if needed) + tmpCluster = FAT_int_GetFatValue(disk, cluster); + if(tmpCluster == -1) { + bNewCluster = 1; + tmpCluster = FAT_int_AllocateCluster(disk, cluster); + if( tmpCluster == 0 ) { + return Length - remLength; + } + } + cluster = tmpCluster; + } + + // Finish off + tmpBuf = malloc( disk->BytesPerCluster ); + if( bNewCluster ) + memset(tmpBuf, 0, disk->BytesPerCluster); + else + FAT_int_ReadCluster( disk, cluster, disk->BytesPerCluster, tmpBuf ); + memcpy( tmpBuf, Buffer, remLength ); + FAT_int_WriteCluster( disk, cluster, tmpBuf ); + free( tmpBuf ); + + return Length; +} + +/** + * \fn void FAT_int_ProperFilename(char *dest, char *src) + * \brief Converts a FAT directory entry name into a proper filename + */ +void FAT_int_ProperFilename(char *dest, char *src) +{ + int a, b; + + for( a = 0; a < 8; a++) { + if(src[a] == ' ') break; + dest[a] = src[a]; + } + b = a; + a = 8; + if(src[8] != ' ') + dest[b++] = '.'; + for( ; a < 11; a++, b++) { + if(src[a] == ' ') break; + dest[b] = src[a]; + } + dest[b] = '\0'; + #if DEBUG + //LOG("dest='%s'", dest); + #endif +} + +/** + * \fn char *FAT_int_CreateName(tVFS_Node *parent, fat_filetable *ft, char *LongFileName) + * \brief Converts either a LFN or a 8.3 Name into a proper name + */ +char *FAT_int_CreateName(tVFS_Node *parent, fat_filetable *ft, char *LongFileName) +{ + char *ret; + int len; + #if USE_LFN + if(LongFileName && LongFileName[0] != '\0') + { + len = strlen(LongFileName); + ret = malloc(len+1); + strcpy(ret, LongFileName); + } + else + { + #endif + ret = (char*) malloc(13); + memset(ret, 13, '\0'); + FAT_int_ProperFilename(ret, ft->name); + #if USE_LFN + } + #endif + return ret; +} + +/** + * \fn tVFS_Node *FAT_int_CreateNode(tVFS_Node *parent, fat_filetable *ft, char *LongFileName) + * \brief Creates a tVFS_Node structure for a given file entry + */ +tVFS_Node *FAT_int_CreateNode(tVFS_Node *parent, fat_filetable *ft, char *LongFileName) +{ + tVFS_Node node = {0}; + tVFS_Node *ret; + tFAT_VolInfo *disk = parent->ImplPtr; + + ENTER("pParent pFT sLongFileName", parent, ft, LongFileName); + + // Set Other Data + node.Inode = ft->cluster | (ft->clusterHi<<16); + node.Size = ft->size; + LOG("ft->size = %i", ft->size); + node.ImplPtr = parent->ImplPtr; + node.UID = 0; node.GID = 0; + node.NumACLs = 1; + + node.Flags = 0; + if(ft->attrib & ATTR_DIRECTORY) node.Flags |= VFS_FFLAG_DIRECTORY; + if(ft->attrib & ATTR_READONLY) { + node.Flags |= VFS_FFLAG_READONLY; + node.ACLs = &gVFS_ACL_EveryoneRX; // R-XR-XR-X + } + else { + node.ACLs = &gVFS_ACL_EveryoneRWX; // RWXRWXRWX + } + + node.ATime = timestamp(0,0,0, + ((ft->adate&0x1F)-1), //Days + ((ft->adate&0x1E0)-1), //Months + 1980+((ft->adate&0xFF00)>>8)); //Years + + node.CTime = ft->ctimems * 10; //Miliseconds + node.CTime += timestamp( + (ft->ctime&0x1F)<<1, //Seconds + ((ft->ctime&0x3F0)>>5), //Minutes + ((ft->ctime&0xF800)>>11), //Hours + ((ft->cdate&0x1F)-1), //Days + ((ft->cdate&0x1E0)-1), //Months + 1980+((ft->cdate&0xFF00)>>8)); //Years + + node.MTime = timestamp( + (ft->mtime&0x1F)<<1, //Seconds + ((ft->mtime&0x3F0)>>5), //Minuites + ((ft->mtime&0xF800)>>11), //Hours + ((ft->mdate&0x1F)-1), //Days + ((ft->mdate&0x1E0)-1), //Months + 1980+((ft->mdate&0xFF00)>>8)); //Years + + if(node.Flags & VFS_FFLAG_DIRECTORY) { + node.ReadDir = FAT_ReadDir; + node.FindDir = FAT_FindDir; + node.MkNod = FAT_Mknod; + node.Size = -1; + } else { + node.Read = FAT_Read; + node.Write = FAT_Write; + } + node.Close = FAT_CloseFile; + node.Relink = FAT_Relink; + + ret = Inode_CacheNode(disk->inodeHandle, &node); + LEAVE('p', ret); + return ret; +} + +#if USE_LFN +/** + \fn char *FAT_int_GetLFN(tVFS_Node *node) + \brief Return pointer to LFN cache entry + */ +char *FAT_int_GetLFN(tVFS_Node *node) +{ + t_lfncache *tmp; + tmp = fat_lfncache; + while(tmp) + { + if(tmp->Inode == node->Inode && tmp->Disk == node->ImplPtr) + return tmp->Name; + tmp = tmp->Next; + } + tmp = malloc(sizeof(t_lfncache)); + tmp->Inode = node->Inode; + tmp->Disk = node->ImplPtr; + memset(tmp->Name, 0, 256); + + tmp->Next = fat_lfncache; + fat_lfncache = tmp; + + return tmp->Name; +} + +/** + \fn void FAT_int_DelLFN(tVFS_Node *node) + \brief Delete a LFN cache entry +*/ +void FAT_int_DelLFN(tVFS_Node *node) +{ + t_lfncache *tmp; + + if(!fat_lfncache) return; + + if(!fat_lfncache->Next) + { + tmp = fat_lfncache; + fat_lfncache = tmp->Next; + free(tmp); + return; + } + tmp = fat_lfncache; + while(tmp && tmp->Next) + { + if(tmp->Inode == node->Inode && tmp->Disk == node->ImplPtr) + { + free(tmp->Next); + tmp->Next = tmp->Next->Next; + return; + } + tmp = tmp->Next; + } +} +#endif + +/** + \fn char *FAT_ReadDir(tVFS_Node *Node, int ID) + \param Node Node structure of directory + \param ID Directory position +**/ +char *FAT_ReadDir(tVFS_Node *Node, int ID) +{ + fat_filetable fileinfo[16]; //Sizeof=32, 16 per sector + int a=0; + tFAT_VolInfo *disk = Node->ImplPtr; + Uint32 cluster, offset; + int preSkip; + char *ret; + #if USE_LFN + char *lfn = NULL; + #endif + + ENTER("pNode iID", Node, ID); + + // Get Byte Offset and skip + offset = ID * sizeof(fat_filetable); + preSkip = offset / (512 * disk->bootsect.spc); + LOG("disk->bootsect.spc = %i", disk->bootsect.spc); + LOG("Node->size = %i", Node->Size); + cluster = Node->Inode & 0xFFFFFFFF; // Cluster ID + + // Do Cluster Skip + // - Pre FAT32 had a reserved area for the root. + if( disk->type == FAT32 || cluster != disk->rootOffset ) + { + //Skip previous clusters + for(a=preSkip;a--;) { + cluster = FAT_int_GetFatValue(disk, cluster); + // Check for end of cluster chain + if(cluster == -1) { LEAVE('n'); return NULL;} + } + } + + // Bounds Checking (Used to spot heap overflows) + if(cluster > disk->ClusterCount + 2) + { + Warning("FAT_ReadDir - Cluster ID is over cluster count (0x%x>0x%x)", + cluster, disk->ClusterCount+2); + LEAVE('n'); + return NULL; + } + + LOG("cluster=0x%x, ID=%i", cluster, ID); + + // Compute Offsets + // - Pre FAT32 cluster base (in sectors) + if( cluster == disk->rootOffset && disk->type != FAT32 ) + offset = disk->bootsect.resvSectCount + cluster*disk->bootsect.spc; + else + { // FAT32 cluster base (in sectors) + offset = disk->firstDataSect; + offset += (cluster - 2) * disk->bootsect.spc; + } + // Sector in cluster + if(disk->bootsect.spc != 1) + offset += (ID / 16) % disk->bootsect.spc; + // Offset in sector + a = ID % 16; + + LOG("offset=%i, a=%i", offset, a); + + // Read Sector + VFS_ReadAt(disk->fileHandle, offset*512, 512, fileinfo); // Read Dir Data + + LOG("name[0] = 0x%x", (Uint8)fileinfo[a].name[0]); + //Check if this is the last entry + if( fileinfo[a].name[0] == '\0' ) { + Node->Size = ID; + LOG("End of list"); + LEAVE('n'); + return NULL; // break + } + + // Check for empty entry + if( (Uint8)fileinfo[a].name[0] == 0xE5 ) { + LOG("Empty Entry"); + LEAVE('p', VFS_SKIP); + return VFS_SKIP; // Skip + } + + #if USE_LFN + // Get Long File Name Cache + lfn = FAT_int_GetLFN(Node); + if(fileinfo[a].attrib == ATTR_LFN) + { + fat_longfilename *lfnInfo; + int len; + + lfnInfo = (fat_longfilename *) &fileinfo[a]; + if(lfnInfo->id & 0x40) memset(lfn, 0, 256); + // Get the current length + len = strlen(lfn); + + // Sanity Check (FAT implementations should not allow >255 bytes) + if(len + 13 > 255) return VFS_SKIP; + // Rebase all bytes + for(a=len+1;a--;) lfn[a+13] = lfn[a]; + + // Append new bytes + lfn[ 0] = lfnInfo->name1[0]; lfn[ 1] = lfnInfo->name1[1]; + lfn[ 2] = lfnInfo->name1[2]; lfn[ 3] = lfnInfo->name1[3]; + lfn[ 4] = lfnInfo->name1[4]; + lfn[ 5] = lfnInfo->name2[0]; lfn[ 6] = lfnInfo->name2[1]; + lfn[ 7] = lfnInfo->name2[2]; lfn[ 8] = lfnInfo->name2[3]; + lfn[ 9] = lfnInfo->name2[4]; lfn[10] = lfnInfo->name2[5]; + lfn[11] = lfnInfo->name3[0]; lfn[12] = lfnInfo->name3[1]; + LEAVE('p', VFS_SKIP); + return VFS_SKIP; + } + #endif + + //Check if it is a volume entry + if(fileinfo[a].attrib & 0x08) { + LEAVE('p', VFS_SKIP); + return VFS_SKIP; + } + // Ignore . and .. + if(fileinfo[a].name[0] == '.') { + LEAVE('p', VFS_SKIP); + return VFS_SKIP; + } + + LOG("name='%c%c%c%c%c%c%c%c.%c%c%c'\n", + fileinfo[a].name[0], fileinfo[a].name[1], fileinfo[a].name[2], fileinfo[a].name[3], + fileinfo[a].name[4], fileinfo[a].name[5], fileinfo[a].name[6], fileinfo[a].name[7], + fileinfo[a].name[8], fileinfo[a].name[9], fileinfo[a].name[10] ); + + #if USE_LFN + //node = FAT_int_CreateNode(Node, &fileinfo[a], lfn); + ret = FAT_int_CreateName(Node, &fileinfo[a], lfn); + lfn[0] = '\0'; + #else + //node = FAT_int_CreateNode(Node, &fileinfo[a], NULL); + ret = FAT_int_CreateName(Node, &fileinfo[a], NULL); + #endif + + LEAVE('s', ret); + return ret; +} + +/** + * \fn tVFS_Node *FAT_FindDir(tVFS_Node *node, char *name) + * \brief Finds an entry in the current directory + */ +tVFS_Node *FAT_FindDir(tVFS_Node *Node, char *name) +{ + fat_filetable fileinfo[16]; + char tmpName[11]; + #if USE_LFN + fat_longfilename *lfnInfo; + char *lfn = NULL; + int lfnPos=255, lfnId = -1; + #endif + int i=0; + tVFS_Node *tmpNode; + Uint64 diskOffset; + tFAT_VolInfo *disk = Node->ImplPtr; + Uint32 dirCluster; + Uint32 cluster; + + ENTER("pNode sname", Node, name); + + // Fast Returns + if(!name || name[0] == '\0') { + LEAVE('n'); + return NULL; + } + + #if USE_LFN + lfn = FAT_int_GetLFN(Node); + #endif + + dirCluster = Node->Inode & 0xFFFFFFFF; + // Seek to Directory + if( dirCluster == disk->rootOffset && disk->type != FAT32 ) + diskOffset = (disk->bootsect.resvSectCount+dirCluster*disk->bootsect.spc) << 9; + else + diskOffset = (disk->firstDataSect+(dirCluster-2)*disk->bootsect.spc) << 9; + + for(;;i++) + { + // Load sector + if((i & 0xF) == 0) { + //Log("FAT_FindDir: diskOffset = 0x%x", diskOffset); + VFS_ReadAt(disk->fileHandle, diskOffset, 512, fileinfo); + diskOffset += 512; + } + + //Check if the files are free + if(fileinfo[i&0xF].name[0] == '\0') break; //Free and last + if(fileinfo[i&0xF].name[0] == '\xE5') goto loadCluster; //Free + + + #if USE_LFN + // Long File Name Entry + if(fileinfo[i&0xF].attrib == ATTR_LFN) + { + lfnInfo = (fat_longfilename *) &fileinfo[i&0xF]; + if(lfnInfo->id & 0x40) { + memset(lfn, 0, 256); + lfnPos = 255; + } + lfn[lfnPos--] = lfnInfo->name3[1]; lfn[lfnPos--] = lfnInfo->name3[0]; + lfn[lfnPos--] = lfnInfo->name2[5]; lfn[lfnPos--] = lfnInfo->name2[4]; + lfn[lfnPos--] = lfnInfo->name2[3]; lfn[lfnPos--] = lfnInfo->name2[2]; + lfn[lfnPos--] = lfnInfo->name2[1]; lfn[lfnPos--] = lfnInfo->name2[0]; + lfn[lfnPos--] = lfnInfo->name1[4]; lfn[lfnPos--] = lfnInfo->name1[3]; + lfn[lfnPos--] = lfnInfo->name1[2]; lfn[lfnPos--] = lfnInfo->name1[1]; + lfn[lfnPos--] = lfnInfo->name1[0]; + if((lfnInfo->id&0x3F) == 1) + { + memcpy(lfn, lfn+lfnPos+1, 256-lfnPos); + lfnId = i+1; + } + } + else + { + // Remove LFN if it does not apply + if(lfnId != i) lfn[0] = '\0'; + #endif + // Get Real Filename + FAT_int_ProperFilename(tmpName, fileinfo[i&0xF].name); + + LOG("tmpName = '%s'", tmpName); + + //Only Long name is case sensitive, 8.3 is not + #if USE_LFN + if(strucmp(tmpName, name) == 0 || strcmp(lfn, name) == 0) { + #else + if(strucmp(tmpName, name) == 0) { + #endif + cluster = fileinfo[i&0xF].cluster | (fileinfo[i&0xF].clusterHi << 16); + tmpNode = Inode_GetCache(disk->inodeHandle, cluster); + if(tmpNode == NULL) // Node is not cached + { + #if USE_LFN + tmpNode = FAT_int_CreateNode(Node, &fileinfo[i&0xF], lfn); + #else + tmpNode = FAT_int_CreateNode(Node, &fileinfo[i&0xF], NULL); + #endif + } + #if USE_LFN + lfn[0] = '\0'; + #endif + LEAVE('p', tmpNode); + return tmpNode; + } + #if USE_LFN + } + #endif + + loadCluster: + //Load Next cluster? + if( ((i+1) >> 4) % disk->bootsect.spc == 0 && ((i+1) & 0xF) == 0) + { + if( dirCluster == disk->rootOffset && disk->type != FAT32 ) + continue; + dirCluster = FAT_int_GetFatValue(disk, dirCluster); + if(dirCluster == -1) break; + diskOffset = (disk->firstDataSect+(dirCluster-2)*disk->bootsect.spc)*512; + } + } + + LEAVE('n'); + return NULL; +} + +/** + * \fn int FAT_Mknod(tVFS_Node *Node, char *Name, Uint Flags) + * \brief Create a new node + */ +int FAT_Mknod(tVFS_Node *Node, char *Name, Uint Flags) +{ + return 0; +} + +/** + * \fn int FAT_Relink(tVFS_Node *Node, char *OldName, char *NewName) + * \brief Rename / Delete a file + */ +int FAT_Relink(tVFS_Node *Node, char *OldName, char *NewName) +{ + return 0; +} + +/** + * \fn void FAT_CloseFile(tVFS_Node *Node) + * \brief Close an open file + */ +void FAT_CloseFile(tVFS_Node *Node) +{ + tFAT_VolInfo *disk = Node->ImplPtr; + if(Node == NULL) return ; + + Inode_UncacheNode(disk->inodeHandle, Node->Inode); + #if USE_LFN + // If node has been uncached and is a directory, delete the LFN cache + if( !Inode_GetCache(disk->inodeHandle, Node->Inode) && Node->Flags & VFS_FFLAG_DIRECTORY) + FAT_int_DelLFN(Node); + else // Get Cache references the node, so dereference it + Inode_UncacheNode(disk->inodeHandle, Node->Inode); + #endif + return ; +} + +/** + * \fn void fat_install() + * \brief Add the FAT Filesystem to the VFS + */ +void fat_install() +{ + VFS_AddDriver( &gFAT_FSInfo ); +} diff --git a/Modules/Filesystems/FAT/fs_fat.h b/Modules/Filesystems/FAT/fs_fat.h new file mode 100644 index 00000000..84eee1d9 --- /dev/null +++ b/Modules/Filesystems/FAT/fs_fat.h @@ -0,0 +1,169 @@ +/* + * Acess2 + * FAT12/16/32 Driver + * vfs/fs/fs_fat.h + */ +#ifndef _FS_FAT_H_ +#define _FS_FAT_H_ + +// === On Disk Structures === +/** + * \struct fat_bootsect_s + * \brief Bootsector format + */ +struct fat_bootsect_s +{ + Uint8 jmp[3]; //!< Jump Instruction + char oemname[8]; //!< OEM Name. Typically MSDOS1.1 + Uint16 bps; //!< Bytes per Sector. Assumed to be 512 + Uint8 spc; //!< Sectors per Cluster + Uint16 resvSectCount; //!< Number of reserved sectors at beginning of volume + Uint8 fatCount; //!< Number of copies of the FAT + Uint16 files_in_root; //!< Count of files in the root directory + Uint16 totalSect16; //!< Total sector count (FAT12/16) + Uint8 mediaDesc; //!< Media Desctiptor + Uint16 fatSz16; //!< FAT Size (FAT12/16) + Uint16 spt; //!< Sectors per track. Ignored (Acess uses LBA) + Uint16 heads; //!< Heads. Ignored (Acess uses LBA) + Uint32 hiddenCount; //!< ??? + Uint32 totalSect32; //!< Total sector count (FAT32) + union { + struct { + Uint8 drvNum; //!< Drive Number. BIOS Drive ID (E.g. 0x80) + Uint8 resv; //!< Reserved byte + Uint8 bootSig; //!< Boot Signature. ??? + Uint32 volId; //!< Volume ID + char label[11]; //!< Disk Label + char fsType[8]; //!< FS Type. ??? + } __attribute__((packed)) fat16; //!< FAT16 Specific information + struct { + Uint32 fatSz32; //!< 32-Bit FAT Size + Uint16 extFlags; //!< Extended flags + Uint16 fsVer; //!< Filesystem Version + Uint32 rootClust; //!< Root Cluster ID + Uint16 fsInfo; //!< FS Info. ??? + Uint16 backupBS; //!< Backup Bootsector Sector Offset + char resv[12]; //!< Reserved Data + Uint8 drvNum; //!< Drive Number + char resv2; //!< Reserved Data + Uint8 bootSig; //!< Boot Signature. ??? + Uint32 volId; //!< Volume ID + char label[11]; //!< Disk Label + char fsType[8]; //!< Filesystem Type. ??? + } __attribute__((packed)) fat32; //!< FAT32 Specific Information + }__attribute__((packed)) spec; //!< Non Shared Data + char pad[512-90]; //!< Bootsector Data (Code/Boot Signature 0xAA55) +} __attribute__((packed)); + +/** + \struct fat_filetable_s + \brief Format of a 8.3 file entry on disk +*/ +struct fat_filetable_s { + char name[11]; //!< 8.3 Name + Uint8 attrib; //!< File Attributes. + Uint8 ntres; //!< Reserved for NT - Set to 0 + Uint8 ctimems; //!< 10ths of a second ranging from 0-199 (2 seconds) + Uint16 ctime; //!< Creation Time + Uint16 cdate; //!< Creation Date + Uint16 adate; //!< Accessed Data. No Time feild though + Uint16 clusterHi; //!< High Cluster. 0 for FAT12 and FAT16 + Uint16 mtime; //!< Last Modified Time + Uint16 mdate; //!< Last Modified Date + Uint16 cluster; //!< Low Word of First cluster + Uint32 size; //!< Size of file +} __attribute__((packed)); + +/** + \struct fat_longfilename_s + \brief Format of a long file name entry on disk +*/ +struct fat_longfilename_s { + Uint8 id; //!< ID of entry. Bit 6 is set for last entry + Uint16 name1[5]; //!< 5 characters of name + Uint8 attrib; //!< Attributes. Must be ATTR_LFN + Uint8 type; //!< Type. ??? + Uint8 checksum; //!< Checksum + Uint16 name2[6]; //!< 6 characters of name + Uint16 firstCluster; //!< Used for non LFN compatability. Set to 0 + Uint16 name3[2]; //!< Last 2 characters of name +} __attribute__((packed)); + +/** + * \name File Attributes + * \brief Flag values for ::fat_filetable_s.attrib + * \{ + */ +#define ATTR_READONLY 0x01 //!< Read-only file +#define ATTR_HIDDEN 0x02 //!< Hidden File +#define ATTR_SYSTEM 0x04 //!< System File +#define ATTR_VOLUMEID 0x08 //!< Volume ID (Deprecated) +#define ATTR_DIRECTORY 0x10 //!< Directory +/** + * \brief File needs archiving + * \note User set flag, no significance to the FS driver + */ +#define ATTR_ARCHIVE 0x20 +/** + * \brief Meta Attribute + * + * If ::fat_filetable_s.attrib equals ATTR_LFN the file is a LFN entry + */ +#define ATTR_LFN (ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUMEID) +/** + * \} + */ + +/** + * \brief Internal IDs for FAT types + */ +enum eFatType +{ + FAT12, //!< FAT12 Volume + FAT16, //!< FAT16 Volume + FAT32, //!< FAT32 Volume +}; + +/** + * \name End of Cluster marks + * \brief FAT values that indicate the end of a cluster chain in + * different versions. + * \{ + */ +#define EOC_FAT12 0x0FFF //!< FAT-12 Mark +#define EOC_FAT16 0xFFFF //!< FAT-16 Mark +#define EOC_FAT32 0x00FFFFFF //!< FAT-32 Mark +/** + * \} + */ + +typedef struct fat_bootsect_s fat_bootsect; +typedef struct fat_filetable_s fat_filetable; +typedef struct fat_longfilename_s fat_longfilename; + +// === Memory Structures === +/** + * \struct drv_fat_volinfo_s + * \brief Representation of a volume in memory + */ +struct drv_fat_volinfo_s +{ + int fileHandle; //!< File Handle + int type; //!< FAT Type. See eFatType + char name[12]; //!< Volume Name (With NULL Terminator) + tSpinlock lFAT; //!< Lock to prevent double-writing to the FAT + Uint32 firstDataSect; //!< First data sector + Uint32 rootOffset; //!< Root Offset (clusters) + Uint32 ClusterCount; //!< Total Cluster Count + fat_bootsect bootsect; //!< Boot Sector + tVFS_Node rootNode; //!< Root Node + int BytesPerCluster; + int inodeHandle; //!< Inode Cache Handle + #if CACHE_FAT + Uint32 *FATCache; //!< FAT Cache + #endif +}; + +typedef struct drv_fat_volinfo_s tFAT_VolInfo; + +#endif diff --git a/Modules/Filesystems/FS_Ext2/Makefile b/Modules/Filesystems/FS_Ext2/Makefile deleted file mode 100644 index 806e638c..00000000 --- a/Modules/Filesystems/FS_Ext2/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# -# - -OBJ = ext2.o read.o dir.o write.o -NAME = FS_Ext2 - --include ../Makefile.tpl diff --git a/Modules/Filesystems/FS_Ext2/dir.c b/Modules/Filesystems/FS_Ext2/dir.c deleted file mode 100644 index 0ab3ed39..00000000 --- a/Modules/Filesystems/FS_Ext2/dir.c +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Acess OS - * Ext2 Driver Version 1 - */ -/** - * \file dir.c - * \brief Second Extended Filesystem Driver - * \todo Implement file full write support - */ -#define DEBUG 1 -#define VERBOSE 0 -#include "ext2_common.h" - - -// === PROTOTYPES === -char *Ext2_ReadDir(tVFS_Node *Node, int Pos); -tVFS_Node *Ext2_FindDir(tVFS_Node *Node, char *FileName); - int Ext2_MkNod(tVFS_Node *Node, char *Name, Uint Flags); -tVFS_Node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeId, char *Name); - -// === CODE === -/** - \fn char *Ext2_ReadDir(tVFS_Node *Node, int Pos) - \brief Reads a directory entry -*/ -char *Ext2_ReadDir(tVFS_Node *Node, int Pos) -{ - tExt2_Inode inode; - char namebuf[EXT2_NAME_LEN+1]; - tExt2_DirEnt dirent; - Uint64 Base; // Block's Base Address - int block = 0, ofs = 0; - int entNum = 0; - tExt2_Disk *disk = Node->ImplPtr; - Uint size; - - ENTER("pNode iPos", Node, Pos); - - // Read directory's inode - //Ext2_int_GetInode(Node, &inode); - Ext2_int_ReadInode(disk, Node->Inode, &inode); - size = inode.i_size; - - LOG("inode.i_block[0] = 0x%x", inode.i_block[0]); - - // Find Entry - // Get First Block - // - Do this ourselves as it is a simple operation - Base = inode.i_block[0] * disk->BlockSize; - while(Pos -- && size > 0) - { - VFS_ReadAt( disk->FD, Base+ofs, sizeof(tExt2_DirEnt), &dirent); - ofs += dirent.rec_len; - size -= dirent.rec_len; - entNum ++; - - if(ofs >= disk->BlockSize) { - block ++; - if( ofs > disk->BlockSize ) { - Warning("[EXT2] Directory Entry %i of inode %i extends over a block boundary, ignoring", - entNum-1, Node->Inode); - } - ofs = 0; - Base = Ext2_int_GetBlockAddr( disk, inode.i_block, block ); - } - } - - // Check for the end of the list - if(size <= 0) { - LEAVE('n'); - return NULL; - } - - // Read Entry - VFS_ReadAt( disk->FD, Base+ofs, sizeof(tExt2_DirEnt), &dirent ); - //LOG("dirent.inode = %i", dirent.inode); - //LOG("dirent.rec_len = %i", dirent.rec_len); - //LOG("dirent.name_len = %i", dirent.name_len); - VFS_ReadAt( disk->FD, Base+ofs+sizeof(tExt2_DirEnt), dirent.name_len, namebuf ); - namebuf[ dirent.name_len ] = '\0'; // Cap off string - - - // Ignore . and .. (these are done in the VFS) - if( (namebuf[0] == '.' && namebuf[1] == '\0') - || (namebuf[0] == '.' && namebuf[1] == '.' && namebuf[2]=='\0')) { - LEAVE('p', VFS_SKIP); - return VFS_SKIP; // Skip - } - - LEAVE('s', namebuf); - // Create new node - return strdup(namebuf); -} - -/** - \fn tVFS_Node *Ext2_FindDir(tVFS_Node *node, char *filename) - \brief Gets information about a file - \param node vfs node - Parent Node - \param filename String - Name of file - \return VFS Node of file -*/ -tVFS_Node *Ext2_FindDir(tVFS_Node *Node, char *Filename) -{ - tExt2_Disk *disk = Node->ImplPtr; - tExt2_Inode inode; - char namebuf[EXT2_NAME_LEN+1]; - tExt2_DirEnt dirent; - Uint64 Base; // Block's Base Address - int block = 0, ofs = 0; - int entNum = 0; - Uint size; - - // Read directory's inode - Ext2_int_ReadInode(disk, Node->Inode, &inode); - size = inode.i_size; - - // Get First Block - // - Do this ourselves as it is a simple operation - Base = inode.i_block[0] * disk->BlockSize; - // Find File - while(size > 0) - { - VFS_ReadAt( disk->FD, Base+ofs, sizeof(tExt2_DirEnt), &dirent); - VFS_ReadAt( disk->FD, Base+ofs+sizeof(tExt2_DirEnt), dirent.name_len, namebuf ); - namebuf[ dirent.name_len ] = '\0'; // Cap off string - // If it matches, create a node and return it - if(strcmp(namebuf, Filename) == 0) - return Ext2_int_CreateNode( disk, dirent.inode, namebuf ); - // Increment pointers - ofs += dirent.rec_len; - size -= dirent.rec_len; - entNum ++; - - // Check for end of block - if(ofs >= disk->BlockSize) { - block ++; - if( ofs > disk->BlockSize ) { - Warning("[EXT2 ] Directory Entry %i of inode %i extends over a block boundary, ignoring", - entNum-1, Node->Inode); - } - ofs = 0; - Base = Ext2_int_GetBlockAddr( disk, inode.i_block, block ); - } - } - - return NULL; -} - -/** - * \fn int Ext2_MkNod(tVFS_Node *Parent, char *Name, Uint Flags) - * \brief Create a new node - */ -int Ext2_MkNod(tVFS_Node *Parent, char *Name, Uint Flags) -{ - return 0; -} - -// ---- INTERNAL FUNCTIONS ---- -/** - * \fn vfs_node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeID, char *Name) - * \brief Create a new VFS Node - */ -tVFS_Node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeID, char *Name) -{ - tExt2_Inode inode; - tVFS_Node retNode; - tVFS_Node *tmpNode; - - if( !Ext2_int_ReadInode(Disk, InodeID, &inode) ) - return NULL; - - if( (tmpNode = Inode_GetCache(Disk->CacheID, InodeID)) ) - return tmpNode; - - - // Set identifiers - retNode.Inode = InodeID; - retNode.ImplPtr = Disk; - - // Set file length - retNode.Size = inode.i_size; - - // Set Access Permissions - retNode.UID = inode.i_uid; - retNode.GID = inode.i_gid; - retNode.NumACLs = 3; - retNode.ACLs = VFS_UnixToAcessACL(inode.i_mode & 0777, inode.i_uid, inode.i_gid); - - // Set Function Pointers - retNode.Read = Ext2_Read; - retNode.Write = Ext2_Write; - retNode.Close = Ext2_CloseFile; - - switch(inode.i_mode & EXT2_S_IFMT) - { - // Symbolic Link - case EXT2_S_IFLNK: - retNode.Flags = VFS_FFLAG_SYMLINK; - break; - // Regular File - case EXT2_S_IFREG: - retNode.Flags = 0; - retNode.Size |= (Uint64)inode.i_dir_acl << 32; - break; - // Directory - case EXT2_S_IFDIR: - retNode.ReadDir = Ext2_ReadDir; - retNode.FindDir = Ext2_FindDir; - retNode.MkNod = Ext2_MkNod; - //retNode.Relink = Ext2_Relink; - retNode.Flags = VFS_FFLAG_DIRECTORY; - break; - // Unknown, Write protect and hide it to be safe - default: - retNode.Flags = VFS_FFLAG_READONLY;//|VFS_FFLAG_HIDDEN; - break; - } - - // Check if the file should be hidden - //if(Name[0] == '.') retNode.Flags |= VFS_FFLAG_HIDDEN; - - // Set Timestamps - retNode.ATime = now(); - retNode.MTime = inode.i_mtime * 1000; - retNode.CTime = inode.i_ctime * 1000; - - // Save in node cache and return saved node - return Inode_CacheNode(Disk->CacheID, &retNode); -} diff --git a/Modules/Filesystems/FS_Ext2/ext2.c b/Modules/Filesystems/FS_Ext2/ext2.c deleted file mode 100644 index c2c2df9c..00000000 --- a/Modules/Filesystems/FS_Ext2/ext2.c +++ /dev/null @@ -1,330 +0,0 @@ -/* - * Acess OS - * Ext2 Driver Version 1 - */ -/** - * \file fs/ext2.c - * \brief Second Extended Filesystem Driver - * \todo Implement file full write support - */ -#define DEBUG 1 -#define VERBOSE 0 -#include "ext2_common.h" -#include - -// === PROTOTYPES === - int Ext2_Install(char **Arguments); -// Interface Functions -tVFS_Node *Ext2_InitDevice(char *Device, char **Options); -void Ext2_Unmount(tVFS_Node *Node); -void Ext2_CloseFile(tVFS_Node *Node); -// Internal Helpers - int Ext2_int_GetInode(tVFS_Node *Node, tExt2_Inode *Inode); -Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum); -Uint32 Ext2_int_AllocateInode(tExt2_Disk *Disk, Uint32 Parent); -void Ext2_int_UpdateSuperblock(tExt2_Disk *Disk); - -// === SEMI-GLOBALS === -MODULE_DEFINE(0, 0x5B /*v0.90*/, FS_Ext2, Ext2_Install, NULL); -tExt2_Disk gExt2_disks[6]; - int giExt2_count = 0; -tVFS_Driver gExt2_FSInfo = { - "ext2", 0, Ext2_InitDevice, Ext2_Unmount, NULL - }; - -// === CODE === - -/** - * \fn int Ext2_Install(char **Arguments) - * \brief Install the Ext2 Filesystem Driver - */ -int Ext2_Install(char **Arguments) -{ - VFS_AddDriver( &gExt2_FSInfo ); - return MODULE_ERR_OK; -} - -/** - \fn tVFS_Node *Ext2_InitDevice(char *Device, char **Options) - \brief Initializes a device to be read by by the driver - \param Device String - Device to read from - \param Options NULL Terminated array of option strings - \return Root Node -*/ -tVFS_Node *Ext2_InitDevice(char *Device, char **Options) -{ - tExt2_Disk *disk; - int fd; - int groupCount; - tExt2_SuperBlock sb; - tExt2_Inode inode; - - ENTER("sDevice pOptions", Device, Options); - - // Open Disk - fd = VFS_Open(Device, VFS_OPENFLAG_READ|VFS_OPENFLAG_WRITE); //Open Device - if(fd == -1) { - Warning("[EXT2 ] Unable to open '%s'", Device); - LEAVE('n'); - return NULL; - } - - // Read Superblock at offset 1024 - VFS_ReadAt(fd, 1024, 1024, &sb); // Read Superblock - - // Sanity Check Magic value - if(sb.s_magic != 0xEF53) { - Warning("[EXT2 ] Volume '%s' is not an EXT2 volume", Device); - VFS_Close(fd); - LEAVE('n'); - return NULL; - } - - // Get Group count - groupCount = DivUp(sb.s_blocks_count, sb.s_blocks_per_group); - LOG("groupCount = %i", groupCount); - - // Allocate Disk Information - disk = malloc(sizeof(tExt2_Disk) + sizeof(tExt2_Group)*groupCount); - if(!disk) { - Warning("[EXT2 ] Unable to allocate disk structure"); - VFS_Close(fd); - LEAVE('n'); - return NULL; - } - disk->FD = fd; - memcpy(&disk->SuperBlock, &sb, 1024); - disk->GroupCount = groupCount; - - // Get an inode cache handle - disk->CacheID = Inode_GetHandle(); - - // Get Block Size - LOG("s_log_block_size = 0x%x", sb.s_log_block_size); - disk->BlockSize = 1024 << sb.s_log_block_size; - - // Read Group Information - VFS_ReadAt( - disk->FD, - sb.s_first_data_block * disk->BlockSize + 1024, - sizeof(tExt2_Group)*groupCount, - disk->Groups - ); - - #if VERBOSE - LOG("Block Group 0"); - LOG(".bg_block_bitmap = 0x%x", disk->Groups[0].bg_block_bitmap); - LOG(".bg_inode_bitmap = 0x%x", disk->Groups[0].bg_inode_bitmap); - LOG(".bg_inode_table = 0x%x", disk->Groups[0].bg_inode_table); - LOG("Block Group 1"); - LOG(".bg_block_bitmap = 0x%x", disk->Groups[1].bg_block_bitmap); - LOG(".bg_inode_bitmap = 0x%x", disk->Groups[1].bg_inode_bitmap); - LOG(".bg_inode_table = 0x%x", disk->Groups[1].bg_inode_table); - #endif - - // Get root Inode - Ext2_int_ReadInode(disk, 2, &inode); - - // Create Root Node - memset(&disk->RootNode, 0, sizeof(tVFS_Node)); - disk->RootNode.Inode = 2; // Root inode ID - disk->RootNode.ImplPtr = disk; // Save disk pointer - disk->RootNode.Size = -1; // Fill in later (on readdir) - disk->RootNode.Flags = VFS_FFLAG_DIRECTORY; - - disk->RootNode.ReadDir = Ext2_ReadDir; - disk->RootNode.FindDir = Ext2_FindDir; - //disk->RootNode.Relink = Ext2_Relink; - - // Complete root node - disk->RootNode.UID = inode.i_uid; - disk->RootNode.GID = inode.i_gid; - disk->RootNode.NumACLs = 1; - disk->RootNode.ACLs = &gVFS_ACL_EveryoneRW; - - #if DEBUG - LOG("inode.i_size = 0x%x", inode.i_size); - LOG("inode.i_block[0] = 0x%x", inode.i_block[0]); - #endif - - LEAVE('p', &disk->RootNode); - return &disk->RootNode; -} - -/** - * \fn void Ext2_Unmount(tVFS_Node *Node) - * \brief Close a mounted device - */ -void Ext2_Unmount(tVFS_Node *Node) -{ - tExt2_Disk *disk = Node->ImplPtr; - - VFS_Close( disk->FD ); - Inode_ClearCache( disk->CacheID ); - memset(disk, 0, sizeof(tExt2_Disk)+disk->GroupCount*sizeof(tExt2_Group)); - free(disk); -} - -/** - * \fn void Ext2_CloseFile(tVFS_Node *Node) - * \brief Close a file (Remove it from the cache) - */ -void Ext2_CloseFile(tVFS_Node *Node) -{ - tExt2_Disk *disk = Node->ImplPtr; - Inode_UncacheNode(disk->CacheID, Node->Inode); - return ; -} - -//================================== -//= INTERNAL FUNCTIONS = -//================================== -/** - * \fn int Ext2_int_ReadInode(tExt2_Disk *Disk, Uint InodeId, tExt2_Inode *Inode) - * \brief Read an inode into memory - */ -int Ext2_int_ReadInode(tExt2_Disk *Disk, Uint32 InodeId, tExt2_Inode *Inode) -{ - int group, subId; - - //ENTER("pDisk iInodeId pInode", Disk, InodeId, Inode); - - if(InodeId == 0) return 0; - - InodeId --; // Inodes are numbered starting at 1 - - group = InodeId / Disk->SuperBlock.s_inodes_per_group; - subId = InodeId % Disk->SuperBlock.s_inodes_per_group; - - //LOG("group=%i, subId = %i", group, subId); - - // Read Inode - VFS_ReadAt(Disk->FD, - Disk->Groups[group].bg_inode_table * Disk->BlockSize + sizeof(tExt2_Inode)*subId, - sizeof(tExt2_Inode), - Inode); - - //LEAVE('i', 1); - return 1; -} - -/** - * \brief Write a modified inode out to disk - */ -int Ext2_int_WriteInode(tExt2_Disk *Disk, Uint32 InodeId, tExt2_Inode *Inode) -{ - int group, subId; - ENTER("pDisk iInodeId pInode", Disk, InodeId, Inode); - - if(InodeId == 0) return 0; - - InodeId --; // Inodes are numbered starting at 1 - - group = InodeId / Disk->SuperBlock.s_inodes_per_group; - subId = InodeId % Disk->SuperBlock.s_inodes_per_group; - - LOG("group=%i, subId = %i", group, subId); - - // Write Inode - VFS_WriteAt(Disk->FD, - Disk->Groups[group].bg_inode_table * Disk->BlockSize + sizeof(tExt2_Inode)*subId, - sizeof(tExt2_Inode), - Inode); - - LEAVE('i', 1); - return 1; -} - -/** - * \fn Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum) - * \brief Get the address of a block from an inode's list - * \param Disk Disk information structure - * \param Blocks Pointer to an inode's block list - * \param BlockNum Block index in list - */ -Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum) -{ - Uint32 *iBlocks; - int dwPerBlock = Disk->BlockSize / 4; - - // Direct Blocks - if(BlockNum < 12) - return (Uint64)Blocks[BlockNum] * Disk->BlockSize; - - // Single Indirect Blocks - iBlocks = malloc( Disk->BlockSize ); - VFS_ReadAt(Disk->FD, (Uint64)Blocks[12]*Disk->BlockSize, Disk->BlockSize, iBlocks); - - BlockNum -= 12; - if(BlockNum < dwPerBlock) - { - BlockNum = iBlocks[BlockNum]; - free(iBlocks); - return (Uint64)BlockNum * Disk->BlockSize; - } - - BlockNum -= dwPerBlock; - // Double Indirect Blocks - if(BlockNum < dwPerBlock*dwPerBlock) - { - VFS_ReadAt(Disk->FD, (Uint64)Blocks[13]*Disk->BlockSize, Disk->BlockSize, iBlocks); - VFS_ReadAt(Disk->FD, (Uint64)iBlocks[BlockNum/dwPerBlock]*Disk->BlockSize, Disk->BlockSize, iBlocks); - BlockNum = iBlocks[BlockNum%dwPerBlock]; - free(iBlocks); - return (Uint64)BlockNum * Disk->BlockSize; - } - - BlockNum -= dwPerBlock*dwPerBlock; - // Triple Indirect Blocks - VFS_ReadAt(Disk->FD, (Uint64)Blocks[14]*Disk->BlockSize, Disk->BlockSize, iBlocks); - VFS_ReadAt(Disk->FD, (Uint64)iBlocks[BlockNum/(dwPerBlock*dwPerBlock)]*Disk->BlockSize, Disk->BlockSize, iBlocks); - VFS_ReadAt(Disk->FD, (Uint64)iBlocks[(BlockNum/dwPerBlock)%dwPerBlock]*Disk->BlockSize, Disk->BlockSize, iBlocks); - BlockNum = iBlocks[BlockNum%dwPerBlock]; - free(iBlocks); - return (Uint64)BlockNum * Disk->BlockSize; -} - -/** - * \fn Uint32 Ext2_int_AllocateInode(tExt2_Disk *Disk, Uint32 Parent) - * \brief Allocate an inode (from the current group preferably) - * \param Disk EXT2 Disk Information Structure - * \param Parent Inode ID of the parent (used to locate the child nearby) - */ -Uint32 Ext2_int_AllocateInode(tExt2_Disk *Disk, Uint32 Parent) -{ -// Uint block = (Parent - 1) / Disk->SuperBlock.s_inodes_per_group; - return 0; -} - -/** - * \fn void Ext2_int_UpdateSuperblock(tExt2_Disk *Disk) - * \brief Updates the superblock - */ -void Ext2_int_UpdateSuperblock(tExt2_Disk *Disk) -{ - int bpg = Disk->SuperBlock.s_blocks_per_group; - int ngrp = Disk->SuperBlock.s_blocks_count / bpg; - int i; - - // Update Primary - VFS_WriteAt(Disk->FD, 1024, 1024, &Disk->SuperBlock); - - // Secondaries - // at Block Group 1, 3^n, 5^n, 7^n - - // 1 - if(ngrp <= 1) return; - VFS_WriteAt(Disk->FD, 1*bpg*Disk->BlockSize, 1024, &Disk->SuperBlock); - - // Powers of 3 - for( i = 3; i < ngrp; i *= 3 ) - VFS_WriteAt(Disk->FD, i*bpg*Disk->BlockSize, 1024, &Disk->SuperBlock); - - // Powers of 5 - for( i = 5; i < ngrp; i *= 5 ) - VFS_WriteAt(Disk->FD, i*bpg*Disk->BlockSize, 1024, &Disk->SuperBlock); - - // Powers of 7 - for( i = 7; i < ngrp; i *= 7 ) - VFS_WriteAt(Disk->FD, i*bpg*Disk->BlockSize, 1024, &Disk->SuperBlock); -} diff --git a/Modules/Filesystems/FS_Ext2/ext2_common.h b/Modules/Filesystems/FS_Ext2/ext2_common.h deleted file mode 100644 index 877b71d3..00000000 --- a/Modules/Filesystems/FS_Ext2/ext2_common.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Acess OS - * Ext2 Driver Version 1 - */ -/** - * \file ext2_common.h - * \brief Second Extended Filesystem Driver - */ -#ifndef _EXT2_COMMON_H -#define _EXT2_COMMON_H -#include -#include -#include "ext2fs.h" - -#define EXT2_UPDATE_WRITEBACK 1 - -// === STRUCTURES === -typedef struct { - int FD; - int CacheID; - tVFS_Node RootNode; - - tExt2_SuperBlock SuperBlock; - int BlockSize; - - int GroupCount; - tExt2_Group Groups[]; -} tExt2_Disk; - -// === FUNCTIONS === -// --- Common --- -extern void Ext2_CloseFile(tVFS_Node *Node); -extern Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum); -extern void Ext2_int_UpdateSuperblock(tExt2_Disk *Disk); -extern int Ext2_int_ReadInode(tExt2_Disk *Disk, Uint32 InodeId, tExt2_Inode *Inode); -extern int Ext2_int_WriteInode(tExt2_Disk *Disk, Uint32 InodeId, tExt2_Inode *Inode); -// --- Dir --- -extern char *Ext2_ReadDir(tVFS_Node *Node, int Pos); -extern tVFS_Node *Ext2_FindDir(tVFS_Node *Node, char *FileName); -extern int Ext2_MkNod(tVFS_Node *Node, char *Name, Uint Flags); -// --- Read --- -extern Uint64 Ext2_Read(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer); -// --- Write --- -extern Uint64 Ext2_Write(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer); - -#endif diff --git a/Modules/Filesystems/FS_Ext2/ext2fs.h b/Modules/Filesystems/FS_Ext2/ext2fs.h deleted file mode 100644 index 8fd87ce4..00000000 --- a/Modules/Filesystems/FS_Ext2/ext2fs.h +++ /dev/null @@ -1,156 +0,0 @@ -/** - * Acess2 - * \file ext2fs.h - * \brief EXT2 Filesystem Driver - */ -#ifndef _EXT2FS_H_ -#define _EXT2FS_H_ - -/** - \name Inode Flag Values - \{ -*/ -#define EXT2_S_IFMT 0xF000 //!< Format Mask -#define EXT2_S_IFSOCK 0xC000 //!< Socket -#define EXT2_S_IFLNK 0xA000 //!< Symbolic Link -#define EXT2_S_IFREG 0x8000 //!< Regular File -#define EXT2_S_IFBLK 0x6000 //!< Block Device -#define EXT2_S_IFDIR 0x4000 //!< Directory -#define EXT2_S_IFCHR 0x2000 //!< Character Device -#define EXT2_S_IFIFO 0x1000 //!< FIFO -#define EXT2_S_ISUID 0x0800 //!< SUID -#define EXT2_S_ISGID 0x0400 //!< SGID -#define EXT2_S_ISVTX 0x0200 //!< sticky bit -#define EXT2_S_IRWXU 0700 //!< user access rights mask -#define EXT2_S_IRUSR 0400 //!< Owner Read -#define EXT2_S_IWUSR 0200 //!< Owner Write -#define EXT2_S_IXUSR 0100 //!< Owner Execute -#define EXT2_S_IRWXG 0070 //!< Group Access rights mask -#define EXT2_S_IRGRP 0040 //!< Group Read -#define EXT2_S_IWGRP 0020 //!< Group Write -#define EXT2_S_IXGRP 0010 //!< Group Execute -#define EXT2_S_IRWXO 0007 //!< Global Access rights mask -#define EXT2_S_IROTH 0004 //!< Global Read -#define EXT2_S_IWOTH 0002 //!< Global Write -#define EXT2_S_IXOTH 0001 //!< Global Execute -//! \} - -#define EXT2_NAME_LEN 255 //!< Maximum Name Length - -// === TYPEDEFS === -typedef struct ext2_inode_s tExt2_Inode; //!< Inode Type -typedef struct ext2_super_block_s tExt2_SuperBlock; //!< Superblock Type -typedef struct ext2_group_desc_s tExt2_Group; //!< Group Descriptor Type -typedef struct ext2_dir_entry_s tExt2_DirEnt; //!< Directory Entry Type - -// === STRUCTURES === -/** - * \brief EXT2 Superblock Structure - */ -struct ext2_super_block_s { - Uint32 s_inodes_count; //!< Inodes count - Uint32 s_blocks_count; //!< Blocks count - Uint32 s_r_blocks_count; //!< Reserved blocks count - Uint32 s_free_blocks_count; //!< Free blocks count - Uint32 s_free_inodes_count; //!< Free inodes count - Uint32 s_first_data_block; //!< First Data Block - Uint32 s_log_block_size; //!< Block size - Sint32 s_log_frag_size; //!< Fragment size - Uint32 s_blocks_per_group; //!< Number Blocks per group - Uint32 s_frags_per_group; //!< Number Fragments per group - Uint32 s_inodes_per_group; //!< Number Inodes per group - Uint32 s_mtime; //!< Mount time - Uint32 s_wtime; //!< Write time - Uint16 s_mnt_count; //!< Mount count - Sint16 s_max_mnt_count; //!< Maximal mount count - Uint16 s_magic; //!< Magic signature - Uint16 s_state; //!< File system state - Uint16 s_errors; //!< Behaviour when detecting errors - Uint16 s_pad; //!< Padding - Uint32 s_lastcheck; //!< time of last check - Uint32 s_checkinterval; //!< max. time between checks - Uint32 s_creator_os; //!< Formatting OS - Uint32 s_rev_level; //!< Revision level - Uint16 s_def_resuid; //!< Default uid for reserved blocks - Uint16 s_def_resgid; //!< Default gid for reserved blocks - Uint32 s_reserved[235]; //!< Padding to the end of the block -}; - -/** - * \struct ext2_inode_s - * \brief EXT2 Inode Definition - */ -struct ext2_inode_s { - Uint16 i_mode; //!< File mode - Uint16 i_uid; //!< Owner Uid - Uint32 i_size; //!< Size in bytes - Uint32 i_atime; //!< Access time - Uint32 i_ctime; //!< Creation time - Uint32 i_mtime; //!< Modification time - Uint32 i_dtime; //!< Deletion Time - Uint16 i_gid; //!< Group Id - Uint16 i_links_count; //!< Links count - Uint32 i_blocks; //!< Number of blocks allocated for the file - Uint32 i_flags; //!< File flags - union { - Uint32 linux_reserved1; //!< Linux: Reserved - Uint32 hurd_translator; //!< HURD: Translator - Uint32 masix_reserved1; //!< Masix: Reserved - } osd1; //!< OS dependent 1 - Uint32 i_block[15]; //!< Pointers to blocks - Uint32 i_version; //!< File version (for NFS) - Uint32 i_file_acl; //!< File ACL - Uint32 i_dir_acl; //!< Directory ACL / Extended File Size - Uint32 i_faddr; //!< Fragment address - union { - struct { - Uint8 l_i_frag; //!< Fragment number - Uint8 l_i_fsize; //!< Fragment size - Uint16 i_pad1; //!< Padding - Uint32 l_i_reserved2[2]; //!< Reserved - } linux2; - struct { - Uint8 h_i_frag; //!< Fragment number - Uint8 h_i_fsize; //!< Fragment size - Uint16 h_i_mode_high; //!< Mode High Bits - Uint16 h_i_uid_high; //!< UID High Bits - Uint16 h_i_gid_high; //!< GID High Bits - Uint32 h_i_author; //!< Creator ID - } hurd2; - struct { - Uint8 m_i_frag; //!< Fragment number - Uint8 m_i_fsize; //!< Fragment size - Uint16 m_pad1; //!< Padding - Uint32 m_i_reserved2[2]; //!< reserved - } masix2; - } osd2; //!< OS dependent 2 -}; - -/** - * \struct ext2_group_desc_s - * \brief EXT2 Group Descriptor - */ -struct ext2_group_desc_s { - Uint32 bg_block_bitmap; //!< Blocks bitmap block - Uint32 bg_inode_bitmap; //!< Inodes bitmap block - Uint32 bg_inode_table; //!< Inodes table block - Uint16 bg_free_blocks_count; //!< Free blocks count - Uint16 bg_free_inodes_count; //!< Free inodes count - Uint16 bg_used_dirs_count; //!< Directories count - Uint16 bg_pad; //!< Padding - Uint32 bg_reserved[3]; //!< Reserved -}; - -/** - * \brief EXT2 Directory Entry - * \note The name may take up less than 255 characters - */ -struct ext2_dir_entry_s { - Uint32 inode; //!< Inode number - Uint16 rec_len; //!< Directory entry length - Uint8 name_len; //!< Short Name Length - Uint8 type; //!< File Type - char name[]; //!< File name -}; - -#endif diff --git a/Modules/Filesystems/FS_Ext2/read.c b/Modules/Filesystems/FS_Ext2/read.c deleted file mode 100644 index 81f5ee64..00000000 --- a/Modules/Filesystems/FS_Ext2/read.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Acess OS - * Ext2 Driver Version 1 - */ -/** - * \file read.c - * \brief Second Extended Filesystem Driver - * \todo Implement file full write support - */ -#define DEBUG 1 -#define VERBOSE 0 -#include "ext2_common.h" - -// === PROTOTYPES === -Uint64 Ext2_Read(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer); - -// === CODE === -/** - * \fn Uint64 Ext2_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) - * \brief Read from a file - */ -Uint64 Ext2_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) -{ - tExt2_Disk *disk = Node->ImplPtr; - tExt2_Inode inode; - Uint64 base; - Uint block; - Uint64 remLen; - - ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer); - - // Get Inode - Ext2_int_ReadInode(disk, Node->Inode, &inode); - - // Sanity Checks - if(Offset >= inode.i_size) { - LEAVE('i', 0); - return 0; - } - if(Offset + Length > inode.i_size) - Length = inode.i_size - Offset; - - block = Offset / disk->BlockSize; - Offset = Offset / disk->BlockSize; - base = Ext2_int_GetBlockAddr(disk, inode.i_block, block); - if(base == 0) { - Warning("[EXT2 ] NULL Block Detected in INode 0x%llx", Node->Inode); - LEAVE('i', 0); - return 0; - } - - // Read only block - if(Length <= disk->BlockSize - Offset) - { - VFS_ReadAt( disk->FD, base+Offset, Length, Buffer); - LEAVE('X', Length); - return Length; - } - - // Read first block - remLen = Length; - VFS_ReadAt( disk->FD, base + Offset, disk->BlockSize - Offset, Buffer); - remLen -= disk->BlockSize - Offset; - Buffer += disk->BlockSize - Offset; - block ++; - - // Read middle blocks - while(remLen > disk->BlockSize) - { - base = Ext2_int_GetBlockAddr(disk, inode.i_block, block); - if(base == 0) { - Warning("[EXT2 ] NULL Block Detected in INode 0x%llx", Node->Inode); - LEAVE('i', 0); - return 0; - } - VFS_ReadAt( disk->FD, base, disk->BlockSize, Buffer); - Buffer += disk->BlockSize; - remLen -= disk->BlockSize; - block ++; - } - - // Read last block - base = Ext2_int_GetBlockAddr(disk, inode.i_block, block); - VFS_ReadAt( disk->FD, base, remLen, Buffer); - - LEAVE('X', Length); - return Length; -} diff --git a/Modules/Filesystems/FS_Ext2/write.c b/Modules/Filesystems/FS_Ext2/write.c deleted file mode 100644 index 950f6d59..00000000 --- a/Modules/Filesystems/FS_Ext2/write.c +++ /dev/null @@ -1,365 +0,0 @@ -/* - * Acess OS - * Ext2 Driver Version 1 - */ -/** - * \file write.c - * \brief Second Extended Filesystem Driver - * \todo Implement file full write support - */ -#define DEBUG 1 -#define VERBOSE 0 -#include "ext2_common.h" - -// === PROTOYPES === -Uint64 Ext2_Write(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer); -Uint32 Ext2_int_AllocateBlock(tExt2_Disk *Disk, Uint32 PrevBlock); -void Ext2_int_DeallocateBlock(tExt2_Disk *Disk, Uint32 Block); - int Ext2_int_AppendBlock(tExt2_Disk *Disk, tExt2_Inode *Inode, Uint32 Block); - -// === CODE === -/** - * \fn Uint64 Ext2_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) - * \brief Write to a file - */ -Uint64 Ext2_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) -{ - tExt2_Disk *disk = Node->ImplPtr; - tExt2_Inode inode; - Uint64 base; - Uint64 retLen; - Uint block; - Uint64 allocSize; - int bNewBlocks = 0; - - Debug_HexDump("Ext2_Write", Buffer, Length); - - Ext2_int_ReadInode(disk, Node->Inode, &inode); - - // Get the ammount of space already allocated - // - Round size up to block size - // - block size is a power of two, so this will work - allocSize = (inode.i_size + disk->BlockSize-1) & ~(disk->BlockSize-1); - - // Are we writing to inside the allocated space? - if( Offset < allocSize ) - { - // Will we go out of it? - if(Offset + Length > allocSize) { - bNewBlocks = 1; - retLen = allocSize - Offset; - } else - retLen = Length; - - // Within the allocated space - block = Offset / disk->BlockSize; - Offset %= disk->BlockSize; - base = Ext2_int_GetBlockAddr(disk, inode.i_block, block); - - // Write only block (if only one) - if(Offset + retLen <= disk->BlockSize) { - VFS_WriteAt(disk->FD, base+Offset, retLen, Buffer); - if(!bNewBlocks) return Length; - goto addBlocks; // Ugh! A goto, but it seems unavoidable - } - - // Write First Block - VFS_WriteAt(disk->FD, base+Offset, disk->BlockSize-Offset, Buffer); - Buffer += disk->BlockSize-Offset; - retLen -= disk->BlockSize-Offset; - block ++; - - // Write middle blocks - while(retLen > disk->BlockSize) - { - base = Ext2_int_GetBlockAddr(disk, inode.i_block, block); - VFS_WriteAt(disk->FD, base, disk->BlockSize, Buffer); - Buffer += disk->BlockSize; - retLen -= disk->BlockSize; - block ++; - } - - // Write last block - base = Ext2_int_GetBlockAddr(disk, inode.i_block, block); - VFS_WriteAt(disk->FD, base, retLen, Buffer); - if(!bNewBlocks) return Length; // Writing in only allocated space - } - -addBlocks: - Warning("[EXT2 ] File extending is untested"); - - // Allocate blocks and copy data to them - retLen = Length - allocSize; - while( retLen > disk->BlockSize ) - { - // Allocate a block - block = Ext2_int_AllocateBlock(disk, base/disk->BlockSize); - if(!block) return Length - retLen; - // Add it to this inode - if( !Ext2_int_AppendBlock(disk, &inode, block) ) { - Ext2_int_DeallocateBlock(disk, block); - goto ret; - } - // Copy data to the node - base = block * disk->BlockSize; - VFS_WriteAt(disk->FD, base, disk->BlockSize, Buffer); - // Update pointer and size remaining - inode.i_size += disk->BlockSize; - Buffer += disk->BlockSize; - retLen -= disk->BlockSize; - } - // Last block :D - block = Ext2_int_AllocateBlock(disk, base/disk->BlockSize); - if(!block) goto ret; - if( !Ext2_int_AppendBlock(disk, &inode, block) ) { - Ext2_int_DeallocateBlock(disk, block); - goto ret; - } - base = block * disk->BlockSize; - VFS_WriteAt(disk->FD, base, retLen, Buffer); - inode.i_size += retLen; - retLen = 0; - -ret: // Makes sure the changes to the inode are committed - Ext2_int_WriteInode(disk, Node->Inode, &inode); - return Length - retLen; -} - -/** - * \fn Uint32 Ext2_int_AllocateBlock(tExt2_Disk *Disk, Uint32 PrevBlock) - * \brief Allocate a block from the best possible location - * \param Disk EXT2 Disk Information Structure - * \param PrevBlock Previous block ID in the file - */ -Uint32 Ext2_int_AllocateBlock(tExt2_Disk *Disk, Uint32 PrevBlock) -{ - int bpg = Disk->SuperBlock.s_blocks_per_group; - Uint blockgroup = PrevBlock / bpg; - Uint bitmap[Disk->BlockSize/sizeof(Uint)]; - Uint bitsperblock = 8*Disk->BlockSize; - int i, j = 0; - Uint block; - - // Are there any free blocks? - if(Disk->SuperBlock.s_free_blocks_count == 0) return 0; - - if(Disk->Groups[blockgroup].bg_free_blocks_count > 0) - { - // Search block group's bitmap - for(i = 0; i < bpg; i++) - { - // Get the block in the bitmap block - j = i & (bitsperblock-1); - - // Read in if needed - if(j == 0) { - VFS_ReadAt( - Disk->FD, - (Uint64)Disk->Groups[blockgroup].bg_block_bitmap + i / bitsperblock, - Disk->BlockSize, - bitmap - ); - } - - // Fast Check - if( bitmap[j/32] == -1 ) { - j = (j + 31) & ~31; - continue; - } - - // Is the bit set? - if( bitmap[j/32] & (1 << (j%32)) ) - continue; - - // Ooh! We found one - break; - } - if( i < bpg ) { - Warning("[EXT2 ] Inconsistency detected, Group Free Block count is non-zero when no free blocks exist"); - goto checkAll; // Search the entire filesystem for a free block - // Goto needed for neatness - } - - // Mark as used - bitmap[j/32] |= (1 << (j%32)); - VFS_WriteAt( - Disk->FD, - (Uint64)Disk->Groups[blockgroup].bg_block_bitmap + i / bitsperblock, - Disk->BlockSize, - bitmap - ); - block = i; - Disk->Groups[blockgroup].bg_free_blocks_count --; - #if EXT2_UPDATE_WRITEBACK - //Ext2_int_UpdateBlockGroup(Disk, blockgroup); - #endif - } - else - { - checkAll: - Warning("[EXT2 ] TODO - Implement using blocks outside the current block group"); - return 0; - } - - // Reduce global count - Disk->SuperBlock.s_free_blocks_count --; - #if EXT2_UPDATE_WRITEBACK - Ext2_int_UpdateSuperblock(Disk); - #endif - - return block; -} - -/** - * \brief Deallocates a block - */ -void Ext2_int_DeallocateBlock(tExt2_Disk *Disk, Uint32 Block) -{ -} - -/** - * \brief Append a block to an inode - */ -int Ext2_int_AppendBlock(tExt2_Disk *Disk, tExt2_Inode *Inode, Uint32 Block) -{ - int nBlocks; - int dwPerBlock = Disk->BlockSize / 4; - Uint32 *blocks; - Uint32 id1, id2; - - nBlocks = (Inode->i_size + Disk->BlockSize - 1) / Disk->BlockSize; - - // Direct Blocks - if( nBlocks < 12 ) { - Inode->i_block[nBlocks] = Block; - return 0; - } - - blocks = malloc( Disk->BlockSize ); - if(!blocks) return 1; - - nBlocks -= 12; - // Single Indirect - if( nBlocks < dwPerBlock) - { - // Allocate/Get Indirect block - if( nBlocks == 0 ) { - Inode->i_block[12] = Ext2_int_AllocateBlock(Disk, Inode->i_block[0]); - if( !Inode->i_block[12] ) { - free(blocks); - return 1; - } - memset(blocks, 0, Disk->BlockSize); - } - else - VFS_ReadAt(Disk->FD, Inode->i_block[12]*Disk->BlockSize, Disk->BlockSize, blocks); - - blocks[nBlocks] = Block; - - VFS_WriteAt(Disk->FD, Inode->i_block[12]*Disk->BlockSize, Disk->BlockSize, blocks); - free(blocks); - return 0; - } - - nBlocks += dwPerBlock; - // Double Indirect - if( nBlocks < dwPerBlock*dwPerBlock ) - { - // Allocate/Get Indirect block - if( nBlocks == 0 ) { - Inode->i_block[13] = Ext2_int_AllocateBlock(Disk, Inode->i_block[0]); - if( !Inode->i_block[13] ) { - free(blocks); - return 1; - } - memset(blocks, 0, Disk->BlockSize); - } - else - VFS_ReadAt(Disk->FD, Inode->i_block[13]*Disk->BlockSize, Disk->BlockSize, blocks); - - // Allocate / Get Indirect lvl2 Block - if( nBlocks % dwPerBlock == 0 ) { - id1 = Ext2_int_AllocateBlock(Disk, Inode->i_block[0]); - if( !id1 ) { - free(blocks); - return 1; - } - blocks[nBlocks/dwPerBlock] = id1; - // Write back indirect 1 block - VFS_WriteAt(Disk->FD, Inode->i_block[13]*Disk->BlockSize, Disk->BlockSize, blocks); - memset(blocks, 0, Disk->BlockSize); - } - else { - id1 = blocks[nBlocks / dwPerBlock]; - VFS_ReadAt(Disk->FD, id1*Disk->BlockSize, Disk->BlockSize, blocks); - } - - blocks[nBlocks % dwPerBlock] = Block; - - VFS_WriteAt(Disk->FD, id1*Disk->BlockSize, Disk->BlockSize, blocks); - free(blocks); - return 0; - } - - nBlocks -= dwPerBlock*dwPerBlock; - // Triple Indirect - if( nBlocks < dwPerBlock*dwPerBlock*dwPerBlock ) - { - // Allocate/Get Indirect block - if( nBlocks == 0 ) { - Inode->i_block[14] = Ext2_int_AllocateBlock(Disk, Inode->i_block[0]); - if( !Inode->i_block[14] ) { - free(blocks); - return 1; - } - memset(blocks, 0, Disk->BlockSize); - } - else - VFS_ReadAt(Disk->FD, Inode->i_block[14]*Disk->BlockSize, Disk->BlockSize, blocks); - - // Allocate / Get Indirect lvl2 Block - if( (nBlocks/dwPerBlock) % dwPerBlock == 0 && nBlocks % dwPerBlock == 0 ) - { - id1 = Ext2_int_AllocateBlock(Disk, Inode->i_block[0]); - if( !id1 ) { - free(blocks); - return 1; - } - blocks[nBlocks/dwPerBlock] = id1; - // Write back indirect 1 block - VFS_WriteAt(Disk->FD, Inode->i_block[14]*Disk->BlockSize, Disk->BlockSize, blocks); - memset(blocks, 0, Disk->BlockSize); - } - else { - id1 = blocks[nBlocks / (dwPerBlock*dwPerBlock)]; - VFS_ReadAt(Disk->FD, id1*Disk->BlockSize, Disk->BlockSize, blocks); - } - - // Allocate / Get Indirect Level 3 Block - if( nBlocks % dwPerBlock == 0 ) { - id2 = Ext2_int_AllocateBlock(Disk, id1); - if( !id2 ) { - free(blocks); - return 1; - } - blocks[(nBlocks/dwPerBlock)%dwPerBlock] = id2; - // Write back indirect 1 block - VFS_WriteAt(Disk->FD, id1*Disk->BlockSize, Disk->BlockSize, blocks); - memset(blocks, 0, Disk->BlockSize); - } - else { - id2 = blocks[(nBlocks/dwPerBlock)%dwPerBlock]; - VFS_ReadAt(Disk->FD, id2*Disk->BlockSize, Disk->BlockSize, blocks); - } - - blocks[nBlocks % dwPerBlock] = Block; - - VFS_WriteAt(Disk->FD, id2*Disk->BlockSize, Disk->BlockSize, blocks); - free(blocks); - return 0; - } - - Warning("[EXT2 ] Inode %i cannot have a block appended to it, all indirects used"); - free(blocks); - return 1; -} diff --git a/Modules/Filesystems/FS_NFS/Makefile b/Modules/Filesystems/FS_NFS/Makefile deleted file mode 100644 index 6fa2e6e3..00000000 --- a/Modules/Filesystems/FS_NFS/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# -# - -OBJ = main.o -NAME = FS_NFS - --include ../Makefile.tpl diff --git a/Modules/Filesystems/FS_NFS/common.h b/Modules/Filesystems/FS_NFS/common.h deleted file mode 100644 index d73592fe..00000000 --- a/Modules/Filesystems/FS_NFS/common.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Acess2 - NFS Driver - * By John Hodge (thePowersGang) - * This file is published under the terms of the Acess licence. See the - * file COPYING for details. - * - * common.h - Common definitions - */ -#ifndef _COMMON_H_ -#define _COMMON_H_ - -typedef struct sNFS_Connection -{ - int FD; - tIPAddr Host; - char *Base; - tVFS_Node Node; -} tNFS_Connection; - -#endif diff --git a/Modules/Filesystems/FS_NFS/main.c b/Modules/Filesystems/FS_NFS/main.c deleted file mode 100644 index 459945fa..00000000 --- a/Modules/Filesystems/FS_NFS/main.c +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Acess2 - NFS Driver - * By John Hodge (thePowersGang) - * This file is published under the terms of the Acess licence. See the - * file COPYING for details. - * - * main.c - Driver core - */ -#define DEBUG 1 -#define VERBOSE 0 -#include "common.h" -#include - -// === PROTOTYPES === - int NFS_Install(char **Arguments); -tVFS_Node *NFS_InitDevice(char *Devices, char **Options); -void NFS_Unmount(tVFS_Node *Node); - -// === GLOBALS === -MODULE_DEFINE(0, 0x32 /*v0.5*/, FS_NFS, NFS_Install, NULL); -tVFS_Driver gNFS_FSInfo = {"nfs", 0, NFS_InitDevice, NFS_Unmount, NULL}; - -tNFS_Connection *gpNFS_Connections; - -// === CODE === -/** - * \brief Installs the NFS driver - */ -int NFS_Install(char **Arguments) -{ - VFS_AddDriver( &gNFS_FSInfo ); - return 1; -} - -/** - * \brief Mount a NFS share - */ -tVFS_Node *NFS_InitDevice(char *Device, char **Options) -{ - char *path, *host; - tNFS_Connection *conn; - - path = strchr( Device, ':' ) + 1; - host = strndup( Device, (int)(path-Device)-1 ); - - conn = malloc( sizeof(tNFS_Connection) ); - - if( !IPTools_GetAddress(host, &conn->IP) ) { - free(conn); - return NULL; - } - free(host); - - conn->FD = IPTools_OpenUdpClient( &conn->Host ); - if(conn->FD == -1) { - free(conn); - return NULL; - } - - conn->Base = strdup( path ); - conn->RootNode.ImplPtr = conn; - conn->RootNode.Flags = VFS_FFLAG_DIRECTORY; - - conn->RootNode.ReadDir = NFS_ReadDir; - conn->RootNode.FindDir = NFS_FindDir; - conn->RootNode.Close = NULL; - - return &conn->RootNode; -} - -void NFS_Unmount(tVFS_Node *Node) -{ - -} diff --git a/Modules/Filesystems/InitRD/GenerateInitRD.php b/Modules/Filesystems/InitRD/GenerateInitRD.php new file mode 100644 index 00000000..d89d6e9c --- /dev/null +++ b/Modules/Filesystems/InitRD/GenerateInitRD.php @@ -0,0 +1,129 @@ +/* + * Acess2 InitRD + * InitRD Data + * Generated + */ +#include "initrd.h" +$item) + { + if(is_array($item[1])) { + + ProcessFolder("{$prefix}_{$i}", $item[1]); + + echo "tInitRD_File {$prefix}_{$i}_entries[] = {\n"; + foreach($item[1] as $j=>$child) + { + if($j) echo ",\n"; + echo "\t{\"".addslashes($child[0])."\",&{$prefix}_{$i}_{$j}}"; + } + echo "\n};\n"; + + $size = count($item[1]); + echo <<$child) +{ + if($j) echo ",\n"; + echo "\t{\"".addslashes($child[0])."\",&gInitRD_Files_{$j}}"; +} +echo "\n};\n"; +?> +tVFS_Node gInitRD_RootNode = { + .NumACLs = 1, + .ACLs = &gVFS_ACL_EveryoneRX, + .Flags = VFS_FFLAG_DIRECTORY, + .Size = , + .ImplPtr = gInitRD_Root_Files, + .ReadDir = InitRD_ReadDir, + .FindDir = InitRD_FindDir +}; diff --git a/Modules/Filesystems/InitRD/Makefile b/Modules/Filesystems/InitRD/Makefile new file mode 100644 index 00000000..18dbc599 --- /dev/null +++ b/Modules/Filesystems/InitRD/Makefile @@ -0,0 +1,10 @@ +# InitRD Filesystem Driver +# + +OBJ = main.o files.o +NAME = FS_InitRD + +-include ../Makefile.tpl + +files.c: + php GenerateInitRD.php files.lst > files.c diff --git a/Modules/Filesystems/InitRD/files.lst b/Modules/Filesystems/InitRD/files.lst new file mode 100644 index 00000000..bf365273 --- /dev/null +++ b/Modules/Filesystems/InitRD/files.lst @@ -0,0 +1,8 @@ +Dir "SBin" { + File "init" "../../../Usermode/Applications/init" + File "login" "../../../Usermode/Applications/login" +} +Dir "Bin" { + File "CLIShell" "../../../Usermode/Applications/CLIShell" + File "ls" "../../../Usermode/Applications/ls" +} diff --git a/Modules/Filesystems/InitRD/initrd.h b/Modules/Filesystems/InitRD/initrd.h new file mode 100644 index 00000000..8ae97aec --- /dev/null +++ b/Modules/Filesystems/InitRD/initrd.h @@ -0,0 +1,21 @@ +/* + */ +#ifndef _INITRD_H_ +#define _INITRD_H_ + +#include +#include + +typedef struct sInitRD_File +{ + char *Name; + tVFS_Node *Node; +} tInitRD_File; + + +// === Functions === +extern Uint64 InitRD_ReadFile(tVFS_Node *Node, Uint64 Offset, Uint64 Size, void *Buffer); +extern char *InitRD_ReadDir(tVFS_Node *Node, int ID); +extern tVFS_Node *InitRD_FindDir(tVFS_Node *Node, char *Name); + +#endif diff --git a/Modules/Filesystems/InitRD/main.c b/Modules/Filesystems/InitRD/main.c new file mode 100644 index 00000000..14850587 --- /dev/null +++ b/Modules/Filesystems/InitRD/main.c @@ -0,0 +1,92 @@ +/* + * Acess OS + * InitRD Driver Version 1 + */ +#include "initrd.h" +#include + +// === IMPORTS == +extern tVFS_Node gInitRD_RootNode; + +// === PROTOTYPES === + int InitRD_Install(char **Arguments); +tVFS_Node *InitRD_InitDevice(char *Device, char **Arguments); +void InitRD_Unmount(tVFS_Node *Node); +Uint64 InitRD_ReadFile(tVFS_Node *Node, Uint64 Offset, Uint64 Size, void *Buffer); +char *InitRD_ReadDir(tVFS_Node *Node, int ID); +tVFS_Node *InitRD_FindDir(tVFS_Node *Node, char *Name); + +// === GLOBALS === +MODULE_DEFINE(0, 0x0A, FS_InitRD, InitRD_Install, NULL); +tVFS_Driver gInitRD_FSInfo = { + "initrd", 0, InitRD_InitDevice, InitRD_Unmount, NULL + }; + +/** + * \brief Register initrd with the kernel + */ +int InitRD_Install(char **Arguments) +{ + VFS_AddDriver( &gInitRD_FSInfo ); + return MODULE_ERR_OK; +} + +/** + * \brief Mount the InitRD + */ +tVFS_Node *InitRD_InitDevice(char *Device, char **Arguments) +{ + return &gInitRD_RootNode; +} + +/** + * \brief Unmount the InitRD + */ +void InitRD_Unmount(tVFS_Node *Node) +{ +} + +/** + * \brief Read from a file + */ +Uint64 InitRD_ReadFile(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) +{ + if(Offset > Node->Size) + return 0; + if(Offset + Length > Node->Size) + Length = Node->Size - Offset; + + memcpy(Buffer, Node->ImplPtr, Length); + + return Length; +} + +/** + * \brief Read from a directory + */ +char *InitRD_ReadDir(tVFS_Node *Node, int ID) +{ + tInitRD_File *dir = Node->ImplPtr; + + if(ID >= Node->Size) + return NULL; + + return strdup(dir[ID].Name); +} + +/** + * \brief Find an element in a directory + */ +tVFS_Node *InitRD_FindDir(tVFS_Node *Node, char *Name) +{ + int i; + tInitRD_File *dir = Node->ImplPtr; + + for( i = 0; i < Node->Size; i++ ) + { + if(strcmp(Name, dir[i].Name) == 0) + return dir[i].Node; + } + + return NULL; +} diff --git a/Modules/Filesystems/Makefile.tpl b/Modules/Filesystems/Makefile.tpl index 80c6d4dd..77dfc2c9 100644 --- a/Modules/Filesystems/Makefile.tpl +++ b/Modules/Filesystems/Makefile.tpl @@ -1 +1,2 @@ +CATEGORY = FS -include ../../Makefile.tpl diff --git a/Modules/Filesystems/NFS/Makefile b/Modules/Filesystems/NFS/Makefile new file mode 100644 index 00000000..0b2019f0 --- /dev/null +++ b/Modules/Filesystems/NFS/Makefile @@ -0,0 +1,7 @@ +# +# + +OBJ = main.o +NAME = NFS + +-include ../Makefile.tpl diff --git a/Modules/Filesystems/NFS/common.h b/Modules/Filesystems/NFS/common.h new file mode 100644 index 00000000..d73592fe --- /dev/null +++ b/Modules/Filesystems/NFS/common.h @@ -0,0 +1,20 @@ +/* + * Acess2 - NFS Driver + * By John Hodge (thePowersGang) + * This file is published under the terms of the Acess licence. See the + * file COPYING for details. + * + * common.h - Common definitions + */ +#ifndef _COMMON_H_ +#define _COMMON_H_ + +typedef struct sNFS_Connection +{ + int FD; + tIPAddr Host; + char *Base; + tVFS_Node Node; +} tNFS_Connection; + +#endif diff --git a/Modules/Filesystems/NFS/main.c b/Modules/Filesystems/NFS/main.c new file mode 100644 index 00000000..459945fa --- /dev/null +++ b/Modules/Filesystems/NFS/main.c @@ -0,0 +1,74 @@ +/* + * Acess2 - NFS Driver + * By John Hodge (thePowersGang) + * This file is published under the terms of the Acess licence. See the + * file COPYING for details. + * + * main.c - Driver core + */ +#define DEBUG 1 +#define VERBOSE 0 +#include "common.h" +#include + +// === PROTOTYPES === + int NFS_Install(char **Arguments); +tVFS_Node *NFS_InitDevice(char *Devices, char **Options); +void NFS_Unmount(tVFS_Node *Node); + +// === GLOBALS === +MODULE_DEFINE(0, 0x32 /*v0.5*/, FS_NFS, NFS_Install, NULL); +tVFS_Driver gNFS_FSInfo = {"nfs", 0, NFS_InitDevice, NFS_Unmount, NULL}; + +tNFS_Connection *gpNFS_Connections; + +// === CODE === +/** + * \brief Installs the NFS driver + */ +int NFS_Install(char **Arguments) +{ + VFS_AddDriver( &gNFS_FSInfo ); + return 1; +} + +/** + * \brief Mount a NFS share + */ +tVFS_Node *NFS_InitDevice(char *Device, char **Options) +{ + char *path, *host; + tNFS_Connection *conn; + + path = strchr( Device, ':' ) + 1; + host = strndup( Device, (int)(path-Device)-1 ); + + conn = malloc( sizeof(tNFS_Connection) ); + + if( !IPTools_GetAddress(host, &conn->IP) ) { + free(conn); + return NULL; + } + free(host); + + conn->FD = IPTools_OpenUdpClient( &conn->Host ); + if(conn->FD == -1) { + free(conn); + return NULL; + } + + conn->Base = strdup( path ); + conn->RootNode.ImplPtr = conn; + conn->RootNode.Flags = VFS_FFLAG_DIRECTORY; + + conn->RootNode.ReadDir = NFS_ReadDir; + conn->RootNode.FindDir = NFS_FindDir; + conn->RootNode.Close = NULL; + + return &conn->RootNode; +} + +void NFS_Unmount(tVFS_Node *Node) +{ + +} diff --git a/Modules/IPStack/icmp.c b/Modules/IPStack/icmp.c index 77bc6911..088caaaf 100644 --- a/Modules/IPStack/icmp.c +++ b/Modules/IPStack/icmp.c @@ -111,7 +111,7 @@ int ICMP_Ping(tInterface *Interface, tIPv4 Addr) { if(gICMP_PingSlots[i].Interface == NULL) break; } - if(gICMP_PingSlots[i].Interface == NULL) break; + if( i < PING_SLOTS ) break; Threads_Yield(); } gICMP_PingSlots[i].Interface = Interface; diff --git a/Modules/IPStack/tcp.c b/Modules/IPStack/tcp.c index fef9065b..9c26767b 100644 --- a/Modules/IPStack/tcp.c +++ b/Modules/IPStack/tcp.c @@ -315,7 +315,7 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head // Is this packet the next expected packet? if( pkt->Sequence != Connection->NextSequenceRcv ) { - tTCPStoredPacket *tmp, *prev; + tTCPStoredPacket *tmp, *prev = NULL; Log("[TCP ] Out of sequence packet (0x%08x != 0x%08x)", pkt->Sequence, Connection->NextSequenceRcv); diff --git a/Modules/Makefile.tpl b/Modules/Makefile.tpl index 964f5cec..8f548c59 100644 --- a/Modules/Makefile.tpl +++ b/Modules/Makefile.tpl @@ -12,10 +12,10 @@ CFGFILES += $(shell test -f Makefile.cfg && echo Makefile.cfg) -include $(CFGFILES) CPPFLAGS = -I$(ACESSDIR)/Kernel/include -I$(ACESSDIR)/Kernel/arch/$(ARCHDIR)/include -DARCH=$(ARCH) $(_CPPFLAGS) -CFLAGS = -Wall -Werror -fno-stack-protector $(CPPFLAGS) +CFLAGS = -Wall -Werror -fno-stack-protector $(CPPFLAGS) -O3 OBJ := $(addsuffix .$(ARCH),$(OBJ)) -BIN = ../$(NAME).kmd.$(ARCH) +BIN = ../$(CATEGORY)_$(NAME).kmd.$(ARCH) KOBJ = ../$(NAME).xo.$(ARCH) DEPFILES = $(filter %.o.$(ARCH),$(OBJ)) diff --git a/Modules/Storage/Makefile.tpl b/Modules/Storage/Makefile.tpl index 80c6d4dd..d5291f69 100644 --- a/Modules/Storage/Makefile.tpl +++ b/Modules/Storage/Makefile.tpl @@ -1 +1,3 @@ +CATEGORY = Storage + -include ../../Makefile.tpl diff --git a/Usermode/Libraries/crt0.o_src/Makefile b/Usermode/Libraries/crt0.o_src/Makefile index 324836bf..f191556b 100644 --- a/Usermode/Libraries/crt0.o_src/Makefile +++ b/Usermode/Libraries/crt0.o_src/Makefile @@ -2,8 +2,7 @@ # # -AS = nasm -RM = rm -f +-include ../Makefile.cfg ASFLAGS = -felf