* Sync up to trunk HEAD (r62502).
[reactos.git] / lib / fslib / vfatlib / check / io.c
1 /* io.c - Virtual disk input/output */
2
3 /* Written 1993 by Werner Almesberger */
4
5 /*
6 * Thu Feb 26 01:15:36 CET 1998: Martin Schulze <joey@infodrom.north.de>
7 * Fixed nasty bug that caused every file with a name like
8 * xxxxxxxx.xxx to be treated as bad name that needed to be fixed.
9 */
10
11 /* FAT32, VFAT, Atari format support, and various fixes additions May 1998
12 * by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */
13
14
15 #include "vfatlib.h"
16
17 #define NDEBUG
18 #include <debug.h>
19
20 #define FSCTL_IS_VOLUME_DIRTY CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 30, METHOD_BUFFERED, FILE_ANY_ACCESS)
21
22 typedef struct _change {
23 void *data;
24 loff_t pos;
25 int size;
26 struct _change *next;
27 } CHANGE;
28
29
30 static CHANGE *changes,*last;
31 static int did_change = 0;
32 static HANDLE fd;
33 static LARGE_INTEGER CurrentOffset;
34
35 unsigned device_no;
36
37 static int WIN32close(HANDLE fd);
38 #define close WIN32close
39 static int WIN32read(HANDLE fd, void *buf, unsigned int len);
40 #define read WIN32read
41 static int WIN32write(HANDLE fd, void *buf, unsigned int len);
42 #define write WIN32write
43 static loff_t WIN32llseek(HANDLE fd, loff_t offset, int whence);
44 #ifdef llseek
45 #undef llseek
46 #endif
47 #define llseek WIN32llseek
48
49 //static int is_device = 0;
50
51 void fs_open(PUNICODE_STRING DriveRoot,int rw)
52 {
53 OBJECT_ATTRIBUTES ObjectAttributes;
54 IO_STATUS_BLOCK Iosb;
55 NTSTATUS Status;
56
57 InitializeObjectAttributes(&ObjectAttributes,
58 DriveRoot,
59 0,
60 NULL,
61 NULL);
62
63 Status = NtOpenFile(&fd,
64 FILE_GENERIC_READ | (rw ? FILE_GENERIC_WRITE : 0),
65 &ObjectAttributes,
66 &Iosb,
67 rw ? 0 : FILE_SHARE_READ,
68 FILE_SYNCHRONOUS_IO_ALERT);
69 if (!NT_SUCCESS(Status))
70 {
71 DPRINT1("NtOpenFile() failed with status 0x%.08x\n", Status);
72 return;
73 }
74
75 // If rw is specified, then the volume should be exclusively locked
76 if (rw) fs_lock(TRUE);
77
78 // Query geometry and partition info, to have bytes per sector, etc
79
80 CurrentOffset.QuadPart = 0LL;
81
82 changes = last = NULL;
83 did_change = 0;
84 }
85
86 BOOLEAN fs_isdirty()
87 {
88 ULONG DirtyMask = 0;
89 NTSTATUS Status;
90 IO_STATUS_BLOCK IoSb;
91
92 /* Check if volume is dirty */
93 Status = NtFsControlFile(fd,
94 NULL, NULL, NULL, &IoSb,
95 FSCTL_IS_VOLUME_DIRTY,
96 NULL, 0, &DirtyMask, sizeof(DirtyMask));
97
98 if (!NT_SUCCESS(Status))
99 {
100 DPRINT1("NtFsControlFile() failed with Status 0x%08x\n", Status);
101 return FALSE;
102 }
103
104 /* Convert Dirty mask to a boolean value */
105 return (DirtyMask & 1);
106 }
107
108 NTSTATUS fs_lock(BOOLEAN LockVolume)
109 {
110 NTSTATUS Status;
111 IO_STATUS_BLOCK IoSb;
112
113 /* Check if volume is dirty */
114 Status = NtFsControlFile(fd,
115 NULL, NULL, NULL, &IoSb,
116 LockVolume ? FSCTL_LOCK_VOLUME :
117 FSCTL_UNLOCK_VOLUME,
118 NULL, 0, NULL, 0);
119
120 if (!NT_SUCCESS(Status))
121 {
122 DPRINT1("NtFsControlFile() failed with Status 0x%08x\n", Status);
123 }
124
125 return Status;
126 }
127
128 void fs_dismount()
129 {
130 NTSTATUS Status;
131 IO_STATUS_BLOCK IoSb;
132
133 /* Check if volume is dirty */
134 Status = NtFsControlFile(fd,
135 NULL, NULL, NULL, &IoSb,
136 FSCTL_DISMOUNT_VOLUME,
137 NULL, 0, NULL, 0);
138
139 if (!NT_SUCCESS(Status))
140 {
141 DPRINT1("NtFsControlFile() failed with Status 0x%08x\n", Status);
142 }
143 }
144
145 void fs_read(loff_t pos,int size,void *data)
146 {
147 CHANGE *walk;
148 int got;
149 #if 1 // TMN
150 const size_t readsize_aligned = (size % 512) ? (size + (512 - (size % 512))) : size; // TMN:
151 const loff_t seekpos_aligned = pos - (pos % 512); // TMN:
152 const size_t seek_delta = (size_t)(pos - seekpos_aligned); // TMN:
153 #if DBG
154 const size_t readsize = (size_t)(pos - seekpos_aligned) + readsize_aligned; // TMN:
155 #endif
156 char* tmpBuf = vfalloc(readsize_aligned); // TMN:
157 if (llseek(fd,seekpos_aligned,0) != seekpos_aligned) pdie("Seek to %I64d",pos);
158 if ((got = read(fd,tmpBuf,readsize_aligned)) < 0) pdie("Read %d bytes at %I64d",size,pos);
159 assert(got >= size);
160 got = size;
161 assert(seek_delta + size <= readsize);
162 memcpy(data, tmpBuf+seek_delta, size);
163 vffree(tmpBuf);
164 #else // TMN:
165 if (llseek(fd,pos,0) != pos) pdie("Seek to %lld",pos);
166 if ((got = read(fd,data,size)) < 0) pdie("Read %d bytes at %lld",size,pos);
167 #endif // TMN:
168 if (got != size) die("Got %d bytes instead of %d at %I64d",got,size,pos);
169 for (walk = changes; walk; walk = walk->next) {
170 if (walk->pos < pos+size && walk->pos+walk->size > pos) {
171 if (walk->pos < pos)
172 memcpy(data,(char *) walk->data+pos-walk->pos,min((size_t)size,
173 (size_t)(walk->size-pos+walk->pos)));
174 else memcpy((char *) data+walk->pos-pos,walk->data,min((size_t)walk->size,
175 (size_t)(size+pos-walk->pos)));
176 }
177 }
178 }
179
180
181 int fs_test(loff_t pos,int size)
182 {
183 void *scratch;
184 int okay;
185
186 #if 1 // TMN
187 const size_t readsize_aligned = (size % 512) ? (size + (512 - (size % 512))) : size; // TMN:
188 const loff_t seekpos_aligned = pos - (pos % 512); // TMN:
189 scratch = vfalloc(readsize_aligned);
190 if (llseek(fd,seekpos_aligned,0) != seekpos_aligned) pdie("Seek to %lld",pos);
191 okay = read(fd,scratch,readsize_aligned) == (int)readsize_aligned;
192 vffree(scratch);
193 #else // TMN:
194 if (llseek(fd,pos,0) != pos) pdie("Seek to %lld",pos);
195 scratch = vfalloc(size);
196 okay = read(fd,scratch,size) == size;
197 vffree(scratch);
198 #endif // TMN:
199 return okay;
200 }
201
202
203 void fs_write(loff_t pos,int size,void *data)
204 {
205 CHANGE *new;
206 int did;
207
208 #if 1 //SAE
209 if (FsCheckFlags & FSCHECK_IMMEDIATE_WRITE) {
210 void *scratch;
211 const size_t readsize_aligned = (size % 512) ? (size + (512 - (size % 512))) : size;
212 const loff_t seekpos_aligned = pos - (pos % 512);
213 const size_t seek_delta = (size_t)(pos - seekpos_aligned);
214 BOOLEAN use_read = (seek_delta != 0) || ((readsize_aligned-size) != 0);
215
216 /* Aloc temp buffer if write is not aligned */
217 if (use_read)
218 scratch = vfalloc(readsize_aligned);
219 else
220 scratch = data;
221
222 did_change = 1;
223 if (llseek(fd,seekpos_aligned,0) != seekpos_aligned) pdie("Seek to %I64d",seekpos_aligned);
224
225 if (use_read)
226 {
227 /* Read aligned data */
228 if (read(fd,scratch,readsize_aligned) < 0) pdie("Read %d bytes at %I64d",size,pos);
229
230 /* Patch data in memory */
231 memcpy((char *)scratch+seek_delta, data, size);
232 }
233
234 /* Write it back */
235 if ((did = write(fd,scratch,readsize_aligned)) == (int)readsize_aligned)
236 {
237 if (use_read) vffree(scratch);
238 return;
239 }
240 if (did < 0) pdie("Write %d bytes at %I64d",size,pos);
241 die("Wrote %d bytes instead of %d at %I64d",did,size,pos);
242 }
243
244 new = vfalloc(sizeof(CHANGE));
245 new->pos = pos;
246 memcpy(new->data = vfalloc(new->size = size),data,size);
247 new->next = NULL;
248 if (last) last->next = new;
249 else changes = new;
250 last = new;
251
252 #else //SAE
253 if (write_immed) {
254 did_change = 1;
255 if (llseek(fd,pos,0) != pos) pdie("Seek to %lld",pos);
256 if ((did = write(fd,data,size)) == size) return;
257 if (did < 0) pdie("Write %d bytes at %lld",size,pos);
258 die("Wrote %d bytes instead of %d at %lld",did,size,pos);
259 }
260 new = vfalloc(sizeof(CHANGE));
261 new->pos = pos;
262 memcpy(new->data = vfalloc(new->size = size),data,size);
263 new->next = NULL;
264 if (last) last->next = new;
265 else changes = new;
266 last = new;
267 #endif //SAE
268 }
269
270
271 static void fs_flush(void)
272 {
273 CHANGE *this;
274 int old_write_immed = (FsCheckFlags & FSCHECK_IMMEDIATE_WRITE);
275
276 /* Disable writes to the list now */
277 FsCheckFlags |= FSCHECK_IMMEDIATE_WRITE;
278
279 while (changes) {
280 this = changes;
281 changes = changes->next;
282
283 fs_write(this->pos, this->size, this->data);
284
285 vffree(this->data);
286 vffree(this);
287 }
288
289 /* Restore values */
290 if (!old_write_immed) FsCheckFlags ^= FSCHECK_IMMEDIATE_WRITE;
291 }
292
293
294 int fs_close(int write)
295 {
296 CHANGE *next;
297 int changed;
298
299 changed = !!changes;
300 if (write) fs_flush();
301 else while (changes) {
302 next = changes->next;
303 vffree(changes->data);
304 vffree(changes);
305 changes = next;
306 }
307 if (close(fd) < 0) pdie("closing file system");
308 return changed || did_change;
309 }
310
311
312 int fs_changed(void)
313 {
314 return !!changes || did_change;
315 }
316
317 /* Local Variables: */
318 /* tab-width: 8 */
319 /* End: */
320
321 static int WIN32close(HANDLE FileHandle)
322 {
323 if (!NT_SUCCESS(NtClose(FileHandle))) return -1;
324
325 return 0;
326 }
327
328 static int WIN32read(HANDLE FileHandle, void *buf, unsigned int len)
329 {
330 IO_STATUS_BLOCK IoStatusBlock;
331 NTSTATUS Status;
332
333 Status = NtReadFile(FileHandle,
334 NULL,
335 NULL,
336 NULL,
337 &IoStatusBlock,
338 buf,
339 len,
340 &CurrentOffset,
341 NULL);
342 if (!NT_SUCCESS(Status))
343 {
344 DPRINT1("NtReadFile() failed (Status %lx)\n", Status);
345 return -1;
346 }
347
348 CurrentOffset.QuadPart += len;
349 return (int)len;
350 }
351
352 static int WIN32write(HANDLE FileHandle, void *buf, unsigned int len)
353 {
354 IO_STATUS_BLOCK IoStatusBlock;
355 NTSTATUS Status;
356
357 Status = NtWriteFile(FileHandle,
358 NULL,
359 NULL,
360 NULL,
361 &IoStatusBlock,
362 buf,
363 len,
364 &CurrentOffset,
365 NULL);
366 if (!NT_SUCCESS(Status))
367 {
368 DPRINT1("NtWriteFile() failed (Status %lx)\n", Status);
369 return -1;
370 }
371
372 CurrentOffset.QuadPart += len;
373 return (int)len;
374 }
375
376 static loff_t WIN32llseek(HANDLE fd, loff_t offset, int whence)
377 {
378 CurrentOffset.QuadPart = (ULONGLONG)offset;
379
380 return offset;
381 }