source: trunk/eraser6/Eraser.Util.FileSystem/Fat12Or16Api.cpp @ 1228

Revision 1228, 6.4 KB checked in by lowjoel, 5 years ago (diff)

Treat the FAT12/FAT16 root directory specially as it is part of the reserved area.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
Line 
1/*
2 * $Id$
3 * Copyright 2009 The Eraser Project
4 * Original Author: Joel Low <lowjoel@users.sourceforge.net>
5 * Modified By:
6 *
7 * This file is part of Eraser.
8 *
9 * Eraser is free software: you can redistribute it and/or modify it under the
10 * terms of the GNU General Public License as published by the Free Software
11 * Foundation, either version 3 of the License, or (at your option) any later
12 * version.
13 *
14 * Eraser is distributed in the hope that it will be useful, but WITHOUT ANY
15 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
17 *
18 * A copy of the GNU General Public License can be found at
19 * <http://www.gnu.org/licenses/>.
20 */
21
22#include <stdafx.h>
23#include "FatApi.h"
24
25using namespace System::IO;
26using namespace System::Runtime::InteropServices;
27
28namespace Eraser {
29namespace Util {
30    Fat12Or16Api::Fat12Or16Api(VolumeInfo^ info) : FatApi(info)
31    {
32        //Sanity checks: check that this volume is FAT12 or FAT16!
33        if (info->VolumeFormat != L"FAT12" && info->VolumeFormat != "FAT16")
34            throw gcnew ArgumentException(L"The volume provided is not a FAT12 or FAT16 volume.");
35    }
36
37    Fat12Or16Api::Fat12Or16Api(VolumeInfo^ info, IO::Stream^ stream) : FatApi(info, stream)
38    {
39        //Sanity checks: check that this volume is FAT12 or FAT16!
40        if (info->VolumeFormat != L"FAT12" && info->VolumeFormat != "FAT16")
41            throw gcnew ArgumentException(L"The volume provided is not a FAT12 or FAT16 volume.");
42    }
43
44    void Fat12Or16Api::LoadFat()
45    {
46        Fat = new char[SectorSizeToSize(BootSector->SectorsPerFat)];
47
48        //Seek to the FAT
49        VolumeStream->Seek(SectorToOffset(BootSector->ReservedSectorCount), SeekOrigin::Begin);
50
51        //Read the FAT
52        array<Byte>^ buffer = gcnew array<Byte>(SectorSizeToSize(BootSector->SectorsPerFat));
53        VolumeStream->Read(buffer, 0, SectorSizeToSize(BootSector->SectorsPerFat));
54        Marshal::Copy(buffer, 0, static_cast<IntPtr>(Fat), buffer->Length);
55    }
56
57    FatDirectoryBase^ Fat12Or16Api::LoadDirectory(unsigned cluster, String^ name,
58        FatDirectoryBase^ parent)
59    {
60        //Return the root directory if we get cluster 0, name is blank and the parent is null
61        if (cluster == 0 && name == String::Empty && parent == nullptr)
62            return gcnew RootDirectory(this);
63        return gcnew Directory(name, parent, cluster, this);
64    }
65
66    long long Fat12Or16Api::ClusterToOffset(unsigned cluster)
67    {
68        unsigned long long sector = BootSector->ReservedSectorCount +                                           //Reserved area
69            BootSector->FatCount * BootSector->SectorsPerFat +                                                  //FAT area
70            (BootSector->RootDirectoryEntryCount * sizeof(::FatDirectoryEntry) / (ClusterSize / SectorSize)) +  //Root directory area
71            (static_cast<unsigned long long>(cluster) - 2) * (ClusterSize / SectorSize);
72        return SectorToOffset(sector);
73    }
74
75    unsigned Fat12Or16Api::DirectoryToCluster(String^ path)
76    {
77        //The path must start with a backslash as it must be volume-relative.
78        if (path->Length != 0 && path[0] != L'\\')
79            throw gcnew ArgumentException(L"The path provided is not volume relative. " +
80                gcnew String(L"Volume relative paths must begin with a backslash."));
81
82        //Chop the path into it's constituent directory components
83        array<String^>^ components = path->Split(Path::DirectorySeparatorChar,
84            Path::AltDirectorySeparatorChar);
85
86        //Traverse the directories until we get the cluster we want.
87        unsigned cluster = 0;
88        FatDirectoryBase^ parentDir = gcnew RootDirectory(this);
89        for each (String^ component in components)
90        {
91            if (component == String::Empty)
92                break;
93
94            parentDir = LoadDirectory(cluster, parentDir == nullptr ? nullptr : parentDir->Name,
95                parentDir);
96            cluster = parentDir->Items[component]->Cluster;
97        }
98
99        return cluster;
100    }
101
102    bool Fat12Or16Api::IsFat12()
103    {
104        unsigned long long numberOfSectors = (BootSector->SectorCount16 == 0 ?
105            BootSector->SectorCount32 : BootSector->SectorCount16);
106        unsigned long long availableSectors = numberOfSectors - (
107            BootSector->ReservedSectorCount +                                                                   //Reserved area
108            BootSector->FatCount * BootSector->SectorsPerFat +                                                  //FAT area
109            (BootSector->RootDirectoryEntryCount * sizeof(::FatDirectoryEntry) / (ClusterSize / SectorSize))    //Root directory area
110        );
111        unsigned long long numberOfClusters = availableSectors / (ClusterSize / SectorSize);
112
113        return numberOfClusters < 0xFF0;
114    }
115
116    Fat12Or16Api::RootDirectory::RootDirectory(Fat12Or16Api^ api)
117        : Api(api),
118          FatDirectoryBase(String::Empty, nullptr, 0)
119    {
120    }
121
122    void Fat12Or16Api::RootDirectory::ReadDirectory()
123    {
124        //Calculate the starting sector of the root directory
125        unsigned long long startPos = Api->SectorToOffset(Api->BootSector->ReservedSectorCount +
126            Api->BootSector->FatCount * Api->BootSector->SectorsPerFat);
127        int directoryLength = Api->BootSector->RootDirectoryEntryCount *
128            sizeof(::FatDirectoryEntry);
129
130        array<Byte>^ buffer = gcnew array<Byte>(directoryLength);
131        Api->VolumeStream->Seek(startPos, SeekOrigin::Begin);
132        Api->VolumeStream->Read(buffer, 0, directoryLength);
133
134        DirectorySize = Api->BootSector->RootDirectoryEntryCount;
135        Directory = new ::FatDirectoryEntry[DirectorySize];
136        Marshal::Copy(buffer, 0, static_cast<IntPtr>(Directory), directoryLength);
137
138        ParseDirectory();
139    }
140
141    void Fat12Or16Api::RootDirectory::WriteDirectory()
142    {
143        //Calculate the starting sector of the root directory
144        unsigned long long startPos = Api->SectorToOffset(Api->BootSector->ReservedSectorCount +
145            Api->BootSector->FatCount * Api->BootSector->SectorsPerFat);
146        int directoryLength = Api->BootSector->RootDirectoryEntryCount *
147            sizeof(::FatDirectoryEntry);
148
149        array<Byte>^ buffer = gcnew array<Byte>(directoryLength);
150        Marshal::Copy(static_cast<IntPtr>(Directory), buffer, 0, directoryLength);
151        Api->VolumeStream->Seek(startPos, SeekOrigin::Begin);
152        Api->VolumeStream->Write(buffer, 0, directoryLength);
153    }
154
155    unsigned Fat12Or16Api::RootDirectory::GetStartCluster(::FatDirectoryEntry& directory)
156    {
157        if (directory.Short.Attributes == 0x0F)
158            throw gcnew ArgumentException(L"The provided directory is a long file name.");
159        return directory.Short.StartClusterLow;
160    }
161
162    Fat12Or16Api::Directory::Directory(String^ name, FatDirectoryBase^ parent, unsigned cluster,
163        Fat12Or16Api^ api) : FatDirectory(name, parent, cluster, api)
164    {
165    }
166
167    unsigned Fat12Or16Api::Directory::GetStartCluster(::FatDirectoryEntry& directory)
168    {
169        if (directory.Short.Attributes == 0x0F)
170            throw gcnew ArgumentException(L"The provided directory is a long file name.");
171        return directory.Short.StartClusterLow;
172    }
173}
174}
Note: See TracBrowser for help on using the repository browser.