2005-07-28 02:37:42 +00:00
|
|
|
/* io.c - Virtual disk input/output */
|
|
|
|
|
|
|
|
/* Written 1993 by Werner Almesberger */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Thu Feb 26 01:15:36 CET 1998: Martin Schulze <joey@infodrom.north.de>
|
|
|
|
* Fixed nasty bug that caused every file with a name like
|
|
|
|
* xxxxxxxx.xxx to be treated as bad name that needed to be fixed.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* FAT32, VFAT, Atari format support, and various fixes additions May 1998
|
|
|
|
* by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
2005-07-29 16:48:09 +00:00
|
|
|
//#include <unistd.h>
|
2005-07-28 02:37:42 +00:00
|
|
|
#include <sys/stat.h>
|
|
|
|
//#include <sys/ioctl.h>
|
|
|
|
#include <errno.h>
|
2005-07-29 16:48:09 +00:00
|
|
|
#include <fcntl.h>
|
|
|
|
#include <assert.h>
|
2005-07-28 02:37:42 +00:00
|
|
|
//#include <linux/fd.h>
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
#define _WIN32_WINNT 0x0400
|
|
|
|
#include <windows.h>
|
|
|
|
#include <winioctl.h>
|
|
|
|
#define __LITTLE_ENDIAN 1234
|
|
|
|
#define __BIG_ENDIAN 4321
|
|
|
|
#define __BYTE_ORDER __LITTLE_ENDIAN
|
|
|
|
#define inline
|
|
|
|
#define __attribute__(x)
|
|
|
|
#define BLOCK_SIZE 512
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
#include "dosfsck.h"
|
|
|
|
#include "common.h"
|
|
|
|
#include "io.h"
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct _change {
|
|
|
|
void *data;
|
|
|
|
loff_t pos;
|
|
|
|
int size;
|
|
|
|
struct _change *next;
|
|
|
|
} CHANGE;
|
|
|
|
|
|
|
|
|
|
|
|
static CHANGE *changes,*last;
|
|
|
|
static int fd,did_change = 0;
|
|
|
|
|
|
|
|
unsigned device_no;
|
|
|
|
|
2005-07-28 18:34:01 +00:00
|
|
|
static int WIN32open(const char *path, int oflag, ...);
|
|
|
|
#define open WIN32open
|
|
|
|
static int WIN32close(int fd);
|
|
|
|
#define close WIN32close
|
|
|
|
static int WIN32read(int fd, void *buf, unsigned int len);
|
|
|
|
#define read WIN32read
|
|
|
|
static int WIN32write(int fd, void *buf, unsigned int len);
|
|
|
|
#define write WIN32write
|
|
|
|
static loff_t WIN32llseek(int fd, loff_t offset, int whence);
|
2005-07-29 16:48:09 +00:00
|
|
|
#ifdef llseek
|
|
|
|
#undef llseek
|
|
|
|
#endif
|
2005-07-28 18:34:01 +00:00
|
|
|
#define llseek WIN32llseek
|
|
|
|
|
|
|
|
static int is_device = 0;
|
|
|
|
|
2005-07-28 02:37:42 +00:00
|
|
|
void fs_open(char *path,int rw)
|
|
|
|
{
|
2005-07-28 18:34:01 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
static char dev_buf[] = "\\\\.\\X:";
|
|
|
|
#else
|
2005-07-28 02:37:42 +00:00
|
|
|
struct stat stbuf;
|
2005-07-28 18:34:01 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
if (path[1] == ':' && path[2] == '\0') {
|
|
|
|
dev_buf[4] = path[0];
|
|
|
|
path = dev_buf;
|
|
|
|
// is_device = 1;
|
|
|
|
}
|
|
|
|
|
2005-07-28 02:37:42 +00:00
|
|
|
if ((fd = open(path,rw ? O_RDWR : O_RDONLY)) < 0)
|
|
|
|
pdie("open %s",path);
|
|
|
|
changes = last = NULL;
|
|
|
|
did_change = 0;
|
|
|
|
|
2005-07-28 18:34:01 +00:00
|
|
|
#if 0
|
2005-07-28 02:37:42 +00:00
|
|
|
if (fstat(fd,&stbuf) < 0)
|
|
|
|
pdie("fstat %s",path);
|
|
|
|
device_no = S_ISBLK(stbuf.st_mode) ? (stbuf.st_rdev >> 8) & 0xff : 0;
|
2005-07-28 18:34:01 +00:00
|
|
|
#endif
|
2005-07-28 02:37:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void fs_read(loff_t pos,int size,void *data)
|
|
|
|
{
|
|
|
|
CHANGE *walk;
|
2005-07-29 16:48:09 +00:00
|
|
|
int got;
|
2005-07-29 22:22:12 +00:00
|
|
|
#if 1 // TMN
|
|
|
|
const size_t readsize_aligned = (size % 512) ? (size + (512 - (size % 512))) : size; // TMN:
|
|
|
|
const loff_t seekpos_aligned = pos - (pos % 512); // TMN:
|
|
|
|
const size_t seek_delta = (size_t)(pos - seekpos_aligned); // TMN:
|
|
|
|
const size_t readsize = (size_t)(pos - seekpos_aligned) + readsize_aligned; // TMN:
|
|
|
|
char* tmpBuf = malloc(readsize_aligned); // TMN:
|
|
|
|
#ifdef _MSC_VER
|
|
|
|
if (llseek(fd,seekpos_aligned,0) != seekpos_aligned) pdie("Seek to %I64d",pos);
|
|
|
|
if ((got = read(fd,tmpBuf,readsize_aligned)) < 0) pdie("Read %d bytes at %I64dd",size,pos);
|
|
|
|
#else
|
|
|
|
if (llseek(fd,seekpos_aligned,0) != seekpos_aligned) pdie("Seek to %lld",pos);
|
|
|
|
if ((got = read(fd,tmpBuf,readsize_aligned)) < 0) pdie("Read %d bytes at %lld",size,pos);
|
|
|
|
#endif
|
2005-07-29 16:48:09 +00:00
|
|
|
assert(got >= size);
|
2005-07-29 22:22:12 +00:00
|
|
|
got = size;
|
|
|
|
assert(seek_delta + size <= readsize);
|
2005-07-29 16:48:09 +00:00
|
|
|
memcpy(data, tmpBuf+seek_delta, size);
|
|
|
|
free(tmpBuf);
|
|
|
|
#else // TMN:
|
2005-07-28 02:37:42 +00:00
|
|
|
if (llseek(fd,pos,0) != pos) pdie("Seek to %lld",pos);
|
2005-07-29 16:48:09 +00:00
|
|
|
if ((got = read(fd,data,size)) < 0) pdie("Read %d bytes at %lld",size,pos);
|
|
|
|
#endif // TMN:
|
2005-07-28 02:37:42 +00:00
|
|
|
if (got != size) die("Got %d bytes instead of %d at %lld",got,size,pos);
|
|
|
|
for (walk = changes; walk; walk = walk->next) {
|
|
|
|
if (walk->pos < pos+size && walk->pos+walk->size > pos) {
|
|
|
|
if (walk->pos < pos)
|
2005-07-29 22:22:12 +00:00
|
|
|
memcpy(data,(char *) walk->data+pos-walk->pos,min((size_t)size,
|
|
|
|
(size_t)(walk->size-pos+walk->pos)));
|
|
|
|
else memcpy((char *) data+walk->pos-pos,walk->data,min((size_t)walk->size,
|
|
|
|
(size_t)(size+pos-walk->pos)));
|
2005-07-28 02:37:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int fs_test(loff_t pos,int size)
|
|
|
|
{
|
|
|
|
void *scratch;
|
|
|
|
int okay;
|
|
|
|
|
2005-07-29 22:22:12 +00:00
|
|
|
#if 1 // TMN
|
|
|
|
const size_t readsize_aligned = (size % 512) ? (size + (512 - (size % 512))) : size; // TMN:
|
|
|
|
const loff_t seekpos_aligned = pos - (pos % 512); // TMN:
|
|
|
|
const size_t seek_delta = (size_t)(pos - seekpos_aligned); // TMN:
|
|
|
|
const size_t readsize = (size_t)(pos - seekpos_aligned) + readsize_aligned; // TMN:
|
|
|
|
scratch = alloc(readsize_aligned);
|
|
|
|
if (llseek(fd,seekpos_aligned,0) != seekpos_aligned) pdie("Seek to %lld",pos);
|
|
|
|
okay = read(fd,scratch,readsize_aligned) == (int)readsize_aligned;
|
|
|
|
free(scratch);
|
|
|
|
#else // TMN:
|
2005-07-28 02:37:42 +00:00
|
|
|
if (llseek(fd,pos,0) != pos) pdie("Seek to %lld",pos);
|
|
|
|
scratch = alloc(size);
|
|
|
|
okay = read(fd,scratch,size) == size;
|
|
|
|
free(scratch);
|
2005-07-29 22:22:12 +00:00
|
|
|
#endif // TMN:
|
2005-07-28 02:37:42 +00:00
|
|
|
return okay;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void fs_write(loff_t pos,int size,void *data)
|
|
|
|
{
|
|
|
|
CHANGE *new;
|
|
|
|
int did;
|
|
|
|
|
|
|
|
if (write_immed) {
|
|
|
|
did_change = 1;
|
|
|
|
if (llseek(fd,pos,0) != pos) pdie("Seek to %lld",pos);
|
|
|
|
if ((did = write(fd,data,size)) == size) return;
|
|
|
|
if (did < 0) pdie("Write %d bytes at %lld",size,pos);
|
|
|
|
die("Wrote %d bytes instead of %d at %lld",did,size,pos);
|
|
|
|
}
|
|
|
|
new = alloc(sizeof(CHANGE));
|
|
|
|
new->pos = pos;
|
|
|
|
memcpy(new->data = alloc(new->size = size),data,size);
|
|
|
|
new->next = NULL;
|
|
|
|
if (last) last->next = new;
|
|
|
|
else changes = new;
|
|
|
|
last = new;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void fs_flush(void)
|
|
|
|
{
|
|
|
|
CHANGE *this;
|
|
|
|
int size;
|
|
|
|
|
|
|
|
while (changes) {
|
|
|
|
this = changes;
|
|
|
|
changes = changes->next;
|
|
|
|
if (llseek(fd,this->pos,0) != this->pos)
|
|
|
|
fprintf(stderr,"Seek to %lld failed: %s\n Did not write %d bytes.\n",
|
2005-07-29 16:48:09 +00:00
|
|
|
(__int64)this->pos,strerror(errno),this->size);
|
2005-07-28 02:37:42 +00:00
|
|
|
else if ((size = write(fd,this->data,this->size)) < 0)
|
|
|
|
fprintf(stderr,"Writing %d bytes at %lld failed: %s\n",this->size,
|
2005-07-29 16:48:09 +00:00
|
|
|
(__int64)this->pos,strerror(errno));
|
2005-07-28 02:37:42 +00:00
|
|
|
else if (size != this->size)
|
|
|
|
fprintf(stderr,"Wrote %d bytes instead of %d bytes at %lld."
|
2005-07-29 16:48:09 +00:00
|
|
|
"\n",size,this->size,(__int64)this->pos);
|
2005-07-28 02:37:42 +00:00
|
|
|
free(this->data);
|
|
|
|
free(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int fs_close(int write)
|
|
|
|
{
|
|
|
|
CHANGE *next;
|
|
|
|
int changed;
|
|
|
|
|
|
|
|
changed = !!changes;
|
|
|
|
if (write) fs_flush();
|
|
|
|
else while (changes) {
|
|
|
|
next = changes->next;
|
|
|
|
free(changes->data);
|
|
|
|
free(changes);
|
|
|
|
changes = next;
|
|
|
|
}
|
|
|
|
if (close(fd) < 0) pdie("closing file system");
|
|
|
|
return changed || did_change;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int fs_changed(void)
|
|
|
|
{
|
|
|
|
return !!changes || did_change;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Local Variables: */
|
|
|
|
/* tab-width: 8 */
|
|
|
|
/* End: */
|
|
|
|
|
|
|
|
|
|
|
|
#define O_SHORT_LIVED _O_SHORT_LIVED
|
2005-07-29 22:22:12 +00:00
|
|
|
//#define O_ACCMODE 3
|
2005-07-28 02:37:42 +00:00
|
|
|
#define O_NONE 3
|
|
|
|
#define O_BACKUP 0x10000
|
|
|
|
#define O_SHARED 0x20000
|
|
|
|
|
|
|
|
static int WIN32open(const char *path, int oflag, ...)
|
|
|
|
{
|
|
|
|
HANDLE fh;
|
|
|
|
DWORD desiredAccess;
|
|
|
|
DWORD shareMode;
|
|
|
|
DWORD creationDisposition;
|
|
|
|
DWORD flagsAttributes = FILE_ATTRIBUTE_NORMAL;
|
|
|
|
SECURITY_ATTRIBUTES securityAttributes;
|
|
|
|
va_list ap;
|
|
|
|
int pmode;
|
|
|
|
int trunc = FALSE;
|
|
|
|
|
|
|
|
securityAttributes.nLength = sizeof(securityAttributes);
|
|
|
|
securityAttributes.lpSecurityDescriptor = NULL;
|
|
|
|
securityAttributes.bInheritHandle = oflag & O_NOINHERIT ? FALSE : TRUE;
|
|
|
|
switch (oflag & O_ACCMODE) {
|
|
|
|
case O_RDONLY:
|
|
|
|
desiredAccess = GENERIC_READ;
|
2005-07-29 16:48:09 +00:00
|
|
|
// shareMode = FILE_SHARE_READ;
|
|
|
|
shareMode = FILE_SHARE_READ|FILE_SHARE_WRITE; // TMN:
|
2005-07-28 02:37:42 +00:00
|
|
|
break;
|
|
|
|
case O_WRONLY:
|
2005-07-29 16:48:09 +00:00
|
|
|
exit(42);
|
2005-07-28 02:37:42 +00:00
|
|
|
desiredAccess = GENERIC_WRITE;
|
|
|
|
shareMode = 0;
|
|
|
|
break;
|
|
|
|
case O_RDWR:
|
2005-07-29 16:48:09 +00:00
|
|
|
exit(43);
|
2005-07-28 02:37:42 +00:00
|
|
|
desiredAccess = GENERIC_READ|GENERIC_WRITE;
|
|
|
|
shareMode = 0;
|
|
|
|
break;
|
|
|
|
case O_NONE:
|
2005-07-29 16:48:09 +00:00
|
|
|
exit(44);
|
2005-07-28 02:37:42 +00:00
|
|
|
desiredAccess = 0;
|
|
|
|
shareMode = FILE_SHARE_READ|FILE_SHARE_WRITE;
|
|
|
|
}
|
|
|
|
if (oflag & O_APPEND) {
|
2005-07-29 16:48:09 +00:00
|
|
|
exit(45);
|
2005-07-28 02:37:42 +00:00
|
|
|
desiredAccess |= FILE_APPEND_DATA|SYNCHRONIZE;
|
|
|
|
shareMode = FILE_SHARE_READ|FILE_SHARE_WRITE;
|
|
|
|
}
|
|
|
|
if (oflag & O_SHARED)
|
|
|
|
shareMode |= FILE_SHARE_READ|FILE_SHARE_WRITE;
|
|
|
|
switch (oflag & (O_CREAT|O_EXCL|O_TRUNC)) {
|
|
|
|
case 0:
|
|
|
|
case O_EXCL:
|
|
|
|
creationDisposition = OPEN_EXISTING;
|
|
|
|
break;
|
|
|
|
case O_CREAT:
|
2005-07-29 16:48:09 +00:00
|
|
|
exit(46);
|
2005-07-28 02:37:42 +00:00
|
|
|
creationDisposition = OPEN_ALWAYS;
|
|
|
|
break;
|
|
|
|
case O_CREAT|O_EXCL:
|
|
|
|
case O_CREAT|O_TRUNC|O_EXCL:
|
2005-07-29 16:48:09 +00:00
|
|
|
exit(47);
|
2005-07-28 02:37:42 +00:00
|
|
|
creationDisposition = CREATE_NEW;
|
|
|
|
break;
|
|
|
|
case O_TRUNC:
|
|
|
|
case O_TRUNC|O_EXCL:
|
2005-07-29 16:48:09 +00:00
|
|
|
exit(48);
|
2005-07-28 02:37:42 +00:00
|
|
|
creationDisposition = TRUNCATE_EXISTING;
|
|
|
|
break;
|
|
|
|
case O_CREAT|O_TRUNC:
|
2005-07-29 16:48:09 +00:00
|
|
|
exit(49);
|
2005-07-28 02:37:42 +00:00
|
|
|
creationDisposition = OPEN_ALWAYS;
|
|
|
|
trunc = TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (oflag & O_CREAT) {
|
2005-07-29 16:48:09 +00:00
|
|
|
exit(50);
|
2005-07-28 02:37:42 +00:00
|
|
|
va_start(ap, oflag);
|
|
|
|
pmode = va_arg(ap, int);
|
|
|
|
va_end(ap);
|
|
|
|
if ((pmode & 0222) == 0)
|
|
|
|
flagsAttributes |= FILE_ATTRIBUTE_READONLY;
|
|
|
|
}
|
|
|
|
if (oflag & O_TEMPORARY) {
|
2005-07-29 16:48:09 +00:00
|
|
|
exit(51);
|
2005-07-28 02:37:42 +00:00
|
|
|
flagsAttributes |= FILE_FLAG_DELETE_ON_CLOSE;
|
|
|
|
desiredAccess |= DELETE;
|
|
|
|
}
|
|
|
|
if (oflag & O_SHORT_LIVED)
|
|
|
|
flagsAttributes |= FILE_ATTRIBUTE_TEMPORARY;
|
|
|
|
if (oflag & O_SEQUENTIAL)
|
|
|
|
flagsAttributes |= FILE_FLAG_SEQUENTIAL_SCAN;
|
|
|
|
else if (oflag & O_RANDOM)
|
|
|
|
flagsAttributes |= FILE_FLAG_RANDOM_ACCESS;
|
|
|
|
if (oflag & O_BACKUP)
|
|
|
|
flagsAttributes |= FILE_FLAG_BACKUP_SEMANTICS;
|
|
|
|
if ((fh = CreateFile(path, desiredAccess, shareMode, &securityAttributes,
|
|
|
|
creationDisposition, flagsAttributes, NULL)) == INVALID_HANDLE_VALUE) {
|
|
|
|
errno = GetLastError();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (trunc) {
|
2005-07-29 16:48:09 +00:00
|
|
|
exit(52);
|
2005-07-28 02:37:42 +00:00
|
|
|
if (!SetEndOfFile(fh)) {
|
|
|
|
errno = GetLastError();
|
|
|
|
CloseHandle(fh);
|
|
|
|
DeleteFile(path);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return (int)fh;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int WIN32close(int fd)
|
|
|
|
{
|
|
|
|
if (!CloseHandle((HANDLE)fd)) {
|
|
|
|
errno = GetLastError();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int WIN32read(int fd, void *buf, unsigned int len)
|
|
|
|
{
|
|
|
|
DWORD actualLen;
|
|
|
|
|
|
|
|
if (!ReadFile((HANDLE)fd, buf, (DWORD)len, &actualLen, NULL)) {
|
|
|
|
errno = GetLastError();
|
|
|
|
if (errno == ERROR_BROKEN_PIPE)
|
|
|
|
return 0;
|
|
|
|
else
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return (int)actualLen;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int WIN32write(int fd, void *buf, unsigned int len)
|
|
|
|
{
|
|
|
|
DWORD actualLen;
|
|
|
|
|
|
|
|
if (!WriteFile((HANDLE)fd, buf, (DWORD)len, &actualLen, NULL)) {
|
|
|
|
errno = GetLastError();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return (int)actualLen;
|
|
|
|
}
|
|
|
|
|
|
|
|
static loff_t WIN32llseek(int fd, loff_t offset, int whence)
|
|
|
|
{
|
|
|
|
long lo, hi;
|
|
|
|
DWORD err;
|
|
|
|
|
2005-07-29 22:22:12 +00:00
|
|
|
lo = (long)(offset & 0xffffffff);
|
|
|
|
hi = (long)(offset >> 32);
|
2005-07-28 02:37:42 +00:00
|
|
|
lo = SetFilePointer((HANDLE)fd, lo, &hi, whence);
|
|
|
|
if (lo == 0xFFFFFFFF && (err = GetLastError()) != NO_ERROR) {
|
|
|
|
errno = err;
|
|
|
|
return -1;
|
|
|
|
}
|
2005-07-29 22:22:12 +00:00
|
|
|
return ((loff_t)hi << 32) | (__u32)lo;
|
2005-07-28 02:37:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int fsctl(int fd, int code)
|
|
|
|
{
|
|
|
|
DWORD ret;
|
|
|
|
if (!DeviceIoControl((HANDLE)fd, code, NULL, 0, NULL, 0, &ret, NULL)) {
|
|
|
|
errno = GetLastError();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|