3 * Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #define SECTORSIZE 2048
27 static ULONG IsoRootSector
; // Starting sector of the root directory
28 static ULONG IsoRootLength
; // Length of the root directory
30 ULONG IsoDriveNumber
= 0;
33 BOOL
IsoOpenVolume(ULONG DriveNumber
)
35 PPVD Pvd
= (PPVD
)DISKREADBUFFER
;
37 DbgPrint((DPRINT_FILESYSTEM
, "IsoOpenVolume() DriveNumber = 0x%x VolumeStartSector = 16\n", DriveNumber
));
39 // Store the drive number
40 IsoDriveNumber
= DriveNumber
;
45 if (!MachDiskReadLogicalSectors(DriveNumber
, 16, 1, Pvd
))
47 FileSystemError("Failed to read the PVD.");
51 IsoRootSector
= Pvd
->RootDirRecord
.ExtentLocationL
;
52 IsoRootLength
= Pvd
->RootDirRecord
.DataLengthL
;
54 DbgPrint((DPRINT_FILESYSTEM
, "IsoRootSector = %u IsoRootLegth = %u\n", IsoRootSector
, IsoRootLength
));
60 static BOOL
IsoSearchDirectoryBufferForFile(PVOID DirectoryBuffer
, ULONG DirectoryLength
, PCHAR FileName
, PISO_FILE_INFO IsoFileInfoPointer
)
67 DbgPrint((DPRINT_FILESYSTEM
, "IsoSearchDirectoryBufferForFile() DirectoryBuffer = 0x%x DirectoryLength = %d FileName = %s\n", DirectoryBuffer
, DirectoryLength
, FileName
));
69 RtlZeroMemory(Name
, 32 * sizeof(UCHAR
));
72 Record
= (PDIR_RECORD
)DirectoryBuffer
;
75 Offset
= Offset
+ Record
->RecordLength
;
76 Record
= (PDIR_RECORD
)((ULONG_PTR
)DirectoryBuffer
+ Offset
);
78 if (Record
->RecordLength
== 0)
80 Offset
= ROUND_UP(Offset
, SECTORSIZE
);
81 Record
= (PDIR_RECORD
)((ULONG_PTR
)DirectoryBuffer
+ Offset
);
84 if (Offset
>= DirectoryLength
)
87 if (Record
->FileIdLength
== 1 && Record
->FileId
[0] == 0)
89 DbgPrint((DPRINT_FILESYSTEM
, "Name '.'\n"));
91 else if (Record
->FileIdLength
== 1 && Record
->FileId
[0] == 1)
93 DbgPrint((DPRINT_FILESYSTEM
, "Name '..'\n"));
97 for (i
= 0; i
< Record
->FileIdLength
&& Record
->FileId
[i
] != ';'; i
++)
98 Name
[i
] = Record
->FileId
[i
];
100 DbgPrint((DPRINT_FILESYSTEM
, "Name '%s'\n", Name
));
102 if (strlen(FileName
) == strlen(Name
) && stricmp(FileName
, Name
) == 0)
104 IsoFileInfoPointer
->FileStart
= Record
->ExtentLocationL
;
105 IsoFileInfoPointer
->FileSize
= Record
->DataLengthL
;
106 IsoFileInfoPointer
->FilePointer
= 0;
107 IsoFileInfoPointer
->Directory
= (Record
->FileFlags
& 0x02)?TRUE
:FALSE
;
114 RtlZeroMemory(Name
, 32 * sizeof(UCHAR
));
122 * IsoBufferDirectory()
123 * This function allocates a buffer, reads the specified directory
124 * and returns a pointer to that buffer. The function returns NULL
125 * if allocation or read fails. The directory is specified by its
126 * starting sector and length.
128 static PVOID
IsoBufferDirectory(ULONG DirectoryStartSector
, ULONG DirectoryLength
)
130 PVOID DirectoryBuffer
;
135 DbgPrint((DPRINT_FILESYSTEM
, "IsoBufferDirectory() DirectoryStartSector = %d DirectoryLength = %d\n", DirectoryStartSector
, DirectoryLength
));
137 SectorCount
= ROUND_UP(DirectoryLength
, SECTORSIZE
) / SECTORSIZE
;
138 DbgPrint((DPRINT_FILESYSTEM
, "Trying to read (DirectoryCount) %d sectors.\n", SectorCount
));
141 // Attempt to allocate memory for directory buffer
143 DbgPrint((DPRINT_FILESYSTEM
, "Trying to allocate (DirectoryLength) %d bytes.\n", DirectoryLength
));
144 DirectoryBuffer
= MmAllocateMemory(DirectoryLength
);
146 if (DirectoryBuffer
== NULL
)
152 // Now read directory contents into DirectoryBuffer
154 for (i
= 0, Ptr
= DirectoryBuffer
; i
< SectorCount
; i
++, Ptr
= (PVOID
)((ULONG_PTR
)Ptr
+ SECTORSIZE
))
156 if (!MachDiskReadLogicalSectors(IsoDriveNumber
, DirectoryStartSector
+ i
, 1, (PVOID
)DISKREADBUFFER
))
158 MmFreeMemory(DirectoryBuffer
);
161 RtlCopyMemory(Ptr
, (PVOID
)DISKREADBUFFER
, SECTORSIZE
);
164 return DirectoryBuffer
;
170 * This function searches the file system for the
171 * specified filename and fills in an ISO_FILE_INFO structure
172 * with info describing the file, etc. returns true
173 * if the file exists or false otherwise
175 static BOOL
IsoLookupFile(PCSTR FileName
, PISO_FILE_INFO IsoFileInfoPointer
)
178 ULONG NumberOfPathParts
;
180 PVOID DirectoryBuffer
;
181 ULONG DirectorySector
;
182 ULONG DirectoryLength
;
183 ISO_FILE_INFO IsoFileInfo
;
185 DbgPrint((DPRINT_FILESYSTEM
, "IsoLookupFile() FileName = %s\n", FileName
));
187 RtlZeroMemory(IsoFileInfoPointer
, sizeof(ISO_FILE_INFO
));
190 // Figure out how many sub-directories we are nested in
192 NumberOfPathParts
= FsGetNumPathParts(FileName
);
194 DirectorySector
= IsoRootSector
;
195 DirectoryLength
= IsoRootLength
;
198 // Loop once for each part
200 for (i
=0; i
<NumberOfPathParts
; i
++)
203 // Get first path part
205 FsGetFirstNameFromPath(PathPart
, FileName
);
208 // Advance to the next part of the path
210 for (; (*FileName
!= '\\') && (*FileName
!= '/') && (*FileName
!= '\0'); FileName
++)
216 // Buffer the directory contents
218 DirectoryBuffer
= IsoBufferDirectory(DirectorySector
, DirectoryLength
);
219 if (DirectoryBuffer
== NULL
)
225 // Search for file name in directory
227 if (!IsoSearchDirectoryBufferForFile(DirectoryBuffer
, DirectoryLength
, PathPart
, &IsoFileInfo
))
229 MmFreeMemory(DirectoryBuffer
);
233 MmFreeMemory(DirectoryBuffer
);
236 // If we have another sub-directory to go then
237 // grab the start sector and file size
239 if ((i
+1) < NumberOfPathParts
)
241 DirectorySector
= IsoFileInfo
.FileStart
;
242 DirectoryLength
= IsoFileInfo
.FileSize
;
247 RtlCopyMemory(IsoFileInfoPointer
, &IsoFileInfo
, sizeof(ISO_FILE_INFO
));
255 * Tries to open the file 'name' and returns true or false
256 * for success and failure respectively
258 FILE* IsoOpenFile(PCSTR FileName
)
260 ISO_FILE_INFO TempFileInfo
;
261 PISO_FILE_INFO FileHandle
;
263 DbgPrint((DPRINT_FILESYSTEM
, "IsoOpenFile() FileName = %s\n", FileName
));
265 if (!IsoLookupFile(FileName
, &TempFileInfo
))
270 FileHandle
= MmAllocateMemory(sizeof(ISO_FILE_INFO
));
272 if (FileHandle
== NULL
)
277 RtlCopyMemory(FileHandle
, &TempFileInfo
, sizeof(ISO_FILE_INFO
));
279 return (FILE*)FileHandle
;
285 * Reads BytesToRead from open file and
286 * returns the number of bytes read in BytesRead
288 BOOL
IsoReadFile(FILE *FileHandle
, ULONG BytesToRead
, ULONG
* BytesRead
, PVOID Buffer
)
290 PISO_FILE_INFO IsoFileInfo
= (PISO_FILE_INFO
)FileHandle
;
292 ULONG OffsetInSector
;
293 ULONG LengthInSector
;
294 ULONG NumberOfSectors
;
297 DbgPrint((DPRINT_FILESYSTEM
, "IsoReadFile() BytesToRead = %d Buffer = 0x%x\n", BytesToRead
, Buffer
));
299 if (BytesRead
!= NULL
)
305 // If they are trying to read past the
306 // end of the file then return success
307 // with BytesRead == 0
309 if (IsoFileInfo
->FilePointer
>= IsoFileInfo
->FileSize
)
315 // If they are trying to read more than there is to read
316 // then adjust the amount to read
318 if ((IsoFileInfo
->FilePointer
+ BytesToRead
) > IsoFileInfo
->FileSize
)
320 BytesToRead
= (IsoFileInfo
->FileSize
- IsoFileInfo
->FilePointer
);
324 // Ok, now we have to perform at most 3 calculations
325 // I'll draw you a picture (using nifty ASCII art):
327 // CurrentFilePointer -+
329 // +----------------+
331 // +-----------+-----------+-----------+-----------+
332 // | Sector 1 | Sector 2 | Sector 3 | Sector 4 |
333 // +-----------+-----------+-----------+-----------+
335 // +---------------+--------------------+
337 // BytesToRead -------+
339 // 1 - The first calculation (and read) will align
340 // the file pointer with the next sector
341 // boundary (if we are supposed to read that much)
342 // 2 - The next calculation (and read) will read
343 // in all the full sectors that the requested
344 // amount of data would cover (in this case
346 // 3 - The last calculation (and read) would read
347 // in the remainder of the data requested out of
353 // Only do the first read if we
354 // aren't aligned on a cluster boundary
356 if (IsoFileInfo
->FilePointer
% SECTORSIZE
)
359 // Do the math for our first read
361 SectorNumber
= IsoFileInfo
->FileStart
+ (IsoFileInfo
->FilePointer
/ SECTORSIZE
);
362 OffsetInSector
= IsoFileInfo
->FilePointer
% SECTORSIZE
;
363 LengthInSector
= (BytesToRead
> (SECTORSIZE
- OffsetInSector
)) ? (SECTORSIZE
- OffsetInSector
) : BytesToRead
;
366 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
368 if (!MachDiskReadLogicalSectors(IsoDriveNumber
, SectorNumber
, 1, (PVOID
)DISKREADBUFFER
))
372 RtlCopyMemory(Buffer
, (PVOID
)((ULONG_PTR
)DISKREADBUFFER
+ OffsetInSector
), LengthInSector
);
373 if (BytesRead
!= NULL
)
375 *BytesRead
+= LengthInSector
;
377 BytesToRead
-= LengthInSector
;
378 IsoFileInfo
->FilePointer
+= LengthInSector
;
379 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ LengthInSector
);
383 // Do the math for our second read (if any data left)
388 // Determine how many full clusters we need to read
390 NumberOfSectors
= (BytesToRead
/ SECTORSIZE
);
392 for (i
= 0; i
< NumberOfSectors
; i
++)
394 SectorNumber
= IsoFileInfo
->FileStart
+ (IsoFileInfo
->FilePointer
/ SECTORSIZE
);
397 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
399 if (!MachDiskReadLogicalSectors(IsoDriveNumber
, SectorNumber
, 1, (PVOID
)DISKREADBUFFER
))
404 RtlCopyMemory(Buffer
, (PVOID
)DISKREADBUFFER
, SECTORSIZE
);
406 if (BytesRead
!= NULL
)
408 *BytesRead
+= SECTORSIZE
;
410 BytesToRead
-= SECTORSIZE
;
411 IsoFileInfo
->FilePointer
+= SECTORSIZE
;
412 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ SECTORSIZE
);
417 // Do the math for our third read (if any data left)
421 SectorNumber
= IsoFileInfo
->FileStart
+ (IsoFileInfo
->FilePointer
/ SECTORSIZE
);
424 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
426 if (!MachDiskReadLogicalSectors(IsoDriveNumber
, SectorNumber
, 1, (PVOID
)DISKREADBUFFER
))
430 RtlCopyMemory(Buffer
, (PVOID
)DISKREADBUFFER
, BytesToRead
);
431 if (BytesRead
!= NULL
)
433 *BytesRead
+= BytesToRead
;
435 IsoFileInfo
->FilePointer
+= BytesToRead
;
436 BytesToRead
-= BytesToRead
;
437 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ BytesToRead
);
440 DbgPrint((DPRINT_FILESYSTEM
, "IsoReadFile() done\n"));
446 ULONG
IsoGetFileSize(FILE *FileHandle
)
448 PISO_FILE_INFO IsoFileHandle
= (PISO_FILE_INFO
)FileHandle
;
450 DbgPrint((DPRINT_FILESYSTEM
, "IsoGetFileSize() FileSize = %d\n", IsoFileHandle
->FileSize
));
452 return IsoFileHandle
->FileSize
;
455 VOID
IsoSetFilePointer(FILE *FileHandle
, ULONG NewFilePointer
)
457 PISO_FILE_INFO IsoFileHandle
= (PISO_FILE_INFO
)FileHandle
;
459 DbgPrint((DPRINT_FILESYSTEM
, "IsoSetFilePointer() NewFilePointer = %d\n", NewFilePointer
));
461 IsoFileHandle
->FilePointer
= NewFilePointer
;
464 ULONG
IsoGetFilePointer(FILE *FileHandle
)
466 PISO_FILE_INFO IsoFileHandle
= (PISO_FILE_INFO
)FileHandle
;
468 DbgPrint((DPRINT_FILESYSTEM
, "IsoGetFilePointer() FilePointer = %d\n", IsoFileHandle
->FilePointer
));
470 return IsoFileHandle
->FilePointer
;