ReactOS  0.4.13-dev-73-gcfe54aa
io.c
Go to the documentation of this file.
1 /* io.c - Virtual disk input/output
2 
3  Copyright (C) 1993 Werner Almesberger <werner.almesberger@lrc.di.epfl.ch>
4  Copyright (C) 1998 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
5  Copyright (C) 2008-2014 Daniel Baumann <mail@daniel-baumann.ch>
6  Copyright (C) 2015 Andreas Bombe <aeb@debian.org>
7 
8  This program is free software: you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation, either version 3 of the License, or
11  (at your option) any later version.
12 
13  This program is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with this program. If not, see <http://www.gnu.org/licenses/>.
20 
21  The complete text of the GNU General Public License
22  can be found in /usr/share/common-licenses/GPL-3 file.
23 */
24 
25 /*
26  * Thu Feb 26 01:15:36 CET 1998: Martin Schulze <joey@infodrom.north.de>
27  * Fixed nasty bug that caused every file with a name like
28  * xxxxxxxx.xxx to be treated as bad name that needed to be fixed.
29  */
30 
31 /* FAT32, VFAT, Atari format support, and various fixes additions May 1998
32  * by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */
33 
34 #include "vfatlib.h"
35 
36 #define NDEBUG
37 #include <debug.h>
38 
39 
40 #define FSCTL_IS_VOLUME_DIRTY CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 30, METHOD_BUFFERED, FILE_ANY_ACCESS)
41 
42 typedef struct _change {
43  void *data;
45  int size;
46  struct _change *next;
47 } CHANGE;
48 
49 static CHANGE *changes, *last;
50 #ifndef __REACTOS__
51 static int fd, did_change = 0;
52 #else
53 static int did_change = 0;
54 static HANDLE fd;
55 static LARGE_INTEGER CurrentOffset;
56 
57 
58 /**** Win32 / NT support ******************************************************/
59 
60 static int WIN32close(HANDLE FileHandle)
61 {
63  return -1;
64  return 0;
65 }
66 #define close WIN32close
67 
68 static int WIN32read(HANDLE FileHandle, void *buf, unsigned int len)
69 {
72 
74  NULL,
75  NULL,
76  NULL,
78  buf,
79  len,
80  &CurrentOffset,
81  NULL);
82  if (!NT_SUCCESS(Status))
83  {
84  DPRINT1("NtReadFile() failed (Status %lx)\n", Status);
85  return -1;
86  }
87 
88  CurrentOffset.QuadPart += len;
89  return (int)len;
90 }
91 #define read WIN32read
92 
93 static int WIN32write(HANDLE FileHandle, void *buf, unsigned int len)
94 {
97 
99  NULL,
100  NULL,
101  NULL,
102  &IoStatusBlock,
103  buf,
104  len,
105  &CurrentOffset,
106  NULL);
107  if (!NT_SUCCESS(Status))
108  {
109  DPRINT1("NtWriteFile() failed (Status %lx)\n", Status);
110  return -1;
111  }
112 
113  CurrentOffset.QuadPart += len;
114  return (int)len;
115 }
116 #define write WIN32write
117 
118 static off_t WIN32lseek(HANDLE fd, off_t offset, int whence)
119 {
121  Offset.QuadPart = (LONGLONG)offset;
122 
123  switch (whence)
124  {
125  case SEEK_SET:
126  break;
127 
128  case SEEK_CUR:
129  Offset.QuadPart += CurrentOffset.QuadPart;
130  break;
131 
132  // case SEEK_END:
133  // Offset.QuadPart += FileSize.QuadPart;
134  // break;
135 
136  default:
137  // errno = EINVAL;
138  return (off_t)-1;
139  }
140 
141  if (Offset.QuadPart < 0LL)
142  {
143  // errno = EINVAL;
144  return (off_t)-1;
145  }
146  // if (Offset.QuadPart > FileSize.QuadPart)
147  // {
148  // // errno = EINVAL;
149  // return (off_t)-1;
150  // }
151 
152  CurrentOffset = Offset;
153 
154  return CurrentOffset.QuadPart;
155 }
156 #define lseek WIN32lseek
157 
158 /******************************************************************************/
159 #endif
160 
161 
162 #ifndef __REACTOS__
163 void fs_open(char *path, int rw)
164 {
165  if ((fd = open(path, rw ? O_RDWR : O_RDONLY)) < 0) {
166  perror("open");
167  exit(6);
168  }
169  changes = last = NULL;
170  did_change = 0;
171 }
172 #else
174 {
178 
180  DriveRoot,
181  0,
182  NULL,
183  NULL);
184 
185  Status = NtOpenFile(&fd,
188  &Iosb,
191  if (!NT_SUCCESS(Status))
192  {
193  DPRINT1("NtOpenFile() failed with status 0x%.08x\n", Status);
194  return Status;
195  }
196 
197  // If read_write is specified, then the volume should be exclusively locked
198  if (read_write)
199  {
200  Status = fs_lock(TRUE);
201  }
202 
203  // Query geometry and partition info, to have bytes per sector, etc
204 
205  CurrentOffset.QuadPart = 0LL;
206 
207  changes = last = NULL;
208  did_change = 0;
209 
210  return Status;
211 }
212 
213 BOOLEAN fs_isdirty(void)
214 {
216  ULONG DirtyMask = 0;
217  IO_STATUS_BLOCK IoSb;
218 
219  /* Check if volume is dirty */
221  NULL, NULL, NULL, &IoSb,
223  NULL, 0, &DirtyMask, sizeof(DirtyMask));
224 
225  if (!NT_SUCCESS(Status))
226  {
227  DPRINT1("NtFsControlFile() failed with Status 0x%08x\n", Status);
228  return FALSE;
229  }
230 
231  /* Convert Dirty mask to a boolean value */
232  return (DirtyMask & 1);
233 }
234 
235 NTSTATUS fs_lock(BOOLEAN LockVolume)
236 {
238  IO_STATUS_BLOCK IoSb;
239 
240  /* Check if volume is dirty */
242  NULL, NULL, NULL, &IoSb,
243  LockVolume ? FSCTL_LOCK_VOLUME
245  NULL, 0, NULL, 0);
246 
247  if (!NT_SUCCESS(Status))
248  {
249  DPRINT1("NtFsControlFile() failed with Status 0x%08x\n", Status);
250  }
251 
252  return Status;
253 }
254 
255 void fs_dismount(void)
256 {
258  IO_STATUS_BLOCK IoSb;
259 
260  /* Check if volume is dirty */
262  NULL, NULL, NULL, &IoSb,
264  NULL, 0, NULL, 0);
265 
266  if (!NT_SUCCESS(Status))
267  {
268  DPRINT1("NtFsControlFile() failed with Status 0x%08x\n", Status);
269  }
270 }
271 #endif
272 
282 void fs_read(off_t pos, int size, void *data)
283 {
284  CHANGE *walk;
285  int got;
286 
287 #ifdef __REACTOS__
288  const size_t readsize_aligned = (size % 512) ? (size + (512 - (size % 512))) : size;
289  const off_t seekpos_aligned = pos - (pos % 512);
290  const size_t seek_delta = (size_t)(pos - seekpos_aligned);
291 #if DBG
292  const size_t readsize = (size_t)(pos - seekpos_aligned) + readsize_aligned;
293 #endif
294  char* tmpBuf = alloc(readsize_aligned);
295  if (lseek(fd, seekpos_aligned, 0) != seekpos_aligned) pdie("Seek to %lld",pos);
296  if ((got = read(fd, tmpBuf, readsize_aligned)) < 0) pdie("Read %d bytes at %lld",size,pos);
297  assert(got >= size);
298  got = size;
299  assert(seek_delta + size <= readsize);
300  memcpy(data, tmpBuf+seek_delta, size);
301  free(tmpBuf);
302 #else
303  if (lseek(fd, pos, 0) != pos)
304  pdie("Seek to %lld", (long long)pos);
305  if ((got = read(fd, data, size)) < 0)
306  pdie("Read %d bytes at %lld", size, (long long)pos);
307 #endif
308  if (got != size)
309  die("Got %d bytes instead of %d at %lld", got, size, (long long)pos);
310  for (walk = changes; walk; walk = walk->next) {
311  if (walk->pos < pos + size && walk->pos + walk->size > pos) {
312  if (walk->pos < pos)
313  memcpy(data, (char *)walk->data + pos - walk->pos,
314  min(size, walk->size - pos + walk->pos));
315  else
316  memcpy((char *)data + walk->pos - pos, walk->data,
317  min(walk->size, size + pos - walk->pos));
318  }
319  }
320 }
321 
323 {
324  void *scratch;
325  int okay;
326 
327 #ifdef __REACTOS__
328  const size_t readsize_aligned = (size % 512) ? (size + (512 - (size % 512))) : size; // TMN:
329  const off_t seekpos_aligned = pos - (pos % 512); // TMN:
330  scratch = alloc(readsize_aligned);
331  if (lseek(fd, seekpos_aligned, 0) != seekpos_aligned) pdie("Seek to %lld",pos);
332  okay = read(fd, scratch, readsize_aligned) == (int)readsize_aligned;
333  free(scratch);
334 #else
335  if (lseek(fd, pos, 0) != pos)
336  pdie("Seek to %lld", (long long)pos);
337  scratch = alloc(size);
338  okay = read(fd, scratch, size) == size;
339  free(scratch);
340 #endif
341  return okay;
342 }
343 
344 void fs_write(off_t pos, int size, void *data)
345 {
346  CHANGE *new;
347  int did;
348 
349 #ifdef __REACTOS__
350  assert(interactive || rw);
351 
353  void *scratch;
354  const size_t readsize_aligned = (size % 512) ? (size + (512 - (size % 512))) : size;
355  const off_t seekpos_aligned = pos - (pos % 512);
356  const size_t seek_delta = (size_t)(pos - seekpos_aligned);
357  BOOLEAN use_read = (seek_delta != 0) || ((readsize_aligned-size) != 0);
358 
359  /* Aloc temp buffer if write is not aligned */
360  if (use_read)
361  scratch = alloc(readsize_aligned);
362  else
363  scratch = data;
364 
365  did_change = 1;
366  if (lseek(fd, seekpos_aligned, 0) != seekpos_aligned) pdie("Seek to %lld",seekpos_aligned);
367 
368  if (use_read)
369  {
370  /* Read aligned data */
371  if (read(fd, scratch, readsize_aligned) < 0) pdie("Read %d bytes at %lld",size,pos);
372 
373  /* Patch data in memory */
374  memcpy((char *)scratch + seek_delta, data, size);
375  }
376 
377  /* Write it back */
378  if ((did = write(fd, scratch, readsize_aligned)) == (int)readsize_aligned)
379  {
380  if (use_read) free(scratch);
381  return;
382  }
383  if (did < 0) pdie("Write %d bytes at %lld", size, pos);
384  die("Wrote %d bytes instead of %d at %lld", did, size, pos);
385  }
386 #else
387  if (write_immed) {
388  did_change = 1;
389  if (lseek(fd, pos, 0) != pos)
390  pdie("Seek to %lld", (long long)pos);
391  if ((did = write(fd, data, size)) == size)
392  return;
393  if (did < 0)
394  pdie("Write %d bytes at %lld", size, (long long)pos);
395  die("Wrote %d bytes instead of %d at %lld", did, size, (long long)pos);
396  }
397 #endif
398  new = alloc(sizeof(CHANGE));
399  new->pos = pos;
400  memcpy(new->data = alloc(new->size = size), data, size);
401  new->next = NULL;
402  if (last)
403  last->next = new;
404  else
405  changes = new;
406  last = new;
407 }
408 
409 static void fs_flush(void)
410 {
411 #ifdef __REACTOS__
412 
413  CHANGE *this;
414  int old_write_immed = (FsCheckFlags & FSCHECK_IMMEDIATE_WRITE);
415 
416  /* Disable writes to the list now */
418 
419  while (changes) {
420  this = changes;
421  changes = changes->next;
422 
423  fs_write(this->pos, this->size, this->data);
424 
425  free(this->data);
426  free(this);
427  }
428 
429  /* Restore values */
430  if (!old_write_immed) FsCheckFlags ^= FSCHECK_IMMEDIATE_WRITE;
431 
432 #else
433  CHANGE *this;
434  int size;
435 
436  while (changes) {
437  this = changes;
438  changes = changes->next;
439  if (lseek(fd, this->pos, 0) != this->pos)
440  fprintf(stderr,
441  "Seek to %lld failed: %s\n Did not write %d bytes.\n",
442  (long long)this->pos, strerror(errno), this->size);
443  else if ((size = write(fd, this->data, this->size)) < 0)
444  fprintf(stderr, "Writing %d bytes at %lld failed: %s\n", this->size,
445  (long long)this->pos, strerror(errno));
446  else if (size != this->size)
447  fprintf(stderr, "Wrote %d bytes instead of %d bytes at %lld."
448  "\n", size, this->size, (long long)this->pos);
449  free(this->data);
450  free(this);
451  }
452 #endif
453 }
454 
455 int fs_close(int write)
456 {
457  CHANGE *next;
458  int changed;
459 
460  changed = ! !changes;
461  if (write)
462  fs_flush();
463  else
464  while (changes) {
465  next = changes->next;
466  free(changes->data);
467  free(changes);
468  changes = next;
469  }
470  if (close(fd) < 0)
471  pdie("closing filesystem");
472  return changed || did_change;
473 }
474 
475 int fs_changed(void)
476 {
477  return ! !changes || did_change;
478 }
#define FILE_GENERIC_READ
Definition: nt_native.h:653
IN PUNICODE_STRING IN POBJECT_ATTRIBUTES ObjectAttributes
Definition: conport.c:35
#define SEEK_CUR
Definition: util.h:63
#define FSCTL_UNLOCK_VOLUME
Definition: nt_native.h:833
#define TRUE
Definition: types.h:120
static CHANGE * changes
Definition: io.c:49
#define LL
Definition: tui.h:72
#define new(TYPE, numElems)
Definition: treelist.c:54
#define open
Definition: acwin.h:71
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
#define free
Definition: debug_ros.c:5
__kernel_off_t off_t
Definition: linux.h:201
LONG NTSTATUS
Definition: precomp.h:26
GLintptr offset
Definition: glext.h:5920
void * data
Definition: io.c:43
#define assert(x)
Definition: debug.h:53
static int fd
Definition: io.c:51
NTSYSCALLAPI NTSTATUS NTAPI NtFsControlFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, ULONG FsControlCode, PVOID InputBuffer, ULONG InputBufferLength, PVOID OutputBuffer, ULONG OutputBufferLength)
_Check_return_opt_ _CRTIMP long __cdecl lseek(_In_ int _FileHandle, _In_ long _Offset, _In_ int _Origin)
#define interactive
Definition: rosglue.h:34
int errno
const char * strerror(int err)
Definition: compat_str.c:23
void pdie(const char *msg,...)
Definition: common.c:74
void fs_open(char *path, int rw)
Definition: io.c:163
#define FILE_SHARE_READ
Definition: compat.h:125
void fs_write(off_t pos, int size, void *data)
Definition: io.c:344
static int did_change
Definition: io.c:51
#define write
Definition: acwin.h:73
int fs_test(off_t pos, int size)
Definition: io.c:322
HANDLE FileHandle
Definition: stats.c:38
ULONG FsCheckFlags
Definition: vfatlib.c:44
int fs_changed(void)
Definition: io.c:475
#define FILE_SYNCHRONOUS_IO_ALERT
Definition: from_kernel.h:30
_In_ ULONG _In_ ULONG Offset
Definition: ntddpcm.h:101
_CRTIMP void __cdecl perror(_In_opt_z_ const char *_ErrMsg)
_Check_return_opt_ _CRTIMP int __cdecl fprintf(_Inout_ FILE *_File, _In_z_ _Printf_format_string_ const char *_Format,...)
struct _change CHANGE
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
off_t pos
Definition: io.c:44
#define FSCTL_DISMOUNT_VOLUME
Definition: nt_native.h:834
__kernel_size_t size_t
Definition: linux.h:237
#define SEEK_SET
Definition: jmemansi.c:26
int64_t LONGLONG
Definition: typedefs.h:66
NTSYSAPI NTSTATUS NTAPI NtOpenFile(OUT PHANDLE phFile, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, OUT PIO_STATUS_BLOCK pIoStatusBlock, IN ULONG ShareMode, IN ULONG OpenMode)
Definition: file.c:3951
GLsizeiptr size
Definition: glext.h:5919
return Iosb
Definition: create.c:4426
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
void fs_read(off_t pos, int size, void *data)
Definition: io.c:282
int write_immed
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
NTSTATUS NTAPI NtClose(IN HANDLE Handle)
Definition: obhandle.c:3399
int rw
static void fs_flush(void)
Definition: io.c:409
NTSYSAPI NTSTATUS NTAPI NtWriteFile(IN HANDLE hFile, IN HANDLE hEvent OPTIONAL, IN PIO_APC_ROUTINE IoApcRoutine OPTIONAL, IN PVOID IoApcContext OPTIONAL, OUT PIO_STATUS_BLOCK pIoStatusBlock, IN PVOID WriteBuffer, IN ULONG WriteBufferLength, IN PLARGE_INTEGER FileOffset OPTIONAL, IN PULONG LockOperationKey OPTIONAL)
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
GLenum GLsizei len
Definition: glext.h:6722
#define close
Definition: acwin.h:74
Status
Definition: gdiplustypes.h:24
#define FSCTL_IS_VOLUME_DIRTY
Definition: io.c:40
#define FILE_GENERIC_WRITE
Definition: nt_native.h:660
static unsigned __int64 next
Definition: rand_nt.c:6
static CHANGE * last
Definition: io.c:49
#define O_RDWR
Definition: fcntl.h:36
Definition: services.c:325
static OUT PIO_STATUS_BLOCK IoStatusBlock
Definition: pipe.c:75
#define min(a, b)
Definition: monoChain.cc:55
#define alloc
Definition: rosglue.h:13
#define FSCHECK_IMMEDIATE_WRITE
Definition: rosglue.h:28
#define DPRINT1
Definition: precomp.h:8
#define FSCTL_LOCK_VOLUME
Definition: nt_native.h:832
static const struct @1575 read_write[]
unsigned int ULONG
Definition: retypes.h:1
FILE * stderr
int fs_close(int write)
Definition: io.c:455
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:106
int size
Definition: io.c:45
#define die(str)
Definition: mkdosfs.c:347
void exit(int exitcode)
Definition: _exit.c:33
struct _change * next
Definition: io.c:46
_CRTIMP int __cdecl read(_In_ int _FileHandle, _Out_writes_bytes_(_MaxCharCount) void *_DstBuf, _In_ unsigned int _MaxCharCount)
NTSTATUS NTAPI NtReadFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID Buffer, ULONG Length, PLARGE_INTEGER ByteOffset, PULONG Key)
LONGLONG QuadPart
Definition: typedefs.h:112
unsigned int(__cdecl typeof(jpeg_read_scanlines))(struct jpeg_decompress_struct *
Definition: typeof.h:31
#define O_RDONLY
Definition: acwin.h:82
Definition: io.c:42