another shot at fixing writes
[reactos.git] / rosapps / sysutils / dosfsck / 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 #include <stdlib.h>
15 #include <stdio.h>
16 #include <string.h>
17 //#include <unistd.h>
18 #include <sys/stat.h>
19 //#include <sys/ioctl.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <assert.h>
23 //#include <linux/fd.h>
24
25
26 #ifdef _WIN32
27 #define _WIN32_WINNT 0x0400
28 #include <windows.h>
29 #include <winioctl.h>
30 #define __LITTLE_ENDIAN 1234
31 #define __BIG_ENDIAN 4321
32 #define __BYTE_ORDER __LITTLE_ENDIAN
33 #define inline
34 #define __attribute__(x)
35 #define BLOCK_SIZE 512
36 #endif
37
38
39 #include "dosfsck.h"
40 #include "common.h"
41 #include "io.h"
42
43
44 typedef struct _change {
45 void *data;
46 loff_t pos;
47 int size;
48 struct _change *next;
49 } CHANGE;
50
51
52 static CHANGE *changes,*last;
53 static int fd,did_change = 0;
54
55 unsigned device_no;
56
57 static int WIN32open(const char *path, int oflag, ...);
58 #define open WIN32open
59 static int WIN32close(int fd);
60 #define close WIN32close
61 static int WIN32read(int fd, void *buf, unsigned int len);
62 #define read WIN32read
63 static int WIN32write(int fd, void *buf, unsigned int len);
64 #define write WIN32write
65 static loff_t WIN32llseek(int fd, loff_t offset, int whence);
66 #ifdef llseek
67 #undef llseek
68 #endif
69 #define llseek WIN32llseek
70
71 static int is_device = 0;
72
73 void fs_open(char *path,int rw)
74 {
75 #ifdef _WIN32
76 static char dev_buf[] = "\\\\.\\X:";
77 #else
78 struct stat stbuf;
79 #endif
80
81 if (path[1] == ':' && path[2] == '\0') {
82 dev_buf[4] = path[0];
83 path = dev_buf;
84 // is_device = 1;
85 }
86
87 if ((fd = open(path,rw ? O_RDWR : O_RDONLY)) < 0)
88 pdie("open %s",path);
89 changes = last = NULL;
90 did_change = 0;
91
92 #if 0
93 if (fstat(fd,&stbuf) < 0)
94 pdie("fstat %s",path);
95 device_no = S_ISBLK(stbuf.st_mode) ? (stbuf.st_rdev >> 8) & 0xff : 0;
96 #endif
97 }
98
99
100 void fs_read(loff_t pos,int size,void *data)
101 {
102 CHANGE *walk;
103 int got;
104 #if 1 // TMN
105 const size_t readsize_aligned = (size % 512) ? (size + (512 - (size % 512))) : size; // TMN:
106 const loff_t seekpos_aligned = pos - (pos % 512); // TMN:
107 const size_t seek_delta = (size_t)(pos - seekpos_aligned); // TMN:
108 const size_t readsize = (size_t)(pos - seekpos_aligned) + readsize_aligned; // TMN:
109 char* tmpBuf = malloc(readsize_aligned); // TMN:
110 #ifdef _MSC_VER
111 if (llseek(fd,seekpos_aligned,0) != seekpos_aligned) pdie("Seek to %I64d",pos);
112 if ((got = read(fd,tmpBuf,readsize_aligned)) < 0) pdie("Read %d bytes at %I64dd",size,pos);
113 #else
114 if (llseek(fd,seekpos_aligned,0) != seekpos_aligned) pdie("Seek to %lld",pos);
115 if ((got = read(fd,tmpBuf,readsize_aligned)) < 0) pdie("Read %d bytes at %lld",size,pos);
116 #endif
117 assert(got >= size);
118 got = size;
119 assert(seek_delta + size <= readsize);
120 memcpy(data, tmpBuf+seek_delta, size);
121 free(tmpBuf);
122 #else // TMN:
123 if (llseek(fd,pos,0) != pos) pdie("Seek to %lld",pos);
124 if ((got = read(fd,data,size)) < 0) pdie("Read %d bytes at %lld",size,pos);
125 #endif // TMN:
126 if (got != size) die("Got %d bytes instead of %d at %lld",got,size,pos);
127 for (walk = changes; walk; walk = walk->next) {
128 if (walk->pos < pos+size && walk->pos+walk->size > pos) {
129 if (walk->pos < pos)
130 memcpy(data,(char *) walk->data+pos-walk->pos,min((size_t)size,
131 (size_t)(walk->size-pos+walk->pos)));
132 else memcpy((char *) data+walk->pos-pos,walk->data,min((size_t)walk->size,
133 (size_t)(size+pos-walk->pos)));
134 }
135 }
136 }
137
138
139 int fs_test(loff_t pos,int size)
140 {
141 void *scratch;
142 int okay;
143
144 #if 1 // TMN
145 const size_t readsize_aligned = (size % 512) ? (size + (512 - (size % 512))) : size; // TMN:
146 const loff_t seekpos_aligned = pos - (pos % 512); // TMN:
147 const size_t seek_delta = (size_t)(pos - seekpos_aligned); // TMN:
148 const size_t readsize = (size_t)(pos - seekpos_aligned) + readsize_aligned; // TMN:
149 scratch = alloc(readsize_aligned);
150 if (llseek(fd,seekpos_aligned,0) != seekpos_aligned) pdie("Seek to %lld",pos);
151 okay = read(fd,scratch,readsize_aligned) == (int)readsize_aligned;
152 free(scratch);
153 #else // TMN:
154 if (llseek(fd,pos,0) != pos) pdie("Seek to %lld",pos);
155 scratch = alloc(size);
156 okay = read(fd,scratch,size) == size;
157 free(scratch);
158 #endif // TMN:
159 return okay;
160 }
161
162
163 void fs_write(loff_t pos,int size,void *data)
164 {
165 CHANGE *new;
166 int did;
167
168 #if 1 //SAE
169 void *scratch;
170 const size_t readsize_aligned = (size % 512) ? (size + (512 - (size % 512))) : size;
171 const loff_t seekpos_aligned = pos - (pos % 512);
172 const size_t seek_delta = (size_t)(pos - seekpos_aligned);
173 const size_t readsize = (size_t)(pos - seekpos_aligned) + readsize_aligned;
174 scratch = alloc(readsize_aligned);
175
176 if (write_immed) {
177 did_change = 1;
178 if (llseek(fd,seekpos_aligned,0) != seekpos_aligned) pdie("Seek to %lld",pos);
179 if ((did = write(fd,data,readsize_aligned)) == (int)readsize_aligned)
180 {
181 free(scratch);
182 return;
183 }
184 if (did < 0) pdie("Write %d bytes at %lld",size,pos);
185 die("Wrote %d bytes instead of %d at %lld",did,size,pos);
186 }
187 new = alloc(sizeof(CHANGE));
188 new->pos = pos;
189 memcpy(new->data = alloc(new->size = readsize_aligned),data,readsize_aligned);
190 new->next = NULL;
191 if (last) last->next = new;
192 else changes = new;
193 last = new;
194
195 #else //SAE
196 if (write_immed) {
197 did_change = 1;
198 if (llseek(fd,pos,0) != pos) pdie("Seek to %lld",pos);
199 if ((did = write(fd,data,size)) == size) return;
200 if (did < 0) pdie("Write %d bytes at %lld",size,pos);
201 die("Wrote %d bytes instead of %d at %lld",did,size,pos);
202 }
203 new = alloc(sizeof(CHANGE));
204 new->pos = pos;
205 memcpy(new->data = alloc(new->size = size),data,size);
206 new->next = NULL;
207 if (last) last->next = new;
208 else changes = new;
209 last = new;
210 #endif //SAE
211 }
212
213
214 static void fs_flush(void)
215 {
216 CHANGE *this;
217 int size;
218
219 while (changes) {
220 this = changes;
221 changes = changes->next;
222 if (llseek(fd,this->pos,0) != this->pos)
223 fprintf(stderr,"Seek to %lld failed: %s\n Did not write %d bytes.\n",
224 (__int64)this->pos,strerror(errno),this->size);
225 else if ((size = write(fd,this->data,this->size)) < 0)
226 fprintf(stderr,"Writing %d bytes at %lld failed: %s\n",this->size,
227 (__int64)this->pos,strerror(errno));
228 else if (size != this->size)
229 fprintf(stderr,"Wrote %d bytes instead of %d bytes at %lld."
230 "\n",size,this->size,(__int64)this->pos);
231 free(this->data);
232 free(this);
233 }
234 }
235
236
237 int fs_close(int write)
238 {
239 CHANGE *next;
240 int changed;
241
242 changed = !!changes;
243 if (write) fs_flush();
244 else while (changes) {
245 next = changes->next;
246 free(changes->data);
247 free(changes);
248 changes = next;
249 }
250 if (close(fd) < 0) pdie("closing file system");
251 return changed || did_change;
252 }
253
254
255 int fs_changed(void)
256 {
257 return !!changes || did_change;
258 }
259
260 /* Local Variables: */
261 /* tab-width: 8 */
262 /* End: */
263
264
265 #define O_SHORT_LIVED _O_SHORT_LIVED
266 //#define O_ACCMODE 3
267 #define O_NONE 3
268 #define O_BACKUP 0x10000
269 #define O_SHARED 0x20000
270
271 static int WIN32open(const char *path, int oflag, ...)
272 {
273 HANDLE fh;
274 DWORD desiredAccess;
275 DWORD shareMode;
276 DWORD creationDisposition;
277 DWORD flagsAttributes = FILE_ATTRIBUTE_NORMAL;
278 SECURITY_ATTRIBUTES securityAttributes;
279 va_list ap;
280 int pmode;
281 int trunc = FALSE;
282
283 securityAttributes.nLength = sizeof(securityAttributes);
284 securityAttributes.lpSecurityDescriptor = NULL;
285 securityAttributes.bInheritHandle = oflag & O_NOINHERIT ? FALSE : TRUE;
286 switch (oflag & O_ACCMODE) {
287 case O_RDONLY:
288 desiredAccess = GENERIC_READ;
289 // shareMode = FILE_SHARE_READ;
290 shareMode = FILE_SHARE_READ|FILE_SHARE_WRITE; // TMN:
291 break;
292 case O_WRONLY:
293 desiredAccess = GENERIC_WRITE;
294 shareMode = 0;
295 break;
296 case O_RDWR:
297 desiredAccess = GENERIC_READ|GENERIC_WRITE;
298 shareMode = 0;
299 break;
300 case O_NONE:
301 desiredAccess = 0;
302 shareMode = FILE_SHARE_READ|FILE_SHARE_WRITE;
303 }
304 if (oflag & O_APPEND) {
305 desiredAccess |= FILE_APPEND_DATA|SYNCHRONIZE;
306 shareMode = FILE_SHARE_READ|FILE_SHARE_WRITE;
307 }
308 if (oflag & O_SHARED)
309 shareMode |= FILE_SHARE_READ|FILE_SHARE_WRITE;
310 switch (oflag & (O_CREAT|O_EXCL|O_TRUNC)) {
311 case 0:
312 case O_EXCL:
313 creationDisposition = OPEN_EXISTING;
314 break;
315 case O_CREAT:
316 creationDisposition = OPEN_ALWAYS;
317 break;
318 case O_CREAT|O_EXCL:
319 case O_CREAT|O_TRUNC|O_EXCL:
320 creationDisposition = CREATE_NEW;
321 break;
322 case O_TRUNC:
323 case O_TRUNC|O_EXCL:
324 creationDisposition = TRUNCATE_EXISTING;
325 break;
326 case O_CREAT|O_TRUNC:
327 creationDisposition = OPEN_ALWAYS;
328 trunc = TRUE;
329 break;
330 }
331 if (oflag & O_CREAT) {
332 va_start(ap, oflag);
333 pmode = va_arg(ap, int);
334 va_end(ap);
335 if ((pmode & 0222) == 0)
336 flagsAttributes |= FILE_ATTRIBUTE_READONLY;
337 }
338 if (oflag & O_TEMPORARY) {
339 flagsAttributes |= FILE_FLAG_DELETE_ON_CLOSE;
340 desiredAccess |= DELETE;
341 }
342 if (oflag & O_SHORT_LIVED)
343 flagsAttributes |= FILE_ATTRIBUTE_TEMPORARY;
344 if (oflag & O_SEQUENTIAL)
345 flagsAttributes |= FILE_FLAG_SEQUENTIAL_SCAN;
346 else if (oflag & O_RANDOM)
347 flagsAttributes |= FILE_FLAG_RANDOM_ACCESS;
348 if (oflag & O_BACKUP)
349 flagsAttributes |= FILE_FLAG_BACKUP_SEMANTICS;
350 if ((fh = CreateFile(path, desiredAccess, shareMode, &securityAttributes,
351 creationDisposition, flagsAttributes, NULL)) == INVALID_HANDLE_VALUE) {
352 errno = GetLastError();
353 return -1;
354 }
355 if (trunc) {
356 if (!SetEndOfFile(fh)) {
357 errno = GetLastError();
358 CloseHandle(fh);
359 DeleteFile(path);
360 return -1;
361 }
362 }
363 return (int)fh;
364 }
365
366 static int WIN32close(int fd)
367 {
368 if (!CloseHandle((HANDLE)fd)) {
369 errno = GetLastError();
370 return -1;
371 }
372 return 0;
373 }
374
375 static int WIN32read(int fd, void *buf, unsigned int len)
376 {
377 DWORD actualLen;
378
379 if (!ReadFile((HANDLE)fd, buf, (DWORD)len, &actualLen, NULL)) {
380 errno = GetLastError();
381 if (errno == ERROR_BROKEN_PIPE)
382 return 0;
383 else
384 return -1;
385 }
386 return (int)actualLen;
387 }
388
389 static int WIN32write(int fd, void *buf, unsigned int len)
390 {
391 DWORD actualLen;
392
393 if (!WriteFile((HANDLE)fd, buf, (DWORD)len, &actualLen, NULL)) {
394 errno = GetLastError();
395 return -1;
396 }
397 return (int)actualLen;
398 }
399
400 static loff_t WIN32llseek(int fd, loff_t offset, int whence)
401 {
402 long lo, hi;
403 DWORD err;
404
405 lo = (long)(offset & 0xffffffff);
406 hi = (long)(offset >> 32);
407 lo = SetFilePointer((HANDLE)fd, lo, &hi, whence);
408 if (lo == 0xFFFFFFFF && (err = GetLastError()) != NO_ERROR) {
409 errno = err;
410 return -1;
411 }
412 return ((loff_t)hi << 32) | (__u32)lo;
413 }
414
415 int fsctl(int fd, int code)
416 {
417 DWORD ret;
418 if (!DeviceIoControl((HANDLE)fd, code, NULL, 0, NULL, 0, &ret, NULL)) {
419 errno = GetLastError();
420 return -1;
421 }
422 return 0;
423 }