source: trunk/eraser/Eraser.Util.Native/Fat12Or16Api.cpp @ 2948

Revision 2805, 6.7 KB checked in by gtrant, 20 months ago (diff)

Update to 2013 and fixes in local compile

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Rev URL
Line 
1/*
2 * $Id$
3 * Copyright 2008-2013 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(S::_(L"The volume provided is not a FAT12 or FAT16 volume."));
35    }
36
37    Fat12Or16Api::Fat12Or16Api(VolumeInfo^ info, IO::Stream^ stream) : FatApi(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(S::_(L"The volume provided is not a FAT12 or FAT16 volume."));
42    }
43
44    Fat12Or16Api::!Fat12Or16Api()
45    {
46        if (Fat != NULL)
47        {
48            delete[] Fat;
49            Fat = NULL;
50        }
51    }
52
53    void Fat12Or16Api::LoadFat()
54    {
55        Fat = new char[SectorSizeToSize(BootSector->SectorsPerFat)];
56
57        //Seek to the FAT
58        VolumeStream->Seek(SectorToOffset(BootSector->ReservedSectorCount), SeekOrigin::Begin);
59
60        //Read the FAT
61        array<Byte>^ buffer = gcnew array<Byte>(SectorSizeToSize(BootSector->SectorsPerFat));
62        VolumeStream->Read(buffer, 0, SectorSizeToSize(BootSector->SectorsPerFat));
63        Marshal::Copy(buffer, 0, static_cast<IntPtr>(Fat), buffer->Length);
64    }
65
66    FatDirectoryBase^ Fat12Or16Api::LoadDirectory(unsigned cluster, String^ name,
67        FatDirectoryBase^ parent)
68    {
69        //Return the root directory if we get cluster 0, name is blank and the parent is null
70        if (cluster == 0 && String::IsNullOrEmpty(name) && parent == nullptr)
71            return gcnew RootDirectory(this);
72        return gcnew Directory(name, parent, cluster, this);
73    }
74
75    long long Fat12Or16Api::ClusterToOffset(unsigned cluster)
76    {
77        unsigned long long sector = BootSector->ReservedSectorCount +                       //Reserved area
78            BootSector->FatCount * BootSector->SectorsPerFat +                              //FAT area
79            (BootSector->RootDirectoryEntryCount * sizeof(::FatDirectoryEntry) /            //Root directory area
80                BootSector->BytesPerSector) +
81            (static_cast<unsigned long long>(cluster) - 2) * BootSector->SectorsPerCluster;
82        return SectorToOffset(sector);
83    }
84
85    unsigned Fat12Or16Api::DirectoryToCluster(String^ path)
86    {
87        //The path must start with a backslash as it must be volume-relative.
88        if (path->Length != 0)
89        {
90            if (path[0] != L'\\')
91                throw gcnew ArgumentException(S::_(L"The path provided is not volume relative. "
92                    L"Volume relative paths must begin with a backslash."));
93            path = path->Remove(0, 1);
94        }
95
96        //Chop the path into it's constituent directory components
97        array<String^>^ components = path->Split(Path::DirectorySeparatorChar,
98            Path::AltDirectorySeparatorChar);
99
100        //Traverse the directories until we get the cluster we want.
101        unsigned cluster = 0;
102        FatDirectoryBase^ parentDir = nullptr;
103        for each (String^ component in components)
104        {
105            if (String::IsNullOrEmpty(component))
106                break;
107
108            parentDir = LoadDirectory(cluster, parentDir == nullptr ? String::Empty : parentDir->Name,
109                parentDir);
110            cluster = parentDir->Items[component]->Cluster;
111        }
112
113        return cluster;
114    }
115
116    bool Fat12Or16Api::IsFat12()
117    {
118        unsigned long long numberOfSectors = (BootSector->SectorCount16 == 0 ?
119            BootSector->SectorCount32 : BootSector->SectorCount16);
120        unsigned long long availableSectors = numberOfSectors - (
121            BootSector->ReservedSectorCount +                                                   //Reserved area
122            BootSector->FatCount * BootSector->SectorsPerFat +                                  //FAT area
123            (BootSector->RootDirectoryEntryCount * sizeof(::FatDirectoryEntry) /            //Root directory area
124                BootSector->BytesPerSector)
125        );
126        unsigned long long numberOfClusters = availableSectors / BootSector->SectorsPerCluster;
127
128        return numberOfClusters <= 0xFF0;
129    }
130
131    Fat12Or16Api::RootDirectory::RootDirectory(Fat12Or16Api^ api)
132        : Api(api),
133          FatDirectoryBase(String::Empty, nullptr, 0)
134    {
135    }
136
137    Fat12Or16Api::RootDirectory::!RootDirectory()
138    {
139        if (Directory != NULL)
140        {
141            delete[] Directory;
142            Directory = NULL;
143            DirectorySize = 0;
144        }
145    }
146
147    void Fat12Or16Api::RootDirectory::ReadDirectory()
148    {
149        //Calculate the starting sector of the root directory
150        unsigned long long startPos = Api->SectorToOffset(Api->BootSector->ReservedSectorCount +
151            Api->BootSector->FatCount * Api->BootSector->SectorsPerFat);
152        int directoryLength = Api->BootSector->RootDirectoryEntryCount *
153            sizeof(::FatDirectoryEntry);
154
155        array<Byte>^ buffer = gcnew array<Byte>(directoryLength);
156        Api->VolumeStream->Seek(startPos, SeekOrigin::Begin);
157        Api->VolumeStream->Read(buffer, 0, directoryLength);
158
159        DirectorySize = Api->BootSector->RootDirectoryEntryCount;
160        Directory = new ::FatDirectoryEntry[DirectorySize];
161        Marshal::Copy(buffer, 0, static_cast<IntPtr>(Directory), directoryLength);
162
163        ParseDirectory();
164    }
165
166    void Fat12Or16Api::RootDirectory::WriteDirectory()
167    {
168        //Calculate the starting sector of the root directory
169        unsigned long long startPos = Api->SectorToOffset(Api->BootSector->ReservedSectorCount +
170            Api->BootSector->FatCount * Api->BootSector->SectorsPerFat);
171        int directoryLength = Api->BootSector->RootDirectoryEntryCount *
172            sizeof(::FatDirectoryEntry);
173
174        array<Byte>^ buffer = gcnew array<Byte>(directoryLength);
175        Marshal::Copy(static_cast<IntPtr>(Directory), buffer, 0, directoryLength);
176        Api->VolumeStream->Seek(startPos, SeekOrigin::Begin);
177        Api->VolumeStream->Write(buffer, 0, directoryLength);
178    }
179
180    unsigned Fat12Or16Api::RootDirectory::GetStartCluster(::FatDirectoryEntry& directory)
181    {
182        if (directory.Short.Attributes == 0x0F)
183            throw gcnew ArgumentException(S::_(L"The provided directory is a long file name."));
184        return directory.Short.StartClusterLow;
185    }
186
187    Fat12Or16Api::Directory::Directory(String^ name, FatDirectoryBase^ parent, unsigned cluster,
188        Fat12Or16Api^ api) : FatDirectory(name, parent, cluster, api)
189    {
190    }
191
192    unsigned Fat12Or16Api::Directory::GetStartCluster(::FatDirectoryEntry& directory)
193    {
194        if (directory.Short.Attributes == 0x0F)
195            throw gcnew ArgumentException(S::_(L"The provided directory is a long file name."));
196        return directory.Short.StartClusterLow;
197    }
198}
199}
Note: See TracBrowser for help on using the repository browser.