/// <summary> /// Create FS node /// </summary> /// <param name="dirEntry">Direntry</param> /// <param name="cluster">Directory cluster</param> /// <param name="num">Direnty number</param> /// <returns></returns> public Node CreateNode(FatDirEntry *dirEntry, uint cluster, uint num) { Node node = new Node(); node.Size = dirEntry->Size; Fat16Cookie cookie = new Fat16Cookie(); cookie.DirEntry = dirEntry; cookie.Cluster = cluster; cookie.Num = num; cookie.FAT16 = this; node.Cookie = cookie; /** * Is it a directory? */ if ((dirEntry->Attribs & ATTRIB_SUBDIR) == ATTRIB_SUBDIR) { node.ReadDir = readDirImpl; node.FindDir = findDirImpl; node.Flags = NodeFlags.DIRECTORY; } else { node.Read = readImpl; node.Write = writeImpl; node.Truncate = truncateImpl; node.Flags = NodeFlags.FILE; } return(node); }
/// <summary> /// Parse direntries /// </summary> private unsafe void parseBoot() { /** * Calculate first data start LBA */ m_clusterBeginLBA = m_beginLBA + m_bpb->ReservedSectors + (m_bpb->NumFats * (int)m_bpb->SectorsPerFat16); // Fetch root directory from memory byte[] buffer = new byte[m_bpb->NumDirEntries * sizeof(FatDirEntry)]; m_dirEntries = (FatDirEntry *)Util.ObjectToVoidPtr(buffer); uint sectorSize = (uint)m_bpb->NumDirEntries / 16; // Do we have a spare sector? if (sectorSize * 16 != m_bpb->NumDirEntries) { sectorSize++; } _Device.Read(_Device, (uint)(m_clusterBeginLBA), sectorSize * 512, buffer); m_numDirEntries = m_bpb->NumDirEntries; m_beginDataLBA = m_clusterBeginLBA + ((m_bpb->NumDirEntries * 32) / m_bpb->BytesPerSector); }
/// <summary> /// Filesystem truncate implementation /// </summary> /// <param name="node"></param> /// <param name="size"></param> /// <returns></returns> private static uint truncateImpl(Node node, uint size) { /** * Get directory entry from cookie "cache" */ Fat16Cookie cookie = (Fat16Cookie)node.Cookie; FatDirEntry *entry = cookie.DirEntry; Fat16 fat = cookie.FAT16; if (entry == null) { return(0); } /** * Empty file not supported */ if (size == 0) { return(0); } /** * Resize file */ return(fat.ResizeFile(entry, cookie.Cluster, cookie.Num, size)); }
/// <summary> /// Filesystem write implementation /// </summary> /// <param name="node"></param> /// <param name="offset"></param> /// <param name="size"></param> /// <param name="buffer"></param> /// <returns></returns> private static uint writeImpl(Node node, uint offset, uint size, byte[] buffer) { /** * Get directory entry from cookie "cache" */ Fat16Cookie cookie = (Fat16Cookie)node.Cookie; Fat16 fat = cookie.FAT16; FatDirEntry *entry = cookie.DirEntry; uint totalSize = size + offset; /** * Do we need to resize the file? */ if (entry->Size < totalSize) { if (fat.ResizeFile(entry, cookie.Cluster, cookie.Num, totalSize) == 0) { return(0); } } /** * Handle file writing */ return(fat.writeFile(entry->ClusterNumberLo, offset, size, buffer)); }
/// <summary> /// Filesystem read implementation /// </summary> /// <param name="node"></param> /// <param name="offset"></param> /// <param name="size"></param> /// <param name="buffer"></param> /// <returns></returns> private static uint readImpl(Node node, uint offset, uint size, byte[] buffer) { /** * Get directory entry from cookie "cache" */ Fat16Cookie cookie = (Fat16Cookie)node.Cookie; Fat16 fat = cookie.FAT16; FatDirEntry *entry = cookie.DirEntry; /* * If the offset is behind the size, stop here */ if (offset > entry->Size) { return(0); } /* * If bytes to read is bigger than the file size, set the size to the file size minus offset */ if (offset + size > entry->Size) { size = entry->Size - offset; } //Util.PrintStackTrace(6); uint read = fat.readFile(entry->ClusterNumberLo, offset, size, buffer); return(read); }
/// <summary> /// Read directory /// </summary> /// <param name="cluster"></param> /// <returns></returns> public SubDirectory readDirectory(uint cluster) { SubDirectory outDir = new SubDirectory(); if (cluster == 0xFFFFFFFF) { outDir.Length = m_numDirEntries; outDir.DirEntries = m_dirEntries; } else { byte[] buffer = new byte[m_bpb->NumDirEntries * sizeof(FatDirEntry)]; // To-do why does this read that mutch? readFile(cluster, 0, (uint)(m_bpb->NumDirEntries * sizeof(FatDirEntry)), buffer); FatDirEntry *entries = (FatDirEntry *)Heap.Alloc(m_bpb->NumDirEntries * sizeof(FatDirEntry)); FatDirEntry *curBufPtr = (FatDirEntry *)Util.ObjectToVoidPtr(buffer); int length = 0; for (int i = 0; i < m_bpb->NumDirEntries; i++) { entries[i] = curBufPtr[i]; if (curBufPtr[i].Name[0] == 0x00) { break; } length++; } outDir.DirEntries = entries; outDir.Length = (uint)length; } return(outDir); }
/// <summary> /// Find node in directory /// </summary> /// <param name="cluster">Cluster number</param> /// <param name="testFor">Compare string</param> /// <returns></returns> public Node FindFileInDirectory(uint cluster, char *testFor) { SubDirectory dir = readDirectory(cluster); for (int i = 0; i < dir.Length; i++) { FatDirEntry entry = dir.DirEntries[i]; if (entry.Name[0] == 0 || entry.Name[0] == 0xE5 || entry.Attribs == 0xF || (entry.Attribs & 0x08) > 0) { continue; } if (Memory.Compare(testFor, entry.Name, 11)) { FatDirEntry *entr = (FatDirEntry *)Heap.Alloc(sizeof(FatDirEntry)); Memory.Memcpy(entr, dir.DirEntries + i, sizeof(FatDirEntry)); return(CreateNode(entr, cluster, (uint)i)); } } return(null); }
/// <summary> /// Set file size in Direntries /// </summary> /// <param name="cluster">Start cluster</param> /// <param name="num">Direnty location</param> /// <param name="size">Size</param> private void SetFileSize(uint cluster, uint num, uint size) { uint offset = num * (uint)sizeof(FatDirEntry); uint offsetSector = offset / 512; offset -= offsetSector * 512; // Read dir entry part uint realOffset = 0; if (cluster == 0xFFFFFFFF) { realOffset = (uint)(m_clusterBeginLBA + offsetSector); } else { realOffset = Data_clust_to_lba(cluster) + offsetSector; } byte[] buf = new byte[512]; _Device.Read(_Device, realOffset, 512, buf); byte * bufPtr = (byte *)Util.ObjectToVoidPtr(buf); FatDirEntry *entry = (FatDirEntry *)(bufPtr + offset); entry->Size = size; _Device.Write(_Device, realOffset, 512, buf); // Update dir entry if needed if (cluster == 0xFFFFFFFF) { m_dirEntries[num].Size = size; } }
/// <summary> /// Filesystem read directory implementation /// </summary> /// <param name="node"></param> /// <param name="index"></param> /// <returns></returns> private static DirEntry *readDirImpl(Node node, uint index) { int j = 0; /** * Find cluster number if not root directory */ uint cluster = 0xFFFFFFFF; Fat16Cookie cookie = (Fat16Cookie)node.Cookie; Fat16 fat = cookie.FAT16; if (cookie.DirEntry != null) { FatDirEntry *entry = cookie.DirEntry; cluster = entry->ClusterNumberLo; } /** * Read directory entries */ SubDirectory dir = fat.readDirectory(cluster); for (int i = 0; i < dir.Length; i++) { FatDirEntry entry = dir.DirEntries[i]; /** * Correct attributes? */ if (entry.Name[0] == 0 || entry.Name[0] == (char)0xE5 || entry.Attribs == 0xF || (entry.Attribs & 0x08) > 0) { continue; } /** * Do we need to search further? */ if (j >= index) { DirEntry *outDir = (DirEntry *)Heap.Alloc(sizeof(DirEntry)); outDir->Reclen = (ushort)sizeof(DirEntry); GetName(dir, i, outDir->Name); /** * Directory or file? */ if ((dir.DirEntries[i].Attribs & ATTRIB_SUBDIR) == 0) { outDir->Type = (byte)DT_Type.DT_REG; } else { outDir->Type = (byte)DT_Type.DT_DIR; } return(outDir); } j++; } return(null); }
/// <summary> /// Find directory implementation /// </summary> /// <param name="node">FS Node</param> /// <param name="name">Filename</param> /// <returns></returns> private static Node findDirImpl(Node node, string name) { Fat16Cookie cookie = (Fat16Cookie)node.Cookie; Fat16 fat16 = cookie.FAT16; /** * Calculate lengths (and check if no LFN) */ int length = name.Length; if (length > 12) { return(null); } int dot = name.IndexOf('.'); if (dot > 8) { return(null); } /** * Prepare test memory block */ char *testFor = (char *)Heap.Alloc(11); Memory.Memset(testFor, ' ', 11); int min = (dot == -1) ? Math.Min(length, 8) : Math.Min(dot, 8); int i = 0; for (; i < min; i++) { testFor[i] = String.ToUpper(name[i]); } if (dot != -1) { int lengthExt = length - dot - 1; min = Math.Min(3, lengthExt); i++; for (int j = 0; j < min; j++) { testFor[j + 8] = String.ToUpper(name[i + j]); } } /** * Find cluster number */ uint cluster = 0xFFFFFFFF; if (cookie.DirEntry != null) { FatDirEntry *entry = cookie.DirEntry; cluster = entry->ClusterNumberLo; } /** * Find file in cluster (directory) */ Node nd = fat16.FindFileInDirectory(cluster, testFor); Heap.Free(testFor); return(nd); }
/// <summary> /// Resize file /// /// @TODO: Allow cluster allocation and removal /// /// /// </summary> /// <param name="direntry">Current direntry</param> /// <param name="cluster">Cluster number for writing</param> /// <param name="num">Direntry number in cluster</param> /// <param name="size">File size</param> /// <returns>Changed size (=0 when error)</returns> private uint ResizeFile(FatDirEntry *direntry, uint cluster, uint num, uint size) { uint realsize = size; int bytesPerCluster = m_bpb->SectorsPerCluster * m_bpb->BytesPerSector; uint readSizeNew = size - 1; uint readSizeOld = direntry->Size - 1; /** * Calculate sectors and clusters */ uint sectorsNew = (uint)Math.Ceil((double)readSizeNew / (double)m_bpb->BytesPerSector); uint clustersNew = (uint)Math.Ceil((double)sectorsNew / (double)m_bpb->SectorsPerCluster); if (readSizeNew == bytesPerCluster) { clustersNew++; } uint sectorsOld = (uint)Math.Ceil((double)(readSizeOld) / (double)m_bpb->BytesPerSector); uint clustersOld = (uint)Math.Ceil((double)sectorsOld / (double)m_bpb->SectorsPerCluster); if (readSizeOld == bytesPerCluster) { clustersOld++; } /** * Calculate difference */ int clusterDiff = (int)clustersNew - (int)clustersOld; /** * @TODO: Test this! (lightly tested, looks like is that it is working) */ if (clusterDiff != 0) { /** * Increase or decrease */ if (clusterDiff < 0) { clusterDiff = Math.Abs(clusterDiff); ushort currentLastCluster = findLastCluster((ushort)cluster); ushort newLastCluster = findLastCluster((ushort)cluster, 1); /** * Removing clusters */ for (int i = 0; i < clusterDiff; i++) { /** * Change cluster table values */ changeClusterValue(currentLastCluster, 0x0000); changeClusterValue(newLastCluster, 0xFFFF); currentLastCluster = findLastCluster((ushort)cluster); newLastCluster = findLastCluster((ushort)cluster, 1); } } else { ushort currentCluster = findLastCluster((ushort)cluster); byte[] buf = new byte[m_bpb->BytesPerSector]; Memory.Memclear(Util.ObjectToVoidPtr(buf), m_bpb->BytesPerSector); /** * Allocating clusters */ for (int i = 0; i < clusterDiff; i++) { ushort freeCluster = findNextFreeCluster(); /** * Change cluster table values */ changeClusterValue(currentCluster, freeCluster); changeClusterValue(freeCluster, 0xFFFF); currentCluster = freeCluster; /** * Free cluster */ uint toFreeLBA = Data_clust_to_lba(currentCluster); for (uint x = 0; x < m_bpb->SectorsPerCluster; x++) { _Device.Write(_Device, toFreeLBA + x, m_bpb->BytesPerSector, buf); } } Heap.Free(buf); } } /** * CLEAR EMPTY SPACE * * Calculate startpoint and offsets */ uint startPoint = (uint)(size > direntry->Size ? direntry->Size : size); uint offsetSector = startPoint / 512; uint offset = startPoint - (offsetSector * 512); /** * Get starting position on FS */ uint lba = Data_clust_to_lba(direntry->ClusterNumberLo); byte[] writeSec = new byte[m_bpb->BytesPerSector]; byte[] readSec = new byte[m_bpb->BytesPerSector]; /** * Free cluster */ for (uint i = offsetSector; i < m_bpb->SectorsPerCluster; i++) { /** * Do we have an offset to use? */ if (offset != 0) { _Device.Read(_Device, lba + i, 512, readSec); Memory.Memcpy(Util.ObjectToVoidPtr(writeSec), Util.ObjectToVoidPtr(readSec), (int)offset); Memory.Memclear((byte *)Util.ObjectToVoidPtr(writeSec) + offset, (int)(512 - offset)); } else { Memory.Memclear(Util.ObjectToVoidPtr(writeSec), 512); } offset = 0; _Device.Write(_Device, lba + i, 512, writeSec); } /** * Free objects */ Heap.Free(Util.ObjectToVoidPtr(writeSec)); Heap.Free(Util.ObjectToVoidPtr(readSec)); /** * Finally update node! */ SetFileSize(cluster, num, realsize); direntry->Size = realsize; return(realsize); }