3 * Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
4 * Copyright (C) 2008-2009 Hervé Poussineau <hpoussin@reactos.org>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 /////////////////////////////////////////////////////////////////////////////////////////////
28 /////////////////////////////////////////////////////////////////////////////////////////////
30 VOID
FileSystemError(PCSTR ErrorString
)
32 DPRINTM(DPRINT_FILESYSTEM
, "%s\n", ErrorString
);
34 UiMessageBox(ErrorString
);
37 PFILE
FsOpenFile(PCSTR FileName
)
39 CHAR FullPath
[MAX_PATH
];
44 // Print status message
46 DPRINTM(DPRINT_FILESYSTEM
, "Opening file '%s'...\n", FileName
);
49 // Create full file name
51 MachDiskGetBootPath(FullPath
, sizeof(FullPath
));
52 strcat(FullPath
, FileName
);
57 ret
= ArcOpen(FullPath
, OpenReadOnly
, &FileId
);
68 VOID
FsCloseFile(PFILE FileHandle
)
70 ULONG FileId
= (ULONG
)FileHandle
;
78 // Do not check for error; this function is
79 // supposed to always succeed
85 * returns number of bytes read or EOF
87 BOOLEAN
FsReadFile(PFILE FileHandle
, ULONG BytesToRead
, ULONG
* BytesRead
, PVOID Buffer
)
89 ULONG FileId
= (ULONG
)FileHandle
;
95 ret
= ArcRead(FileId
, Buffer
, BytesToRead
, BytesRead
);
106 ULONG
FsGetFileSize(PFILE FileHandle
)
108 ULONG FileId
= (ULONG
)FileHandle
;
109 FILEINFORMATION Information
;
113 // Query file informations
115 ret
= ArcGetFileInformation(FileId
, &Information
);
120 if (ret
!= ESUCCESS
|| Information
.EndingAddress
.HighPart
!= 0)
126 return Information
.EndingAddress
.LowPart
;
129 VOID
FsSetFilePointer(PFILE FileHandle
, ULONG NewFilePointer
)
131 ULONG FileId
= (ULONG
)FileHandle
;
132 LARGE_INTEGER Position
;
137 Position
.HighPart
= 0;
138 Position
.LowPart
= NewFilePointer
;
139 ArcSeek(FileId
, &Position
, SeekAbsolute
);
142 // Do not check for error; this function is
143 // supposed to always succeed
148 * FsGetNumPathParts()
149 * This function parses a path in the form of dir1\dir2\file1.ext
150 * and returns the number of parts it has (i.e. 3 - dir1,dir2,file1.ext)
152 ULONG
FsGetNumPathParts(PCSTR Path
)
157 for (i
=0,num
=0; i
<strlen(Path
); i
++)
159 if ((Path
[i
] == '\\') || (Path
[i
] == '/'))
166 DPRINTM(DPRINT_FILESYSTEM
, "FsGetNumPathParts() Path = %s NumPathParts = %d\n", Path
, num
);
172 * FsGetFirstNameFromPath()
173 * This function parses a path in the form of dir1\dir2\file1.ext
174 * and puts the first name of the path (e.g. "dir1") in buffer
175 * compatible with the MSDOS directory structure
177 VOID
FsGetFirstNameFromPath(PCHAR Buffer
, PCSTR Path
)
181 // Copy all the characters up to the end of the
182 // string or until we hit a '\' character
183 // and put them in Buffer
184 for (i
=0; i
<strlen(Path
); i
++)
186 if ((Path
[i
] == '\\') || (Path
[i
] == '/'))
198 DPRINTM(DPRINT_FILESYSTEM
, "FsGetFirstNameFromPath() Path = %s FirstName = %s\n", Path
, Buffer
);
201 typedef struct tagFILEDATA
204 ULONG ReferenceCount
;
205 const DEVVTBL
* FuncTable
;
206 const DEVVTBL
* FileFuncTable
;
210 typedef struct tagDEVICE
212 LIST_ENTRY ListEntry
;
213 const DEVVTBL
* FuncTable
;
216 ULONG ReferenceCount
;
219 static FILEDATA FileData
[MAX_FDS
];
220 static LIST_ENTRY DeviceListHead
;
222 LONG
ArcClose(ULONG FileId
)
226 if (FileId
>= MAX_FDS
|| !FileData
[FileId
].FuncTable
)
229 ret
= FileData
[FileId
].FuncTable
->Close(FileId
);
233 FileData
[FileId
].FuncTable
= NULL
;
234 FileData
[FileId
].Specific
= NULL
;
235 FileData
[FileId
].DeviceId
= -1;
240 LONG
ArcGetFileInformation(ULONG FileId
, FILEINFORMATION
* Information
)
242 if (FileId
>= MAX_FDS
|| !FileData
[FileId
].FuncTable
)
244 return FileData
[FileId
].FuncTable
->GetFileInformation(FileId
, Information
);
247 LONG
ArcOpen(CHAR
* Path
, OPENMODE OpenMode
, ULONG
* FileId
)
256 ULONG dwCount
, dwLength
;
257 OPENMODE DeviceOpenMode
;
260 /* Print status message */
261 DPRINTM(DPRINT_FILESYSTEM
, "Opening file '%s'...\n", Path
);
265 /* Search last ')', which delimits device and path */
266 FileName
= strrchr(Path
, ')');
271 /* Count number of "()", which needs to be replaced by "(0)" */
273 for (p
= Path
; p
!= FileName
; p
++)
274 if (*p
== '(' && *(p
+ 1) == ')')
277 /* Duplicate device name, and replace "()" by "(0)" (if required) */
278 dwLength
= FileName
- Path
+ dwCount
;
281 DeviceName
= MmHeapAlloc(FileName
- Path
+ dwCount
);
284 for (p
= Path
, q
= DeviceName
; p
!= FileName
; p
++)
287 if (*p
== '(' && *(p
+ 1) == ')')
294 /* Search for the device */
295 pEntry
= DeviceListHead
.Flink
;
296 if (OpenMode
== OpenReadOnly
|| OpenMode
== OpenWriteOnly
)
297 DeviceOpenMode
= OpenMode
;
299 DeviceOpenMode
= OpenReadWrite
;
300 while (pEntry
!= &DeviceListHead
)
302 pDevice
= CONTAINING_RECORD(pEntry
, DEVICE
, ListEntry
);
303 if (strncmp(pDevice
->Prefix
, DeviceName
, dwLength
) == 0)
305 /* OK, device found. It is already opened? */
306 if (pDevice
->ReferenceCount
== 0)
308 /* Search some room for the device */
309 for (DeviceId
= 0; DeviceId
< MAX_FDS
; DeviceId
++)
310 if (!FileData
[DeviceId
].FuncTable
)
312 if (DeviceId
== MAX_FDS
)
314 /* Try to open the device */
315 FileData
[DeviceId
].FuncTable
= pDevice
->FuncTable
;
316 ret
= pDevice
->FuncTable
->Open(pDevice
->Prefix
, DeviceOpenMode
, &DeviceId
);
319 FileData
[DeviceId
].FuncTable
= NULL
;
324 /* Done, caller wanted to open the raw device */
326 pDevice
->ReferenceCount
++;
330 /* Try to detect the file system */
332 FileData
[DeviceId
].FileFuncTable
= IsoMount(DeviceId
);
333 if (!FileData
[DeviceId
].FileFuncTable
)
335 FileData
[DeviceId
].FileFuncTable
= FatMount(DeviceId
);
337 if (!FileData
[DeviceId
].FileFuncTable
)
338 FileData
[DeviceId
].FileFuncTable
= NtfsMount(DeviceId
);
339 if (!FileData
[DeviceId
].FileFuncTable
)
340 FileData
[DeviceId
].FileFuncTable
= Ext2Mount(DeviceId
);
343 if (!FileData
[DeviceId
].FileFuncTable
)
344 FileData
[DeviceId
].FileFuncTable
= PxeMount(DeviceId
);
346 if (!FileData
[DeviceId
].FileFuncTable
)
348 /* Error, unable to detect file system */
349 pDevice
->FuncTable
->Close(DeviceId
);
350 FileData
[DeviceId
].FuncTable
= NULL
;
354 pDevice
->DeviceId
= DeviceId
;
358 DeviceId
= pDevice
->DeviceId
;
360 pDevice
->ReferenceCount
++;
363 pEntry
= pEntry
->Flink
;
365 if (pEntry
== &DeviceListHead
)
368 /* At this point, device is found and opened. Its file id is stored
369 * in DeviceId, and FileData[DeviceId].FileFuncTable contains what
370 * needs to be called to open the file */
372 /* Search some room for the device */
373 for (i
= 0; i
< MAX_FDS
; i
++)
374 if (!FileData
[i
].FuncTable
)
379 /* Skip leading backslash, if any */
380 if (*FileName
== '\\')
384 FileData
[i
].FuncTable
= FileData
[DeviceId
].FileFuncTable
;
385 FileData
[i
].DeviceId
= DeviceId
;
387 ret
= FileData
[i
].FuncTable
->Open(FileName
, OpenMode
, FileId
);
390 FileData
[i
].FuncTable
= NULL
;
396 LONG
ArcRead(ULONG FileId
, VOID
* Buffer
, ULONG N
, ULONG
* Count
)
398 if (FileId
>= MAX_FDS
|| !FileData
[FileId
].FuncTable
)
400 return FileData
[FileId
].FuncTable
->Read(FileId
, Buffer
, N
, Count
);
403 LONG
ArcSeek(ULONG FileId
, LARGE_INTEGER
* Position
, SEEKMODE SeekMode
)
405 if (FileId
>= MAX_FDS
|| !FileData
[FileId
].FuncTable
)
407 return FileData
[FileId
].FuncTable
->Seek(FileId
, Position
, SeekMode
);
410 VOID
FsRegisterDevice(CHAR
* Prefix
, const DEVVTBL
* FuncTable
)
415 DPRINTM(DPRINT_FILESYSTEM
, "FsRegisterDevice() Prefix = %s\n", Prefix
);
417 dwLength
= strlen(Prefix
) + 1;
418 pNewEntry
= MmHeapAlloc(sizeof(DEVICE
) + dwLength
);
421 pNewEntry
->FuncTable
= FuncTable
;
422 pNewEntry
->ReferenceCount
= 0;
423 pNewEntry
->Prefix
= (CHAR
*)(pNewEntry
+ 1);
424 memcpy(pNewEntry
->Prefix
, Prefix
, dwLength
);
426 InsertHeadList(&DeviceListHead
, &pNewEntry
->ListEntry
);
429 LPCWSTR
FsGetServiceName(ULONG FileId
)
431 if (FileId
>= MAX_FDS
|| !FileData
[FileId
].FuncTable
)
433 return FileData
[FileId
].FuncTable
->ServiceName
;
436 VOID
FsSetDeviceSpecific(ULONG FileId
, VOID
* Specific
)
438 if (FileId
>= MAX_FDS
|| !FileData
[FileId
].FuncTable
)
440 FileData
[FileId
].Specific
= Specific
;
443 VOID
* FsGetDeviceSpecific(ULONG FileId
)
445 if (FileId
>= MAX_FDS
|| !FileData
[FileId
].FuncTable
)
447 return FileData
[FileId
].Specific
;
450 ULONG
FsGetDeviceId(ULONG FileId
)
452 if (FileId
>= MAX_FDS
)
454 return FileData
[FileId
].DeviceId
;
461 RtlZeroMemory(FileData
, sizeof(FileData
));
462 for (i
= 0; i
< MAX_FDS
; i
++)
463 FileData
[i
].DeviceId
= (ULONG
)-1;
465 InitializeListHead(&DeviceListHead
);