ReactOS 0.4.15-dev-7788-g1ad9096
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
42typedef struct _change {
43 void *data;
45 int size;
46 struct _change *next;
48
50#ifndef __REACTOS__
51static int fd, did_change = 0;
52#else
53static int did_change = 0;
54static HANDLE fd;
55static LARGE_INTEGER CurrentOffset;
56
57
58/**** Win32 / NT support ******************************************************/
59
60static int WIN32close(HANDLE FileHandle)
61{
63 return -1;
64 return 0;
65}
66#define close WIN32close
67
68static 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
93static int WIN32write(HANDLE FileHandle, void *buf, unsigned int len)
94{
97
99 NULL,
100 NULL,
101 NULL,
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
118static 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__
163void 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
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
213BOOLEAN 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
235NTSTATUS 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
255void 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
282void 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
344void fs_write(off_t pos, int size, void *data)
345{
346 CHANGE *new;
347 int did;
348
349#ifdef __REACTOS__
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
409static 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;
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;
439 if (lseek(fd, this->pos, 0) != this->pos)
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
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
475int fs_changed(void)
476{
477 return ! !changes || did_change;
478}
unsigned char BOOLEAN
#define read
Definition: acwin.h:96
#define O_RDONLY
Definition: acwin.h:108
#define open
Definition: acwin.h:95
#define close
Definition: acwin.h:98
#define write
Definition: acwin.h:97
LONG NTSTATUS
Definition: precomp.h:26
#define DPRINT1
Definition: precomp.h:8
IN PUNICODE_STRING IN POBJECT_ATTRIBUTES ObjectAttributes
Definition: conport.c:36
#define free
Definition: debug_ros.c:5
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define FILE_SHARE_READ
Definition: compat.h:136
unsigned int(__cdecl typeof(jpeg_read_scanlines))(struct jpeg_decompress_struct *
Definition: typeof.h:31
#define assert(x)
Definition: debug.h:53
return Iosb
Definition: create.c:4402
__kernel_size_t size_t
Definition: linux.h:237
__kernel_off_t off_t
Definition: linux.h:201
_Must_inspect_result_ _In_opt_ PFLT_INSTANCE _Out_ PHANDLE FileHandle
Definition: fltkernel.h:1231
#define FILE_SYNCHRONOUS_IO_ALERT
Definition: from_kernel.h:30
Status
Definition: gdiplustypes.h:25
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
GLsizeiptr size
Definition: glext.h:5919
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
GLenum GLsizei len
Definition: glext.h:6722
GLintptr offset
Definition: glext.h:5920
#define O_RDWR
Definition: fcntl.h:36
_CRTIMP void __cdecl perror(_In_opt_z_ const char *_ErrMsg)
#define stderr
Definition: stdio.h:100
_Check_return_opt_ _CRTIMP int __cdecl fprintf(_Inout_ FILE *_File, _In_z_ _Printf_format_string_ const char *_Format,...)
#define SEEK_SET
Definition: jmemansi.c:26
#define lseek
Definition: syshdrs.h:47
#define die(str)
Definition: mkdosfs.c:347
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
#define SEEK_CUR
Definition: util.h:63
static const struct @1635 read_write[]
static OUT PIO_STATUS_BLOCK IoStatusBlock
Definition: pipe.c:75
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:106
const char * strerror(int err)
Definition: compat_str.c:23
#define min(a, b)
Definition: monoChain.cc:55
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:3952
#define FSCTL_LOCK_VOLUME
Definition: nt_native.h:832
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 FSCTL_UNLOCK_VOLUME
Definition: nt_native.h:833
NTSTATUS NTAPI NtClose(IN HANDLE Handle)
Definition: obhandle.c:3402
#define FSCTL_DISMOUNT_VOLUME
Definition: nt_native.h:834
NTSYSAPI NTSTATUS NTAPI NtFsControlFile(IN HANDLE hFile, IN HANDLE hEvent OPTIONAL, IN PIO_APC_ROUTINE IoApcRoutine OPTIONAL, IN PVOID IoApcContext OPTIONAL, OUT PIO_STATUS_BLOCK pIoStatusBlock, IN ULONG DeviceIoControlCode, IN PVOID InBuffer OPTIONAL, IN ULONG InBufferLength, OUT PVOID OutBuffer OPTIONAL, IN ULONG OutBufferLength)
#define FILE_GENERIC_READ
Definition: nt_native.h:653
#define FILE_GENERIC_WRITE
Definition: nt_native.h:660
_In_ ULONG _In_ ULONG Offset
Definition: ntddpcm.h:101
static unsigned __int64 next
Definition: rand_nt.c:6
ULONG FsCheckFlags
Definition: vfatlib.c:44
#define alloc
Definition: rosglue.h:13
#define FSCHECK_IMMEDIATE_WRITE
Definition: rosglue.h:28
#define rw
Definition: rosglue.h:38
#define interactive
Definition: rosglue.h:34
#define write_immed
Definition: rosglue.h:39
#define errno
Definition: errno.h:18
#define exit(n)
Definition: config.h:202
void pdie(const char *msg,...)
Definition: common.c:74
static CHANGE * last
Definition: io.c:49
int fs_changed(void)
Definition: io.c:475
static CHANGE * changes
Definition: io.c:49
struct _change CHANGE
int fs_close(int write)
Definition: io.c:455
#define FSCTL_IS_VOLUME_DIRTY
Definition: io.c:40
int fs_test(off_t pos, int size)
Definition: io.c:322
static int fd
Definition: io.c:51
void fs_read(off_t pos, int size, void *data)
Definition: io.c:282
void fs_write(off_t pos, int size, void *data)
Definition: io.c:344
static int did_change
Definition: io.c:51
static void fs_flush(void)
Definition: io.c:409
void fs_open(char *path, int rw)
Definition: io.c:163
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)
Definition: io.c:42
int size
Definition: io.c:45
off_t pos
Definition: io.c:44
struct _change * next
Definition: io.c:46
void * data
Definition: io.c:43
#define new(TYPE, numElems)
Definition: treelist.c:54
#define LL
Definition: tui.h:167
int64_t LONGLONG
Definition: typedefs.h:68
uint32_t ULONG
Definition: typedefs.h:59
LONGLONG QuadPart
Definition: typedefs.h:114