ReactOS  0.4.13-dev-235-g7373cb3
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>
26 
27 DBG_DEFAULT_CHANNEL(FILESYSTEM);
28 
29 /* GLOBALS ********************************************************************/
30 
31 #define TAG_DEVICE_NAME 'NDsF'
32 #define TAG_DEVICE 'vDsF'
33 
34 typedef struct tagFILEDATA
35 {
41 } FILEDATA;
42 
43 typedef struct tagDEVICE
44 {
50 } DEVICE;
51 
54 
55 /* ARC FUNCTIONS **************************************************************/
56 
57 ARC_STATUS ArcOpen(CHAR* Path, OPENMODE OpenMode, ULONG* FileId)
58 {
60  ULONG Count, i;
61  PLIST_ENTRY pEntry;
62  DEVICE* pDevice;
64  CHAR* FileName;
65  CHAR* p;
66  CHAR* q;
67  SIZE_T Length;
68  OPENMODE DeviceOpenMode;
69  ULONG DeviceId;
70 
71  /* Print status message */
72  TRACE("Opening file '%s'...\n", Path);
73 
74  *FileId = MAX_FDS;
75 
76  /* Search last ')', which delimits device and path */
77  FileName = strrchr(Path, ')');
78  if (!FileName)
79  return EINVAL;
80  FileName++;
81 
82  /* Count number of "()", which needs to be replaced by "(0)" */
83  Count = 0;
84  for (p = Path; p != FileName; p++)
85  {
86  if (*p == '(' && *(p + 1) == ')')
87  Count++;
88  }
89 
90  /* Duplicate device name, and replace "()" by "(0)" (if required) */
91  Length = FileName - Path + Count;
92  if (Count != 0)
93  {
95  if (!DeviceName)
96  return ENOMEM;
97  for (p = Path, q = DeviceName; p != FileName; p++)
98  {
99  *q++ = *p;
100  if (*p == '(' && *(p + 1) == ')')
101  *q++ = '0';
102  }
103  }
104  else
105  {
106  DeviceName = Path;
107  }
108 
109  /* Search for the device */
110  if (OpenMode == OpenReadOnly || OpenMode == OpenWriteOnly)
111  DeviceOpenMode = OpenMode;
112  else
113  DeviceOpenMode = OpenReadWrite;
114 
115  pEntry = DeviceListHead.Flink;
116  while (pEntry != &DeviceListHead)
117  {
118  pDevice = CONTAINING_RECORD(pEntry, DEVICE, ListEntry);
119  if (strncmp(pDevice->Prefix, DeviceName, Length) == 0)
120  {
121  /* OK, device found. It is already opened? */
122  if (pDevice->ReferenceCount == 0)
123  {
124  /* Search some room for the device */
125  for (DeviceId = 0; DeviceId < MAX_FDS; DeviceId++)
126  {
127  if (!FileData[DeviceId].FuncTable)
128  break;
129  }
130  if (DeviceId == MAX_FDS)
131  return EMFILE;
132 
133  /* Try to open the device */
134  FileData[DeviceId].FuncTable = pDevice->FuncTable;
135  Status = pDevice->FuncTable->Open(pDevice->Prefix, DeviceOpenMode, &DeviceId);
136  if (Status != ESUCCESS)
137  {
138  FileData[DeviceId].FuncTable = NULL;
139  return Status;
140  }
141  else if (!*FileName)
142  {
143  /* Done, caller wanted to open the raw device */
144  *FileId = DeviceId;
145  pDevice->ReferenceCount++;
146  return ESUCCESS;
147  }
148 
149  /* Try to detect the file system */
150 #ifndef _M_ARM
151  FileData[DeviceId].FileFuncTable = IsoMount(DeviceId);
152  if (!FileData[DeviceId].FileFuncTable)
153 #endif
154  FileData[DeviceId].FileFuncTable = FatMount(DeviceId);
155  if (!FileData[DeviceId].FileFuncTable)
156  FileData[DeviceId].FileFuncTable = BtrFsMount(DeviceId);
157 #ifndef _M_ARM
158  if (!FileData[DeviceId].FileFuncTable)
159  FileData[DeviceId].FileFuncTable = NtfsMount(DeviceId);
160  if (!FileData[DeviceId].FileFuncTable)
161  FileData[DeviceId].FileFuncTable = Ext2Mount(DeviceId);
162 #endif
163 #if defined(_M_IX86) || defined(_M_AMD64)
164  if (!FileData[DeviceId].FileFuncTable)
165  FileData[DeviceId].FileFuncTable = PxeMount(DeviceId);
166 #endif
167  if (!FileData[DeviceId].FileFuncTable)
168  {
169  /* Error, unable to detect file system */
170  pDevice->FuncTable->Close(DeviceId);
171  FileData[DeviceId].FuncTable = NULL;
172  return ENODEV;
173  }
174 
175  pDevice->DeviceId = DeviceId;
176  }
177  else
178  {
179  DeviceId = pDevice->DeviceId;
180  }
181  pDevice->ReferenceCount++;
182  break;
183  }
184  pEntry = pEntry->Flink;
185  }
186  if (pEntry == &DeviceListHead)
187  return ENODEV;
188 
189  /* At this point, device is found and opened. Its file id is stored
190  * in DeviceId, and FileData[DeviceId].FileFuncTable contains what
191  * needs to be called to open the file */
192 
193  /* Search some room for the device */
194  for (i = 0; i < MAX_FDS; i++)
195  {
196  if (!FileData[i].FuncTable)
197  break;
198  }
199  if (i == MAX_FDS)
200  return EMFILE;
201 
202  /* Skip leading backslash, if any */
203  if (*FileName == '\\')
204  FileName++;
205 
206  /* Open the file */
208  FileData[i].DeviceId = DeviceId;
209  *FileId = i;
210  Status = FileData[i].FuncTable->Open(FileName, OpenMode, FileId);
211  if (Status != ESUCCESS)
212  {
214  *FileId = MAX_FDS;
215  }
216  return Status;
217 }
218 
220 {
222 
223  if (FileId >= MAX_FDS || !FileData[FileId].FuncTable)
224  return EBADF;
225 
226  Status = FileData[FileId].FuncTable->Close(FileId);
227 
228  if (Status == ESUCCESS)
229  {
230  FileData[FileId].FuncTable = NULL;
231  FileData[FileId].Specific = NULL;
232  FileData[FileId].DeviceId = -1;
233  }
234  return Status;
235 }
236 
238 {
239  if (FileId >= MAX_FDS || !FileData[FileId].FuncTable)
240  return EBADF;
241  return FileData[FileId].FuncTable->Read(FileId, Buffer, N, Count);
242 }
243 
245 {
246  if (FileId >= MAX_FDS || !FileData[FileId].FuncTable)
247  return EBADF;
248  return FileData[FileId].FuncTable->Seek(FileId, Position, SeekMode);
249 }
250 
252 {
253  if (FileId >= MAX_FDS || !FileData[FileId].FuncTable)
254  return EBADF;
255  return FileData[FileId].FuncTable->GetFileInformation(FileId, Information);
256 }
257 
258 /* FUNCTIONS ******************************************************************/
259 
261 {
262  ERR("%s\n", ErrorString);
263  UiMessageBox(ErrorString);
264 }
265 
267 {
268  CHAR FullPath[MAX_PATH] = "";
269  ULONG FileId;
271 
272  //
273  // Print status message
274  //
275  TRACE("Opening file '%s'...\n", FileName);
276 
277  //
278  // Check whether FileName is a full path
279  // and if not, create a full file name.
280  //
281  // See ArcOpen: Search last ')', which delimits device and path.
282  //
283  if (strrchr(FileName, ')') == NULL)
284  {
285  /* This is not a full path. Use the current (i.e. boot) device. */
286  MachDiskGetBootPath(FullPath, sizeof(FullPath));
287 
288  /* Append a path separator if needed */
289  if (FileName[0] != '\\' && FileName[0] != '/')
290  strcat(FullPath, "\\");
291  }
292  // Append (or just copy) the remaining file name.
293  strcat(FullPath, FileName);
294 
295  //
296  // Open the file
297  //
298  Status = ArcOpen(FullPath, OpenReadOnly, &FileId);
299 
300  //
301  // Check for success
302  //
303  if (Status == ESUCCESS)
304  return (PFILE)FileId;
305  else
306  return (PFILE)0;
307 }
308 
310 {
311  ULONG FileId = (ULONG)FileHandle;
312 
313  //
314  // Close the handle. Do not check for error,
315  // this function is supposed to always succeed.
316  //
317  ArcClose(FileId);
318 }
319 
320 /*
321  * ReadFile()
322  * returns number of bytes read or EOF
323  */
325 {
326  ULONG FileId = (ULONG)FileHandle;
327 
328  //
329  // Read the file
330  //
331  return (ArcRead(FileId, Buffer, BytesToRead, BytesRead) == ESUCCESS);
332 }
333 
335 {
336  ULONG FileId = (ULONG)FileHandle;
337 
338  //
339  // Get file information
340  //
341  return (ArcGetFileInformation(FileId, Information) == ESUCCESS);
342 }
343 
345 {
346  ULONG FileId = (ULONG)FileHandle;
349 
350  //
351  // Query file informations
352  //
354 
355  //
356  // Check for error
357  //
358  if (Status != ESUCCESS || Information.EndingAddress.HighPart != 0)
359  return 0;
360 
361  //
362  // Return file size
363  //
364  return Information.EndingAddress.LowPart;
365 }
366 
368 {
369  ULONG FileId = (ULONG)FileHandle;
371 
372  //
373  // Set file position. Do not check for error,
374  // this function is supposed to always succeed.
375  //
376  Position.HighPart = 0;
377  Position.LowPart = NewFilePointer;
378  ArcSeek(FileId, &Position, SeekAbsolute);
379 }
380 
381 /*
382  * FsGetNumPathParts()
383  * This function parses a path in the form of dir1\dir2\file1.ext
384  * and returns the number of parts it has (i.e. 3 - dir1,dir2,file1.ext)
385  */
387 {
388  size_t i;
389  size_t len;
390  ULONG num;
391 
392  len = strlen(Path);
393 
394  for (i = 0, num = 0; i < len; i++)
395  {
396  if ((Path[i] == '\\') || (Path[i] == '/'))
397  {
398  num++;
399  }
400  }
401  num++;
402 
403  TRACE("FsGetNumPathParts() Path = %s NumPathParts = %d\n", Path, num);
404 
405  return num;
406 }
407 
408 /*
409  * FsGetFirstNameFromPath()
410  * This function parses a path in the form of dir1\dir2\file1.ext
411  * and puts the first name of the path (e.g. "dir1") in buffer
412  * compatible with the MSDOS directory structure
413  */
415 {
416  size_t i;
417  size_t len;
418 
419  len = strlen(Path);
420 
421  // Copy all the characters up to the end of the
422  // string or until we hit a '\' character
423  // and put them in Buffer
424  for (i = 0; i < len; i++)
425  {
426  if ((Path[i] == '\\') || (Path[i] == '/'))
427  {
428  break;
429  }
430  else
431  {
432  Buffer[i] = Path[i];
433  }
434  }
435 
436  Buffer[i] = 0;
437 
438  TRACE("FsGetFirstNameFromPath() Path = %s FirstName = %s\n", Path, Buffer);
439 }
440 
442 {
443  DEVICE* pNewEntry;
444  SIZE_T Length;
445 
446  TRACE("FsRegisterDevice() Prefix = %s\n", Prefix);
447 
448  Length = strlen(Prefix) + 1;
449  pNewEntry = FrLdrTempAlloc(sizeof(DEVICE) + Length, TAG_DEVICE);
450  if (!pNewEntry)
451  return;
452  pNewEntry->FuncTable = FuncTable;
453  pNewEntry->ReferenceCount = 0;
454  pNewEntry->Prefix = (CHAR*)(pNewEntry + 1);
455  memcpy(pNewEntry->Prefix, Prefix, Length);
456 
457  InsertHeadList(&DeviceListHead, &pNewEntry->ListEntry);
458 }
459 
461 {
462  if (FileId >= MAX_FDS || !FileData[FileId].FuncTable)
463  return NULL;
464  return FileData[FileId].FuncTable->ServiceName;
465 }
466 
467 VOID FsSetDeviceSpecific(ULONG FileId, VOID* Specific)
468 {
469  if (FileId >= MAX_FDS || !FileData[FileId].FuncTable)
470  return;
471  FileData[FileId].Specific = Specific;
472 }
473 
475 {
476  if (FileId >= MAX_FDS || !FileData[FileId].FuncTable)
477  return NULL;
478  return FileData[FileId].Specific;
479 }
480 
482 {
483  if (FileId >= MAX_FDS)
484  return (ULONG)-1;
485  return FileData[FileId].DeviceId;
486 }
487 
489 {
490  ULONG i;
491 
492  RtlZeroMemory(FileData, sizeof(FileData));
493  for (i = 0; i < MAX_FDS; i++)
494  FileData[i].DeviceId = (ULONG)-1;
495 
497 
498  // FIXME: Retrieve the current boot device with MachDiskGetBootPath
499  // and store it somewhere in order to not call again and again this
500  // function.
501 }
LPCWSTR ServiceName
Definition: fs.h:29
ARC_STATUS ArcClose(ULONG FileId)
Definition: fs.c:219
signed char * PCHAR
Definition: retypes.h:7
const DEVVTBL * FileFuncTable
Definition: fs.c:39
static FILEDATA FileData[MAX_FDS]
Definition: fs.c:52
ARC_STATUS ArcGetFileInformation(ULONG FileId, FILEINFORMATION *Information)
Definition: fs.c:251
VOID * Specific
Definition: fs.c:40
_In_ __drv_aliasesMem PSTRING Prefix
Definition: rtlfuncs.h:1631
#define TAG_DEVICE_NAME
Definition: fs.c:31
char * strcat(char *DstString, const char *SrcString)
Definition: utclib.c:568
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
ULONG ReferenceCount
Definition: fs.c:49
static LIST_ENTRY DeviceListHead
Definition: fs.c:53
Definition: arc.h:32
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
ULONG FsGetNumPathParts(PCSTR Path)
Definition: fs.c:386
FORCEINLINE VOID InsertHeadList(_Inout_ PLIST_ENTRY ListHead, _Inout_ __drv_aliasesMem PLIST_ENTRY Entry)
Definition: rtlfuncs.h:201
Definition: arc.h:39
static COORD Position
Definition: mouse.c:34
char CHAR
Definition: xmlstorage.h:175
VOID FsGetFirstNameFromPath(PCHAR Buffer, PCSTR Path)
Definition: fs.c:414
Definition: fs.h:22
_Inout_ __drv_aliasesMem PSLIST_ENTRY _Inout_ PSLIST_ENTRY _In_ ULONG Count
Definition: exfuncs.h:1015
ULONG ARC_STATUS
Definition: arc.h:4
ARC_STATUS ArcOpen(CHAR *Path, OPENMODE OpenMode, ULONG *FileId)
Definition: fs.c:57
_Check_return_ _CRTIMP _CONST_RETURN char *__cdecl strrchr(_In_z_ const char *_Str, _In_ int _Ch)
ULONG FsGetDeviceId(ULONG FileId)
Definition: fs.c:481
WCHAR DeviceName[]
Definition: adapter.cpp:21
struct tagFILEDATA FILEDATA
Definition: arc.h:36
BOOLEAN FsGetFileInformation(PFILE FileHandle, FILEINFORMATION *Information)
Definition: fs.c:334
ARC_CLOSE Close
Definition: fs.h:24
Definition: arc.h:48
const DEVVTBL * NtfsMount(ULONG DeviceId)
Definition: ntfs.c:875
NTSTATUS FatMount(_In_ ULONG DeviceId, _In_ ULONG Unknown, _Out_ PBL_FILE_ENTRY *FileEntry)
Definition: fat.c:23
HANDLE FileHandle
Definition: stats.c:38
ARC_STATUS ArcRead(ULONG FileId, VOID *Buffer, ULONG N, ULONG *Count)
Definition: fs.c:237
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
BOOLEAN FsReadFile(PFILE FileHandle, ULONG BytesToRead, ULONG *BytesRead, PVOID Buffer)
Definition: fs.c:324
Definition: bidi.c:97
VOID UiMessageBox(PCSTR Format,...)
Definition: ui.c:347
FORCEINLINE PVOID FrLdrTempAlloc(_In_ SIZE_T Size, _In_ ULONG Tag)
Definition: mm.h:177
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
VOID * FsGetDeviceSpecific(ULONG FileId)
Definition: fs.c:474
enum _SEEKMODE SEEKMODE
Definition: bufpool.h:45
ULONG ReferenceCount
Definition: fs.c:37
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
LPCWSTR FsGetServiceName(ULONG FileId)
Definition: fs.c:460
LIST_ENTRY ListEntry
Definition: fs.c:45
Definition: fs.c:34
struct _LIST_ENTRY * Flink
Definition: typedefs.h:119
VOID FsInit(VOID)
Definition: fs.c:488
#define TRACE(s)
Definition: solgame.cpp:4
#define MAX_PATH
Definition: compat.h:26
int strncmp(const char *String1, const char *String2, ACPI_SIZE Count)
Definition: utclib.c:534
ARC_READ Read
Definition: fs.h:27
ARC_OPEN Open
Definition: fs.h:26
GLuint GLuint num
Definition: glext.h:9618
const DEVVTBL * FuncTable
Definition: fs.c:46
GLdouble GLdouble GLdouble GLdouble q
Definition: gl.h:2063
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:101
CHAR * Prefix
Definition: fs.c:47
#define MAX_FDS
Definition: fs.h:62
ULONG DeviceId
Definition: fs.c:36
const DEVVTBL * FuncTable
Definition: fs.c:38
#define TAG_DEVICE
Definition: fs.c:32
ARC_SEEK Seek
Definition: fs.h:28
DBG_DEFAULT_CHANNEL(FILESYSTEM)
VOID FsSetFilePointer(PFILE FileHandle, ULONG NewFilePointer)
Definition: fs.c:367
ARC_STATUS ArcSeek(ULONG FileId, LARGE_INTEGER *Position, SEEKMODE SeekMode)
Definition: fs.c:244
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
GLenum GLsizei len
Definition: glext.h:6722
Definition: typedefs.h:117
ULONG FsGetFileSize(PFILE FileHandle)
Definition: fs.c:344
Status
Definition: gdiplustypes.h:24
ARC_GET_FILE_INFORMATION GetFileInformation
Definition: fs.h:25
#define ERR(fmt,...)
Definition: debug.h:109
Definition: arc.h:45
ULONG_PTR SIZE_T
Definition: typedefs.h:78
struct _FileName FileName
Definition: fatprocs.h:884
PRTL_UNICODE_STRING_BUFFER Path
struct tagDEVICE DEVICE
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
#define MachDiskGetBootPath(Path, Size)
Definition: machine.h:118
const DEVVTBL * BtrFsMount(ULONG DeviceId)
Definition: btrfs.c:1231
Definition: arc.h:42
const DEVVTBL * IsoMount(ULONG DeviceId)
Definition: iso.c:491
const DEVVTBL * PxeMount(ULONG DeviceId)
Definition: pxe.c:307
PFILE FsOpenFile(PCSTR FileName)
Definition: fs.c:266
const DEVVTBL * Ext2Mount(ULONG DeviceId)
Definition: ext2.c:1300
VOID FileSystemError(PCSTR ErrorString)
Definition: fs.c:260
VOID FsSetDeviceSpecific(ULONG FileId, VOID *Specific)
Definition: fs.c:467
unsigned int ULONG
Definition: retypes.h:1
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:261
Definition: fs.c:43
ULONG DeviceId
Definition: fs.c:48
const char * PCSTR
Definition: typedefs.h:51
GLfloat GLfloat p
Definition: glext.h:8902
enum _OPENMODE OPENMODE
#define PFILE
Definition: fs.h:37
VOID FsCloseFile(PFILE FileHandle)
Definition: fs.c:309
_Must_inspect_result_ _In_ PFILE_OBJECT _In_opt_ PLARGE_INTEGER _In_ ULONG _In_ FLT_IO_OPERATION_FLAGS _Out_opt_ PULONG BytesRead
Definition: fltkernel.h:1255
Iosb Information
Definition: create.c:4377
VOID FsRegisterDevice(CHAR *Prefix, const DEVVTBL *FuncTable)
Definition: fs.c:441