ReactOS 0.4.15-dev-6669-g8227c5d
fs.c
Go to the documentation of this file.
1/*
2 * FreeLoader
3 * Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
4 * Copyright (C) 2008-2009 Hervé Poussineau <hpoussin@reactos.org>
5 *
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.
10 *
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.
15 *
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.
19 */
20
21/* INCLUDES *******************************************************************/
22
23#include <freeldr.h>
24
25#include <debug.h>
27
28/* GLOBALS ********************************************************************/
29
30#define TAG_DEVICE_NAME 'NDsF'
31#define TAG_DEVICE 'vDsF'
32
33typedef struct tagFILEDATA
34{
41
42typedef struct tagDEVICE
43{
50
53
54/* ARC FUNCTIONS **************************************************************/
55
57{
59 ULONG Count, i;
64 CHAR* p;
65 CHAR* q;
67 OPENMODE DeviceOpenMode;
68 ULONG DeviceId;
69
70 /* Print status message */
71 TRACE("Opening file '%s'...\n", Path);
72
73 *FileId = MAX_FDS;
74
75 /* Search last ')', which delimits device and path */
76 FileName = strrchr(Path, ')');
77 if (!FileName)
78 return EINVAL;
79 FileName++;
80
81 /* Count number of "()", which needs to be replaced by "(0)" */
82 Count = 0;
83 for (p = Path; p != FileName; p++)
84 {
85 if (*p == '(' && *(p + 1) == ')')
86 Count++;
87 }
88
89 /* Duplicate device name, and replace "()" by "(0)" (if required) */
91 if (Count != 0)
92 {
94 if (!DeviceName)
95 return ENOMEM;
96 for (p = Path, q = DeviceName; p != FileName; p++)
97 {
98 *q++ = *p;
99 if (*p == '(' && *(p + 1) == ')')
100 *q++ = '0';
101 }
102 }
103 else
104 {
106 }
107
108 /* Search for the device */
109 if (OpenMode == OpenReadOnly || OpenMode == OpenWriteOnly)
110 DeviceOpenMode = OpenMode;
111 else
112 DeviceOpenMode = OpenReadWrite;
113
115 while (pEntry != &DeviceListHead)
116 {
117 pDevice = CONTAINING_RECORD(pEntry, DEVICE, ListEntry);
118 if (strncmp(pDevice->Prefix, DeviceName, Length) == 0)
119 {
120 /* OK, device found. It is already opened? */
121 if (pDevice->ReferenceCount == 0)
122 {
123 /* Search some room for the device */
124 for (DeviceId = 0; DeviceId < MAX_FDS; DeviceId++)
125 {
126 if (!FileData[DeviceId].FuncTable)
127 break;
128 }
129 if (DeviceId == MAX_FDS)
130 return EMFILE;
131
132 /* Try to open the device */
133 FileData[DeviceId].FuncTable = pDevice->FuncTable;
134 Status = pDevice->FuncTable->Open(pDevice->Prefix, DeviceOpenMode, &DeviceId);
135 if (Status != ESUCCESS)
136 {
137 FileData[DeviceId].FuncTable = NULL;
138 return Status;
139 }
140 else if (!*FileName)
141 {
142 /* Done, caller wanted to open the raw device */
143 *FileId = DeviceId;
144 pDevice->ReferenceCount++;
145 return ESUCCESS;
146 }
147
148 /* Try to detect the file system */
149#ifndef _M_ARM
150 FileData[DeviceId].FileFuncTable = IsoMount(DeviceId);
151 if (!FileData[DeviceId].FileFuncTable)
152#endif
153 FileData[DeviceId].FileFuncTable = FatMount(DeviceId);
154 if (!FileData[DeviceId].FileFuncTable)
155 FileData[DeviceId].FileFuncTable = BtrFsMount(DeviceId);
156#ifndef _M_ARM
157 if (!FileData[DeviceId].FileFuncTable)
158 FileData[DeviceId].FileFuncTable = NtfsMount(DeviceId);
159 if (!FileData[DeviceId].FileFuncTable)
160 FileData[DeviceId].FileFuncTable = Ext2Mount(DeviceId);
161#endif
162#if defined(_M_IX86) || defined(_M_AMD64)
163#ifndef UEFIBOOT
164 if (!FileData[DeviceId].FileFuncTable)
165 FileData[DeviceId].FileFuncTable = PxeMount(DeviceId);
166#endif
167#endif
168 if (!FileData[DeviceId].FileFuncTable)
169 {
170 /* Error, unable to detect file system */
171 pDevice->FuncTable->Close(DeviceId);
172 FileData[DeviceId].FuncTable = NULL;
173 return ENODEV;
174 }
175
176 pDevice->DeviceId = DeviceId;
177 }
178 else
179 {
180 DeviceId = pDevice->DeviceId;
181 }
182 pDevice->ReferenceCount++;
183 break;
184 }
186 }
187 if (pEntry == &DeviceListHead)
188 return ENODEV;
189
190 /* At this point, device is found and opened. Its file id is stored
191 * in DeviceId, and FileData[DeviceId].FileFuncTable contains what
192 * needs to be called to open the file */
193
194 /* Search some room for the device */
195 for (i = 0; i < MAX_FDS; i++)
196 {
197 if (!FileData[i].FuncTable)
198 break;
199 }
200 if (i == MAX_FDS)
201 return EMFILE;
202
203 /* Skip leading path separator, if any */
204 if (*FileName == '\\' || *FileName == '/')
205 FileName++;
206
207 /* Open the file */
209 FileData[i].DeviceId = DeviceId;
210 *FileId = i;
211 Status = FileData[i].FuncTable->Open(FileName, OpenMode, FileId);
212 if (Status != ESUCCESS)
213 {
215 *FileId = MAX_FDS;
216 }
217 return Status;
218}
219
221{
223
224 if (FileId >= MAX_FDS || !FileData[FileId].FuncTable)
225 return EBADF;
226
227 Status = FileData[FileId].FuncTable->Close(FileId);
228
229 if (Status == ESUCCESS)
230 {
231 FileData[FileId].FuncTable = NULL;
232 FileData[FileId].Specific = NULL;
233 FileData[FileId].DeviceId = -1;
234 }
235 return Status;
236}
237
239{
240 if (FileId >= MAX_FDS || !FileData[FileId].FuncTable)
241 return EBADF;
242 return FileData[FileId].FuncTable->Read(FileId, Buffer, N, Count);
243}
244
246{
247 if (FileId >= MAX_FDS || !FileData[FileId].FuncTable)
248 return EBADF;
249 return FileData[FileId].FuncTable->Seek(FileId, Position, SeekMode);
250}
251
253{
254 if (FileId >= MAX_FDS || !FileData[FileId].FuncTable)
255 return EBADF;
256 return FileData[FileId].FuncTable->GetFileInformation(FileId, Information);
257}
258
259/* FUNCTIONS ******************************************************************/
260
262{
263 ERR("%s\n", ErrorString);
264 UiMessageBox(ErrorString);
265}
266
270 IN PCSTR DefaultPath OPTIONAL,
271 IN OPENMODE OpenMode,
272 OUT PULONG FileId)
273{
275 SIZE_T cchPathLen;
276 CHAR FullPath[MAX_PATH] = "";
277
278 /*
279 * Check whether FileName is a full path and if not, create a full
280 * file name using the user-provided default path (if present).
281 *
282 * See ArcOpen(): Search last ')', which delimits device and path.
283 */
284 if (strrchr(FileName, ')') == NULL)
285 {
286 /* This is not a full path: prepend the user-provided default path */
287 if (DefaultPath)
288 {
289 Status = RtlStringCbCopyA(FullPath, sizeof(FullPath), DefaultPath);
290 if (!NT_SUCCESS(Status))
291 return ENAMETOOLONG;
292 }
293
294 /* Append a path separator if needed */
295
296 cchPathLen = min(sizeof(FullPath)/sizeof(CHAR), strlen(FullPath));
297 if (cchPathLen >= sizeof(FullPath)/sizeof(CHAR))
298 return ENAMETOOLONG;
299
300 if ((*FileName != '\\' && *FileName != '/') &&
301 cchPathLen > 0 && (FullPath[cchPathLen-1] != '\\' && FullPath[cchPathLen-1] != '/'))
302 {
303 /* FileName does not start with '\' and FullPath does not end with '\' */
304 Status = RtlStringCbCatA(FullPath, sizeof(FullPath), "\\");
305 if (!NT_SUCCESS(Status))
306 return ENAMETOOLONG;
307 }
308 else if ((*FileName == '\\' || *FileName == '/') &&
309 cchPathLen > 0 && (FullPath[cchPathLen-1] == '\\' || FullPath[cchPathLen-1] == '/'))
310 {
311 /* FileName starts with '\' and FullPath ends with '\' */
312 while (*FileName == '\\' || *FileName == '/')
313 ++FileName; // Skip any backslash
314 }
315 }
316 /* Append (or just copy) the remaining file name */
317 Status = RtlStringCbCatA(FullPath, sizeof(FullPath), FileName);
318 if (!NT_SUCCESS(Status))
319 return ENAMETOOLONG;
320
321 /* Open the file */
322 return ArcOpen(FullPath, OpenMode, FileId);
323}
324
325/*
326 * FsGetNumPathParts()
327 * This function parses a path in the form of dir1\dir2\file1.ext
328 * and returns the number of parts it has (i.e. 3 - dir1,dir2,file1.ext)
329 */
331{
332 size_t i;
333 size_t len;
334 ULONG num;
335
336 len = strlen(Path);
337
338 for (i = 0, num = 0; i < len; i++)
339 {
340 if ((Path[i] == '\\') || (Path[i] == '/'))
341 {
342 num++;
343 }
344 }
345 num++;
346
347 TRACE("FsGetNumPathParts() Path = %s NumPathParts = %d\n", Path, num);
348
349 return num;
350}
351
352/*
353 * FsGetFirstNameFromPath()
354 * This function parses a path in the form of dir1\dir2\file1.ext
355 * and puts the first name of the path (e.g. "dir1") in buffer
356 * compatible with the MSDOS directory structure
357 */
359{
360 size_t i;
361 size_t len;
362
363 len = strlen(Path);
364
365 // Copy all the characters up to the end of the
366 // string or until we hit a '\' character
367 // and put them in Buffer
368 for (i = 0; i < len; i++)
369 {
370 if ((Path[i] == '\\') || (Path[i] == '/'))
371 {
372 break;
373 }
374 else
375 {
376 Buffer[i] = Path[i];
377 }
378 }
379
380 Buffer[i] = 0;
381
382 TRACE("FsGetFirstNameFromPath() Path = %s FirstName = %s\n", Path, Buffer);
383}
384
386{
387 DEVICE* pNewEntry;
389
390 TRACE("FsRegisterDevice() Prefix = %s\n", Prefix);
391
392 Length = strlen(Prefix) + 1;
393 pNewEntry = FrLdrTempAlloc(sizeof(DEVICE) + Length, TAG_DEVICE);
394 if (!pNewEntry)
395 return;
396 pNewEntry->FuncTable = FuncTable;
397 pNewEntry->ReferenceCount = 0;
398 pNewEntry->Prefix = (CHAR*)(pNewEntry + 1);
399 RtlCopyMemory(pNewEntry->Prefix, Prefix, Length);
400
402}
403
405{
406 if (FileId >= MAX_FDS || !FileData[FileId].FuncTable)
407 return NULL;
408 return FileData[FileId].FuncTable->ServiceName;
409}
410
412{
413 if (FileId >= MAX_FDS || !FileData[FileId].FuncTable)
414 return;
415 FileData[FileId].Specific = Specific;
416}
417
419{
420 if (FileId >= MAX_FDS || !FileData[FileId].FuncTable)
421 return NULL;
422 return FileData[FileId].Specific;
423}
424
426{
427 if (FileId >= MAX_FDS)
428 return (ULONG)-1;
429 return FileData[FileId].DeviceId;
430}
431
433{
434 ULONG i;
435
437 for (i = 0; i < MAX_FDS; i++)
438 FileData[i].DeviceId = (ULONG)-1;
439
441}
#define N
Definition: crc32.c:57
PRTL_UNICODE_STRING_BUFFER Path
#define EINVAL
Definition: acclib.h:90
#define ENOMEM
Definition: acclib.h:84
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
int strncmp(const char *String1, const char *String2, ACPI_SIZE Count)
Definition: utclib.c:534
#define ENODEV
Definition: acclib.h:89
#define EBADF
Definition: acclib.h:82
LONG NTSTATUS
Definition: precomp.h:26
NTSTATUS FatMount(_In_ ULONG DeviceId, _In_ ULONG Unknown, _Out_ PBL_FILE_ENTRY *FileEntry)
Definition: fat.c:23
#define ERR(fmt,...)
Definition: debug.h:110
#define DBG_DEFAULT_CHANNEL(ch)
Definition: debug.h:103
const DEVVTBL * BtrFsMount(ULONG DeviceId)
Definition: btrfs.c:1297
const DEVVTBL * Ext2Mount(ULONG DeviceId)
Definition: ext2.c:1295
const DEVVTBL * NtfsMount(ULONG DeviceId)
Definition: ntfs.c:881
#define MAX_FDS
Definition: fs.h:34
FORCEINLINE PVOID FrLdrTempAlloc(_In_ SIZE_T Size, _In_ ULONG Tag)
Definition: mm.h:188
ARC_STATUS ArcClose(ULONG FileId)
Definition: fs.c:220
ARC_STATUS ArcGetFileInformation(ULONG FileId, FILEINFORMATION *Information)
Definition: fs.c:252
#define TAG_DEVICE
Definition: fs.c:31
ARC_STATUS ArcSeek(ULONG FileId, LARGE_INTEGER *Position, SEEKMODE SeekMode)
Definition: fs.c:245
ARC_STATUS ArcOpen(CHAR *Path, OPENMODE OpenMode, ULONG *FileId)
Definition: fs.c:56
static LIST_ENTRY DeviceListHead
Definition: fs.c:52
ULONG FsGetNumPathParts(PCSTR Path)
Definition: fs.c:330
ARC_STATUS FsOpenFile(IN PCSTR FileName, IN PCSTR DefaultPath OPTIONAL, IN OPENMODE OpenMode, OUT PULONG FileId)
Definition: fs.c:268
VOID FileSystemError(PCSTR ErrorString)
Definition: fs.c:261
struct tagFILEDATA FILEDATA
ULONG FsGetDeviceId(ULONG FileId)
Definition: fs.c:425
#define TAG_DEVICE_NAME
Definition: fs.c:30
PCWSTR FsGetServiceName(ULONG FileId)
Definition: fs.c:404
struct tagDEVICE DEVICE
VOID * FsGetDeviceSpecific(ULONG FileId)
Definition: fs.c:418
static FILEDATA FileData[MAX_FDS]
Definition: fs.c:51
ARC_STATUS ArcRead(ULONG FileId, VOID *Buffer, ULONG N, ULONG *Count)
Definition: fs.c:238
VOID FsSetDeviceSpecific(ULONG FileId, VOID *Specific)
Definition: fs.c:411
VOID FsRegisterDevice(CHAR *Prefix, const DEVVTBL *FuncTable)
Definition: fs.c:385
VOID FsInit(VOID)
Definition: fs.c:432
VOID FsGetFirstNameFromPath(PCHAR Buffer, PCSTR Path)
Definition: fs.c:358
Definition: bufpool.h:45
#define NULL
Definition: types.h:112
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define MAX_PATH
Definition: compat.h:34
#define EMFILE
Definition: errno.h:30
#define InsertHeadList(ListHead, Entry)
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
struct _FileName FileName
Definition: fatprocs.h:896
const DEVVTBL * PxeMount(ULONG DeviceId)
Definition: pxe.c:282
FxDevice * pDevice
PLIST_ENTRY pEntry
Definition: fxioqueue.cpp:4484
Status
Definition: gdiplustypes.h:25
GLdouble GLdouble GLdouble GLdouble q
Definition: gl.h:2063
GLfloat GLfloat p
Definition: glext.h:8902
GLuint GLuint num
Definition: glext.h:9618
GLenum GLsizei len
Definition: glext.h:6722
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
const DEVVTBL * IsoMount(ULONG DeviceId)
Definition: iso.c:495
#define min(a, b)
Definition: monoChain.cc:55
int Count
Definition: noreturn.cpp:7
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
NTSTRSAFEAPI RtlStringCbCatA(_Inout_updates_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PSTR pszDest, _In_ size_t cbDest, _In_ NTSTRSAFE_PCSTR pszSrc)
Definition: ntstrsafe.h:625
NTSTRSAFEAPI RtlStringCbCopyA(_Out_writes_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PSTR pszDest, _In_ size_t cbDest, _In_ NTSTRSAFE_PCSTR pszSrc)
Definition: ntstrsafe.h:156
#define ENAMETOOLONG
Definition: errno.h:55
_Check_return_ _CRTIMP _CONST_RETURN char *__cdecl strrchr(_In_z_ const char *_Str, _In_ int _Ch)
@ ESUCCESS
Definition: arc.h:32
ULONG ARC_STATUS
Definition: arc.h:4
enum _OPENMODE OPENMODE
enum _SEEKMODE SEEKMODE
@ OpenWriteOnly
Definition: arc.h:66
@ OpenReadWrite
Definition: arc.h:67
@ OpenReadOnly
Definition: arc.h:65
#define TRACE(s)
Definition: solgame.cpp:4
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
Definition: typedefs.h:120
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
Definition: fs.c:43
ULONG DeviceId
Definition: fs.c:47
const DEVVTBL * FuncTable
Definition: fs.c:45
CHAR * Prefix
Definition: fs.c:46
LIST_ENTRY ListEntry
Definition: fs.c:44
ULONG ReferenceCount
Definition: fs.c:48
Definition: fs.h:25
ARC_SEEK Seek
Definition: fs.h:30
PCWSTR ServiceName
Definition: fs.h:31
ARC_GET_FILE_INFORMATION GetFileInformation
Definition: fs.h:27
ARC_OPEN Open
Definition: fs.h:28
ARC_READ Read
Definition: fs.h:29
ARC_CLOSE Close
Definition: fs.h:26
Definition: fs.c:34
const DEVVTBL * FileFuncTable
Definition: fs.c:38
ULONG ReferenceCount
Definition: fs.c:36
const DEVVTBL * FuncTable
Definition: fs.c:37
VOID * Specific
Definition: fs.c:39
ULONG DeviceId
Definition: fs.c:35
static COORD Position
Definition: mouse.c:34
uint32_t * PULONG
Definition: typedefs.h:59
const uint16_t * PCWSTR
Definition: typedefs.h:57
ULONG_PTR SIZE_T
Definition: typedefs.h:80
const char * PCSTR
Definition: typedefs.h:52
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
#define IN
Definition: typedefs.h:39
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
uint32_t ULONG
Definition: typedefs.h:59
#define OUT
Definition: typedefs.h:40
char * PCHAR
Definition: typedefs.h:51
VOID UiMessageBox(PCSTR Format,...)
Definition: ui.c:357
_Must_inspect_result_ _In_ PWDFDEVICE_INIT _In_opt_ PCUNICODE_STRING DeviceName
Definition: wdfdevice.h:3275
_In_ WDFREQUEST _In_ NTSTATUS _In_ ULONG_PTR Information
Definition: wdfrequest.h:1049
_In_ __drv_aliasesMem PSTRING Prefix
Definition: rtlfuncs.h:1630
char CHAR
Definition: xmlstorage.h:175