1 /* io.c - Virtual disk input/output */
3 /* Written 1993 by Werner Almesberger */
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.
11 /* FAT32, VFAT, Atari format support, and various fixes additions May 1998
12 * by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */
20 #define FSCTL_IS_VOLUME_DIRTY CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 30, METHOD_BUFFERED, FILE_ANY_ACCESS)
22 typedef struct _change
{
30 static CHANGE
*changes
,*last
;
31 static int did_change
= 0;
33 static LARGE_INTEGER CurrentOffset
;
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
);
47 #define llseek WIN32llseek
49 //static int is_device = 0;
51 void fs_open(PUNICODE_STRING DriveRoot
,int rw
)
53 OBJECT_ATTRIBUTES ObjectAttributes
;
57 InitializeObjectAttributes(&ObjectAttributes
,
63 Status
= NtOpenFile(&fd
,
64 FILE_GENERIC_READ
| (rw
? FILE_GENERIC_WRITE
: 0),
67 rw
? 0 : FILE_SHARE_READ
,
68 FILE_SYNCHRONOUS_IO_ALERT
);
69 if (!NT_SUCCESS(Status
))
71 DPRINT1("NtOpenFile() failed with status 0x%.08x\n", Status
);
75 // If rw is specified, then the volume should be exclusively locked
76 if (rw
) fs_lock(TRUE
);
78 // Query geometry and partition info, to have bytes per sector, etc
80 CurrentOffset
.QuadPart
= 0LL;
82 changes
= last
= NULL
;
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
));
98 if (!NT_SUCCESS(Status
))
100 DPRINT1("NtFsControlFile() failed with Status 0x%08x\n", Status
);
104 /* Convert Dirty mask to a boolean value */
105 return (DirtyMask
& 1);
108 NTSTATUS
fs_lock(BOOLEAN LockVolume
)
111 IO_STATUS_BLOCK IoSb
;
113 /* Check if volume is dirty */
114 Status
= NtFsControlFile(fd
,
115 NULL
, NULL
, NULL
, &IoSb
,
116 LockVolume
? FSCTL_LOCK_VOLUME
:
120 if (!NT_SUCCESS(Status
))
122 DPRINT1("NtFsControlFile() failed with Status 0x%08x\n", Status
);
131 IO_STATUS_BLOCK IoSb
;
133 /* Check if volume is dirty */
134 Status
= NtFsControlFile(fd
,
135 NULL
, NULL
, NULL
, &IoSb
,
136 FSCTL_DISMOUNT_VOLUME
,
139 if (!NT_SUCCESS(Status
))
141 DPRINT1("NtFsControlFile() failed with Status 0x%08x\n", Status
);
145 void fs_read(loff_t pos
,int size
,void *data
)
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:
154 const size_t readsize
= (size_t)(pos
- seekpos_aligned
) + readsize_aligned
; // TMN:
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
);
161 assert(seek_delta
+ size
<= readsize
);
162 memcpy(data
, tmpBuf
+seek_delta
, size
);
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
);
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
) {
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
)));
181 int fs_test(loff_t pos
,int size
)
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
;
194 if (llseek(fd
,pos
,0) != pos
) pdie("Seek to %lld",pos
);
195 scratch
= vfalloc(size
);
196 okay
= read(fd
,scratch
,size
) == size
;
203 void fs_write(loff_t pos
,int size
,void *data
)
209 if (FsCheckFlags
& FSCHECK_IMMEDIATE_WRITE
) {
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);
216 /* Aloc temp buffer if write is not aligned */
218 scratch
= vfalloc(readsize_aligned
);
223 if (llseek(fd
,seekpos_aligned
,0) != seekpos_aligned
) pdie("Seek to %I64d",seekpos_aligned
);
227 /* Read aligned data */
228 if (read(fd
,scratch
,readsize_aligned
) < 0) pdie("Read %d bytes at %I64d",size
,pos
);
230 /* Patch data in memory */
231 memcpy((char *)scratch
+seek_delta
, data
, size
);
235 if ((did
= write(fd
,scratch
,readsize_aligned
)) == (int)readsize_aligned
)
237 if (use_read
) vffree(scratch
);
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
);
244 new = vfalloc(sizeof(CHANGE
));
246 memcpy(new->data
= vfalloc(new->size
= size
),data
,size
);
248 if (last
) last
->next
= new;
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
);
260 new = vfalloc(sizeof(CHANGE
));
262 memcpy(new->data
= vfalloc(new->size
= size
),data
,size
);
264 if (last
) last
->next
= new;
271 static void fs_flush(void)
274 int old_write_immed
= (FsCheckFlags
& FSCHECK_IMMEDIATE_WRITE
);
276 /* Disable writes to the list now */
277 FsCheckFlags
|= FSCHECK_IMMEDIATE_WRITE
;
281 changes
= changes
->next
;
283 fs_write(this->pos
, this->size
, this->data
);
290 if (!old_write_immed
) FsCheckFlags
^= FSCHECK_IMMEDIATE_WRITE
;
294 int fs_close(int write
)
300 if (write
) fs_flush();
301 else while (changes
) {
302 next
= changes
->next
;
303 vffree(changes
->data
);
307 if (close(fd
) < 0) pdie("closing file system");
308 return changed
|| did_change
;
314 return !!changes
|| did_change
;
317 /* Local Variables: */
321 static int WIN32close(HANDLE FileHandle
)
323 if (!NT_SUCCESS(NtClose(FileHandle
))) return -1;
328 static int WIN32read(HANDLE FileHandle
, void *buf
, unsigned int len
)
330 IO_STATUS_BLOCK IoStatusBlock
;
333 Status
= NtReadFile(FileHandle
,
342 if (!NT_SUCCESS(Status
))
344 DPRINT1("NtReadFile() failed (Status %lx)\n", Status
);
348 CurrentOffset
.QuadPart
+= len
;
352 static int WIN32write(HANDLE FileHandle
, void *buf
, unsigned int len
)
354 IO_STATUS_BLOCK IoStatusBlock
;
357 Status
= NtWriteFile(FileHandle
,
366 if (!NT_SUCCESS(Status
))
368 DPRINT1("NtWriteFile() failed (Status %lx)\n", Status
);
372 CurrentOffset
.QuadPart
+= len
;
376 static loff_t
WIN32llseek(HANDLE fd
, loff_t offset
, int whence
)
378 CurrentOffset
.QuadPart
= (ULONGLONG
)offset
;