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

Revision 2516, 6.5 KB checked in by lowjoel, 3 years ago (diff)

Update copyrights to this year.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Rev URL
Line 
1/*
2 * $Id$
3 * Copyright 2008-2012 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    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 && String::IsNullOrEmpty(name) && 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) /            //Root directory area
71                BootSector->BytesPerSector) +
72            (static_cast<unsigned long long>(cluster) - 2) * BootSector->SectorsPerCluster;
73        return SectorToOffset(sector);
74    }
75
76    unsigned Fat12Or16Api::DirectoryToCluster(String^ path)
77    {
78        //The path must start with a backslash as it must be volume-relative.
79        if (path->Length != 0)
80        {
81            if (path[0] != L'\\')
82                throw gcnew ArgumentException(S::_(L"The path provided is not volume relative. "
83                    L"Volume relative paths must begin with a backslash."));
84            path = path->Remove(0, 1);
85        }
86
87        //Chop the path into it's constituent directory components
88        array<String^>^ components = path->Split(Path::DirectorySeparatorChar,
89            Path::AltDirectorySeparatorChar);
90
91        //Traverse the directories until we get the cluster we want.
92        unsigned cluster = 0;
93        FatDirectoryBase^ parentDir = nullptr;
94        for each (String^ component in components)
95        {
96            if (String::IsNullOrEmpty(component))
97                break;
98
99            parentDir = LoadDirectory(cluster, parentDir == nullptr ? String::Empty : parentDir->Name,
100                parentDir);
101            cluster = parentDir->Items[component]->Cluster;
102        }
103
104        return cluster;
105    }
106
107    bool Fat12Or16Api::IsFat12()
108    {
109        unsigned long long numberOfSectors = (BootSector->SectorCount16 == 0 ?
110            BootSector->SectorCount32 : BootSector->SectorCount16);
111        unsigned long long availableSectors = numberOfSectors - (
112            BootSector->ReservedSectorCount +                                                   //Reserved area
113            BootSector->FatCount * BootSector->SectorsPerFat +                                  //FAT area
114            (BootSector->RootDirectoryEntryCount * sizeof(::FatDirectoryEntry) /            //Root directory area
115                BootSector->BytesPerSector)
116        );
117        unsigned long long numberOfClusters = availableSectors / BootSector->SectorsPerCluster;
118
119        return numberOfClusters <= 0xFF0;
120    }
121
122    Fat12Or16Api::RootDirectory::RootDirectory(Fat12Or16Api^ api)
123        : Api(api),
124          FatDirectoryBase(String::Empty, nullptr, 0)
125    {
126    }
127
128    void Fat12Or16Api::RootDirectory::ReadDirectory()
129    {
130        //Calculate the starting sector of the root directory
131        unsigned long long startPos = Api->SectorToOffset(Api->BootSector->ReservedSectorCount +
132            Api->BootSector->FatCount * Api->BootSector->SectorsPerFat);
133        int directoryLength = Api->BootSector->RootDirectoryEntryCount *
134            sizeof(::FatDirectoryEntry);
135
136        array<Byte>^ buffer = gcnew array<Byte>(directoryLength);
137        Api->VolumeStream->Seek(startPos, SeekOrigin::Begin);
138        Api->VolumeStream->Read(buffer, 0, directoryLength);
139
140        DirectorySize = Api->BootSector->RootDirectoryEntryCount;
141        Directory = new ::FatDirectoryEntry[DirectorySize];
142        Marshal::Copy(buffer, 0, static_cast<IntPtr>(Directory), directoryLength);
143
144        ParseDirectory();
145    }
146
147    void Fat12Or16Api::RootDirectory::WriteDirectory()
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        Marshal::Copy(static_cast<IntPtr>(Directory), buffer, 0, directoryLength);
157        Api->VolumeStream->Seek(startPos, SeekOrigin::Begin);
158        Api->VolumeStream->Write(buffer, 0, directoryLength);
159    }
160
161    unsigned Fat12Or16Api::RootDirectory::GetStartCluster(::FatDirectoryEntry& directory)
162    {
163        if (directory.Short.Attributes == 0x0F)
164            throw gcnew ArgumentException(S::_(L"The provided directory is a long file name."));
165        return directory.Short.StartClusterLow;
166    }
167
168    Fat12Or16Api::Directory::Directory(String^ name, FatDirectoryBase^ parent, unsigned cluster,
169        Fat12Or16Api^ api) : FatDirectory(name, parent, cluster, api)
170    {
171    }
172
173    unsigned Fat12Or16Api::Directory::GetStartCluster(::FatDirectoryEntry& directory)
174    {
175        if (directory.Short.Attributes == 0x0F)
176            throw gcnew ArgumentException(S::_(L"The provided directory is a long file name."));
177        return directory.Short.StartClusterLow;
178    }
179}
180}
Note: See TracBrowser for help on using the repository browser.