Mail Archives: djgpp-workers/1997/09/23/16:03:00
--=====================_875062889==_
Content-Type: text/plain; charset="us-ascii"
Attached are the sources for the "new" files. Mostly _DOS*.c and FS_EMU.c
is merged from the libc v2.01 routines. The _DOS*.c provides a single
replaceable fsext for porting to non-DOS environments. FS_EMU.c provides
functionality for those FSEXT that don't emulate every function and don't
need to (eg, link, copy, etc). _io_api provides _nop(), _def_fs.c is
what redirects everything automagically to the DOS fsext.
Heres to hoping I got it right this time. If I didn't, mail me. 8-)
Randy Maas
randym AT acm DOT org
--=====================_875062889==_
Content-Type: text/plain; charset="us-ascii"
Content-Disposition: attachment; filename="_def_fs.c"
/*
Default FS extension
1997, Randall Maas
*/
#include <sys/fsext.h>
/*
@txh
@node _def_fsext, file system
@syntax
@example
*/
int _def_fsext(__FSEXT_Fnumber Op, int* rv, va_list Args, void* State)
/* @end example */
{
/*
@subheading Description
This is the lowest level file system extension. By default,
@code{_def_fsext} calls MSDOS (@pxref{_DOS_FS_Entry}). By providing
your own @code{_def_fsext} subroutine, the basic file system services
can be changed. For instance, if you were trying to implement a win32
based system (and didn't want MSDOS in the way), you would want to
provide a dummy @code{_def_fsext} routine that calls your win32
interface.
@end txh
*/
return _DOS_FS_Entry(Op, rv, Args, State);
}
--=====================_875062889==_
Content-Type: text/plain; charset="us-ascii"
Content-Disposition: attachment; filename="_DOS_fd.c"
/*
1997, Randall Maas -- maked _DOS_alloc_fd separate from __FSEXT_alloc_fd
so that it can be overridden.
Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details
*/
#include <dpmi.h>
#include <go32.h>
#include <libc/dosio.h>
#include <errno.h>
/*
@txh
@node _DOS_alloc_fd, dos
@subheading Syntax
@example
*/
int _DOS_alloc_fd()
/*@end example*/
{
/*
@subheading Description
This function opens DOS's @samp{NUL} device, so as to allocate a
handle that DOS won't then reuse. It also assigns the handler
function for that descriptor.
@subheading Return Value
Returns the handle, or -1 on error
@end txh
*/
__dpmi_regs r;
_put_path("nul");
r.x.ax = 0x3d82; /* open, no inherit, read/write */
r.x.dx = __tb_offset;
r.x.ds = __tb_segment;
__dpmi_int(0x21, &r);
if (r.x.flags & 1)
{
errno = __doserr_to_errno(r.x.ax);
return -1;
}
return r.x.ax;
}
--=====================_875062889==_
Content-Type: text/plain; charset="us-ascii"
Content-Disposition: attachment; filename="_DOS_fsext.c"
/*
DOS File System Extension for DJGPP.
Copyright 1997 Randall Maas.
1997, Randall Maas remove DOS specific code and inlined documentation.
Brought in DOS specific calls -- the code for these were written by
DJ Delorie and by Morten Welinder, these
Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details
Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details
Copyright 1995 by Morten Welinder
This file maybe freely distributed and modified as long as the
copyright notice remains.
1997, Randall Maas: Split _close into _close and _DOS_close;
Renamed to _DOS_remove.
inlined the documentation.
*/
#include <stdio.h>
#include <libc/stubs.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <go32.h>
#include <dpmi.h>
#include <libc/dosio.h>
#include <fsext.h>
#include <unistd.h>
#include <io.h>
static int _DOS_open (va_list);
static int _DOS_create (va_list);
static int _DOS_close (va_list);
static int _DOS_read (va_list);
static int _DOS_write (va_list);
static int _DOS_ready (va_list);
static int _DOS_seek (va_list);
static int _DOS_remove (va_list);
/*
@txh
@node _DOS_FS_Entry, dos
@subheading Syntax
@example
*/
int _DOS_FS_Entry(Op, RV, Args, State)
__FSEXT_Fnumber Op; /*// Operation to perform. */
int* RV; /*// Return value of the operation. */
va_list Args; /*// Arguments to the operation. */
void* State; /*// Ignored */
/* @end example */
{
/*
@subheading Description
This provides a common entry point for DOS file system functions.
(see @ref{File System Extensions}).
@end txh
*/
if (Op == __FSEXT_nop)
{
/* No operation. */
*RV = 0;
return 1;
}
switch(Op)
{
/* Check the status DOS based file. */
case __FSEXT_ready: *RV = _DOS_ready(Args); break;
/* Read from the DOS based file. */
case __FSEXT_read: *RV = _DOS_read(Args); break;
/* Write to the DOS based file. */
case __FSEXT_write: *RV = _DOS_write(Args); break;
/* Do a seek with the DOS file */
case __FSEXT_lseek: *RV = _DOS_seek(Args); break;
/* Open a DOS based file */
case __FSEXT_open: *RV = _DOS_open(Args); break;
/* Create a DOS based file */
case __FSEXT_creat: *RV = _DOS_create(Args); break;
/* Close the DOS file. */
case __FSEXT_close: *RV = _DOS_close(Args); break;
/* Remove the DOS file. */
case __FSEXT_unlink: *RV =_DOS_remove(Args); break;
default: return 0; /* Emulation was not done. */
}
return 1;
}
/*
@txh
The FS_Ext functions are implemented as follows:
@table @code
@end txh
*/
static int _DOS_open(va_list Args)
{
/*
@txh
@item __FSEXT_open
This is a direct connection to the MS-DOS open function call, int
0x21, %ah = 0x3d. The file is set to binary mode.
@end txh
*/
__dpmi_regs r;
int use_lfn = _USE_LFN;
const char* filename;
int oflag;
filename = va_arg(Args, const char*);
if (filename == 0)
{
errno = EINVAL;
return -1;
/* Bug: should simply indicate not handled. */
}
oflag = va_arg(Args, int);
_put_path(filename);
if(use_lfn) {
r.x.ax = 0x716c;
r.x.bx = oflag & 0xff;
r.x.dx = 1; /* Open existing file */
r.x.si = __tb_offset;
} else {
r.h.ah = 0x3d;
r.h.al = oflag;
r.x.dx = __tb_offset;
}
r.x.cx = 0;
r.x.ds = __tb_segment;
__dpmi_int(0x21, &r);
if(r.x.flags & 1)
{
errno = __doserr_to_errno(r.x.ax);
return -1;
}
__file_handle_set(r.x.ax, O_BINARY);
return r.x.ax;
}
static int _DOS_create (va_list Args)
{
/*
@txh
@item __FSEXT_creat
This is a direct connection to the MS-DOS creat function call, int
0x21, %ah = 0x3c. The file is set to binary mode.
@end txh
*/
__dpmi_regs r;
unsigned use_lfn = _USE_LFN;
const char* filename;
int attrib;
filename = va_arg(Args, const char*);
if (filename == 0)
{
errno = EINVAL;
return -1;
/* BUG: We don't handle this... */
}
attrib = va_arg(Args, int);
_put_path(filename);
if(use_lfn) {
r.x.ax = 0x716c;
r.x.bx = 0x0002; /* open r/w */
r.x.dx = 0x0012; /* Create, truncate if exists */
r.x.si = __tb_offset;
} else {
r.h.ah = 0x3c;
r.x.dx = __tb_offset;
}
r.x.cx = attrib;
r.x.ds = __tb_segment;
__dpmi_int(0x21, &r);
if(r.x.flags & 1)
{
errno = __doserr_to_errno(r.x.ax);
return -1;
}
__file_handle_set(r.x.ax, O_BINARY);
return r.x.ax;
}
static int _DOS_close(va_list Args)
{
/*
@txh
@item __FSEXT_close
This is a direct connection to the MS-DOS close function call, int
0x21, %ah = 0x3e. Returns zero if the file was closed, else nonzero.
@end txh
*/
__dpmi_regs r;
int handle; /* The file descriptor. */
handle = va_arg(Args, int);
r.h.ah = 0x3e;
r.x.bx = handle;
__dpmi_int(0x21, &r);
if (r.x.flags & 1)
{
errno = EBADF;
return -1;
}
return 0;
}
static int _DOS_seek(va_list Args)
{
/*
@txh
@item __FSEXT_seek
This is a direct connection to the MS-DOS lseek function call, int
0x21, %ah = 0x42. Returns -1 on error, the position within the file
otherwise.
@end txh
*/
__dpmi_regs r;
int handle, whence;
off_t offset;
handle = va_arg(Args, int);
offset = va_arg(Args, off_t);
whence = va_arg(Args, int);
r.h.ah = 0x42;
r.h.al = whence;
r.x.bx = handle;
r.x.cx = offset >> 16;
r.x.dx = offset & 0xffff;
__dpmi_int(0x21, &r);
if (r.x.flags & 1)
{
errno = __doserr_to_errno(r.x.ax);
return -1;
}
return (r.x.dx << 16) + r.x.ax;
}
static int _DOS_write(va_list Args)
{
/*
@txh
@item __FSEXT_write
This is a direct connection to the MS-DOS write function call, int
0x21, %ah = 0x40. No conversion is done on the data; it is written as
raw binary data.
@end txh
*/
size_t j, i;
int nput;
unsigned long tbsize;
__dpmi_regs r;
int handle;
const void* buffer;
size_t count;
handle = va_arg(Args, int);
buffer = va_arg(Args, void*);
count = va_arg(Args, size_t);
tbsize = _go32_info_block.size_of_transfer_buffer;
nput = 0;
do {
j = (count <= tbsize) ? count : tbsize;
if (j)
dosmemput(buffer, j, __tb);
r.x.ax = 0x4000;
r.x.bx = handle;
r.x.cx = j;
r.x.dx = __tb & 15;
r.x.ds = __tb / 16;
__dpmi_int(0x21, &r);
if (r.x.flags & 1)
{
errno = __doserr_to_errno(r.x.ax);
return -1;
}
i = r.x.ax;
count -= i;
buffer = (void *)((int)buffer + i);
nput += i;
} while(count && (i == j));
if (count && nput == 0)
{
errno = ENOSPC;
return -1;
}
return nput;
}
static int _DOS_read(va_list Args)
{
/*
@txh
@item __FSEXT_read
This is a direct connection to the MS-DOS read function call, int
0x21, %ah = 0x3f. No conversion is done on the data; it is read as
raw binary data.
@end txh
*/
size_t j, k;
int ngot;
unsigned long tbsize;
__dpmi_regs r;
int handle;
void* buffer;
size_t count;
handle = va_arg(Args, int);
buffer = va_arg(Args, void*);
count = va_arg(Args, size_t);
tbsize = _go32_info_block.size_of_transfer_buffer;
ngot = 0;
do {
j = (count <= tbsize) ? count : tbsize;
r.x.ax = 0x3f00;
r.x.bx = handle;
r.x.cx = j;
r.x.dx = __tb & 15;
r.x.ds = __tb / 16;
__dpmi_int(0x21, &r);
if(r.x.flags & 1)
{
errno = __doserr_to_errno(r.x.ax);
return -1;
}
count -= j;
k = r.x.ax;
ngot += k;
if (k)
dosmemget(__tb, k, buffer);
buffer = (void *)((int)buffer + k);
} while(count && j == k); /* if not == on DOS then no more */
return ngot;
}
/*
Most of this is credited to Morten Welinder
This is as close as we get, I think. For a file connected to a printer
we could of course go ask the BIOS, but this should be enough. */
/* The Dos call 4407 always returns TRUE for disk files. So the
following really is meaningful for character devices only... */
inline static int _DOS_output_ready(int fd)
{
__dpmi_regs regs;
regs.x.ax = 0x4407;
regs.x.bx = fd;
__dpmi_int (0x21, ®s);
if (regs.x.flags & 1)
{
errno = __doserr_to_errno (regs.x.ax);
return -1;
}
else
return regs.h.al == 0xff;
}
inline static int _DOS_input_ready(int fd)
{
__dpmi_regs regs;
regs.x.ax = 0x4406;
regs.x.bx = fd;
__dpmi_int (0x21, ®s);
if (regs.x.flags & 1)
{
errno = __doserr_to_errno (regs.x.ax);
return -1;
}
else
return regs.h.al == 0xff;
}
static int _DOS_ready(va_list Args)
{
int Ret = 0, X, fd;
fd = va_arg(Args, int);
X = _DOS_input_ready(fd);
Ret |= (X < 0) ? __FSEXT_ready_error : (X) ? __FSEXT_ready_read: 0;
X = _DOS_output_ready(fd);
Ret |= (X < 0) ? __FSEXT_ready_error : (X) ? __FSEXT_ready_write: 0;
return Ret;
}
static int _DOS_remove(va_list Args)
{
__dpmi_regs r;
unsigned attr;
int directory_p;
int use_lfn = _USE_LFN;
const char *fn = va_arg(Args, const char*);
/* Get the file attribute byte. */
attr = _chmod(fn, 0);
directory_p = attr & 0x10;
/* Now, make the file writable. We must reset Vol, Dir, Sys and Hidden bits
in addition to the Read-Only bit, or else 214301 will fail. */
_chmod(fn, 1, attr & 0xffe0);
/* Now delete it. Note, _chmod leaves dir name in tranfer buffer. */
if (directory_p)
r.h.ah = 0x3a; /* DOS Remove Directory function */
else
r.h.ah = 0x41; /* DOS Remove File function */
if(use_lfn) {
r.h.al = r.h.ah;
r.h.ah = 0x71;
r.x.si = 0; /* No Wildcards */
}
r.x.dx = __tb_offset;
r.x.ds = __tb_segment;
__dpmi_int(0x21, &r);
if(r.x.flags & 1)
{
/* We failed. Leave the things as we've found them. */
int e = __doserr_to_errno(r.x.ax);
_chmod(fn, 1, attr & 0xffe7);
errno = e;
return -1;
}
return 0;
}
/*
@txh
@end table
@end txh
*/
--=====================_875062889==_
Content-Type: text/plain; charset="us-ascii"
Content-Disposition: attachment; filename="_fs_call.c"
/*
File System Call.
1997 Randall Maas.
Portions Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details
*/
#include <stdio.h>
/* The test is her for using this code on a couple of non DJGPP platforms as well */
#if defined(__djgpp__)
# include <sys/fsext.h>
# else
# include "fsext.h"
#endif
#include <errno.h>
/*
@txh
@node __FSEXT_Call, file system
@subheading Syntax
@example
*/
int __FSEXT_Call(__FSEXT_Fnumber Op, int Handle, va_list Args)
/*//Op identifies which function is to be emulated.*/
/*//Handle is the handle to entity to worked on.*/
/*//Args represents the arguments passed to the original function */
/*@end example */
{
/*
@subheading Description
This procedure is meant to be called by functions require some form of
emulation. It calls the File System Extension associated with the
Handle. If the function is not emulated by this extension, it tries
a generic function emulator to carry out the operation.
@subheading Return Value
If it is unable to find a handler that corresponds to the handle, or
the handler did not carry out the operation, @code{_FS_Call} sets
@var{errno} to EINVAL and returns -1. Otherwise it returns the
value from the handler.
@end txh
*/
__FSEXT_Function *func;
void* state;
int rv;
if (__FSEXT_get_handler(Handle, &func, &state) && func)
{
/* Try to call the function. */
if (func(Op, &rv, Args, state))
return rv; /* The operation was carried out. */
else
{
/* The operation was not carried out. Let's see if we can emulate
the operation in some other way. We only do this if the
original File Handler does not implement operation.
*/
if (__FSEXT_Emu(Op, &rv, Args, NULL))
return rv;
}
}
else
{
/* The handle is not one defined in our FS extensions -- it may be
one not open internally (stdin, stdout, stderr, or one passed via
argument). We punt by letting the default extensions do it */
if (_def_fsext(Op, &rv, Args, NULL)) return rv;
}
errno = EINVAL;
return -1;
}
--=====================_875062889==_
Content-Type: text/plain; charset="us-ascii"
Content-Disposition: attachment; filename="_io_api.c"
/*
Forms the C Library basic IO procedures API.
1997, Randall Maas rewrote this calls to use __FSEXT_Call
*/
#include <fsext.h>
/*
@txh
@node _nop, file system
@subheading Syntax
@example
*/
#include <io.h>
int _nop(int handle)
/*@end example*/
{
/*
@subheading Description
This performs no operation on the IO device or file (referred to by
handle). It's primary purpose is to allow the handler time to mantain
internals of this entity. Usually this is connection maintenance in
the networking world.
@subheading Return Value
0 if everything is okay, or -1 on error.
@end txh
*/
return __FSEXT_Call(__FSEXT_nop, handle, &handle);
}
--=====================_875062889==_
Content-Type: text/plain; charset="us-ascii"
Content-Disposition: attachment; filename="_lseek.c"
/*
emulates _lseek
1997, Randall Maas rewrote this calls to use __FSEXT_Call
*/
#include <sys/fsext.h>
#include <unistd.h>
/*
@txh
@node _lseek, file system
@subheading Syntax
@example
*/
off_t _lseek(int handle, off_t offset, int whence)
/*@end example*/
{
/*
@subheading Description
This function seeks within the file associated with @var{handle}.
If the handle is associated with a file system extension, that
extension will be responsible for emulating the ``lseek''
functionality. Otherwise, MSDOS will be called.
@subheading Return Value
The number of bytes read, or -1 on error.
@end txh
*/
return __FSEXT_Call(__FSEXT_lseek, handle, &handle);
}
--=====================_875062889==_
Content-Type: text/plain; charset="us-ascii"
Content-Disposition: attachment; filename="pread.c"
/* Absolute IO read method.
Randall Maas
Emulates the UNIXish pread
This is useful for "files" on some storage medium.
BUG: Should set errno
*/
#include <io.h>
#include <sys/fsext.h>
/*
@txh
@node pread, io
@subheading Syntax
@example
*/
#include <unistd.h>
ssize_t pread (Handle, Buffer, Size, Ofs)
int Handle; /*// The IO handle to read from */
char* Buffer; /*// The buffer to read data into */
size_t Size; /*// The size of the buffer */
off_t Ofs; /*// The offset within the IO handle to read from */
/* @end example */
{
/*
@subheading Description
This reads from the specified position within the IO channel. It does
this in such a way that the current IO position is not affected.
@subheading Cavaets
Attempting to use @code{pread} on a IO channel that is incapable of
seeking will result in an error.
@subheading Returns
On success, the number of bytes actually read.
@end txh
*/
return __FSEXT_Call(__FSEXT_pread, Handle, &Handle);
}
--=====================_875062889==_
Content-Type: text/plain; charset="us-ascii"
Content-Disposition: attachment; filename="pwrite.c"
/* Absolute IO access methods.
Randall Maas
Emulates the UNIXish pread and pwrite
This is useful for "files" on some storage medium.
BUG: Should set errno
*/
#include <io.h>
#include <sys/fsext.h>
/*
@txh
@node pwrite, io
@subheading Syntax
@example
*/
#include <unistd.h>
ssize_t pwrite(Handle, Buffer, Size, Ofs)
int Handle; /*// The IO handle to write to */
const char* Buffer; /*// The buffer to write data into */
size_t Size; /*// The size of the buffer */
off_t Ofs; /*// The offset within the IO handle to write to */
/* @end example */
{
/*
@subheading Description
This writes to the specified position within the IO channel. It does
this in such a way that the current IO position is not affected.
@subheading Cavaets
Attempting to use @code{pwrite} on a IO channel that is incapable of
seeking will result in an error.
@subheading Returns
On success, the number of bytes actually read.
@end txh
*/
return __FSEXT_Call(__FSEXT_pwrite, Handle, &Handle);
}
--=====================_875062889==_
Content-Type: text/plain; charset="us-ascii"
Content-Disposition: attachment; filename="fsemu.c"
/*
File System emulation for unimplemented functions
1997- Randall Maas, created __FSEXT_Emu and moved some of the code from libc v2.01 to
this. Emulates functions not implemented by some FS extensions.
Some portability to non-DJGPP environments added.
Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details
*/
# if defined(__DJGPP__)
# include <libc/stubs.h>
# include <utime.h> /* For utime() */
# include <unistd.h> /* For read(), write(), etc. */
# include <sys/fsext.h>
# else
# include "fsext.h"
# include <stdio.h>
# include <io.h>
# include <sys/utime.h>
# endif
#include <sys/stat.h> /* For stat() */
#include <fcntl.h> /* For O_RDONLY, etc. */
#include <limits.h> /* For PATH_MAX */
#include <errno.h> /* For errno */
static int _Emu_create (va_list);
static int _Emu_link (va_list);
static int _Emu_copy (va_list);
static int _Emu_prw (__FSEXT_Fnumber, va_list);
/*
@txh
@node __FSEXT_Emu, file system
@subheading Syntax
@example
*/
int __FSEXT_Emu(__FSEXT_Fnumber Op, int* rv, va_list Args, void* State)
/* @end example */
{
/*
@subheading Description
This provides some a simple entry point to emulating File System
Extension functions. The emulation of these functions is based on
simpler functions usually provided by the File System Extensions.
@end txh
*/
switch(Op)
{
case __FSEXT_creat: *rv = _Emu_create (Args); break;
case __FSEXT_link: *rv = _Emu_link (Args); break;
case __FSEXT_copy: *rv = _Emu_copy (Args); break;
case __FSEXT_pread:
case __FSEXT_pwrite: *rv = _Emu_prw(Op, Args); break;
default: return 0; /* Not emulated. */
}
return 1;
}
/*
@txh
Currently the following functions are emulated:
@table @code
@end txh
*/
static int _Emu_create(va_list Args)
{
/*
@txh
@item __FSEXT_create
@code{creat} can be simulate easily by most @code{open} functions --
just open the file, but with settings to create (@code{O_CREAT}) if
it does not exist, and truncate (@code{O_TRUNC}) if it does exist.
(Note: this is a kludge.)
@end txh
*/
const char *path1;
int attrib;
path1 = va_arg(Args, const char*);
attrib = va_arg(Args, int);
return open(path1, O_TRUNC | O_CREAT, attrib);
}
static int _Emu_link(va_list Args)
{
/*
@txh
@item __FSEXT_link
For those systems that can't really do a link (such as MSDOS), we just
do a copy instead, which is as close as these systems get.
Alternatively, we could always fail and return -1. I think this is
slightly better.
*/
const char *path1, *path2;
path1 = va_arg(Args, const char*);
path2 = va_arg(Args, const char*);
/* We call _copy instead of emulating it here in the hopes that a File
System Extension will properly handle the copying. If not, it will be
reflected back, and we will emulate it below in __FSEXT_copy.
@end txh
*/
return _copy(path1, path2);
}
static int _Emu_copy(va_list Args)
{
/*
@txh
@item __FSEXT_copy
This emulates a file copy, using binary read and writes. Some
operating systems provide a copy function. Others, like DOS, do not.
(Why would an OS want to provide "copy" functionality? Consider
Novell's Netware. To copy a file one one network drive to another,
this routine will have the data sequentially sent down the network and
and then send the data right back. Acceptable for one file, but not
for a large number of files. If the OS handled it, it could send a
command to the Netware server and do the copy right there. This is
clearly more efficient, so it is common for network operating
systems -- and others -- to provide copy functions as part of their
file system API.)
@end txh
*/
struct stat statbuf1, statbuf2;
struct utimbuf times;
char buf[16384];
int fd1, fd2, nbyte, status1, status2;
const char *path1, *path2;
path1 = va_arg(Args, const char*);
path2 = va_arg(Args, const char*);
/* Fail if either path is null */
if (path1 == NULL || path2 == NULL)
{
errno = EFAULT;
return -1;
}
if (*path1 == '\0' || *path2 == '\0')
{
errno = ENOENT;
return -1;
}
/* Fail if path1 does not exist - stat() will set errno */
if (stat(path1, &statbuf1) < 0) return -1;
# if defined(S_ISREG)
/* Fail if path1 is not a regular file -- assume it is on platforms without S_ISREG concept*/
if (!S_ISREG(statbuf1.st_mode))
{
errno = EPERM;
return -1;
}
# endif
/* Fail if unable to open path1 - open() will set errno */
fd1 = open(path1, O_RDONLY | O_BINARY);
if (fd1 < 0) return -1;
/* Fail if unable to create path2 - open() will set errno */
fd2 = open(path2, O_WRONLY | O_BINARY | O_CREAT | O_EXCL, 0600);
if (fd2 < 0)
{
(void) close(fd1);
return -1;
}
/* Fail if path1 and path2 are on different devices */
if (fstat(fd2, &statbuf2) < 0) return -1;
if (statbuf1.st_dev != statbuf2.st_dev)
{
(void)close(fd1);
(void)close(fd2);
(void)unlink(path2);
errno = EXDEV;
return -1;
}
/* Copy path1 to path2 */
do
{
nbyte = read(fd1, buf, sizeof buf);
if (nbyte <= 0) break;
if (write(fd2, buf, nbyte) != nbyte) nbyte = -1;
}
while (nbyte > 0);
/* Fail if the copy failed or we can't clean up */
status1 = close(fd1);
status2 = close(fd2);
if (nbyte < 0 || status1 < 0 || status2 < 0)
{
(void) unlink(path2);
return -1;
}
/* Success! */
/* Set the mode to match the original, ignoring errors */
(void) chmod(path2, statbuf1.st_mode);
/* Set the file time to match the original, ignoring errors */
times.actime = statbuf1.st_atime;
times.modtime = statbuf1.st_mtime;
(void) utime(path2, ×);
return 0;
}
static int _Emu_prw(__FSEXT_Fnumber Op, va_list Args)
{
/*
@txh
@item __FSEXT_pread
@code{pread} is simulated by @code{lseek}'ing to the appopriate place
in the file, and read the data. Upon completion, it @code{lseek}'s
back to its previous position. This will fail if the file does not
support @code{lseek}.
@item __FSEXT_pwrite
@code{pread} is simulated by @code{lseek}'ing to the appopriate place
in the file, and writing the data. Upon completion, it @code{lseek}'s
back to its previous position. This will fail if the file does not
support @code{lseek}.
@end
*/
/* Parse the arguments */
int Handle= va_arg(Args, int);
char* Buffer= va_arg(Args, char*);
size_t Size = va_arg(Args, size_t);
off_t Ofs = va_arg(Args, off_t);
unsigned long Old = tell(Handle);
int Ret;
if (lseek(Handle, Ofs, SEEK_SET) != Ofs) return -1;
if (Op == __FSEXT_pread)
Ret = read(Handle, Buffer, Size);
else
Ret = write(Handle, Buffer, Size);
/* Return the IO to its previous position. */
if (lseek(Handle, Old, SEEK_SET) != Old) return -1;
return Ret;
}
/*
@txh
@end table
@subheading Notes
Unfortunately there is no easy way to add functionality to the emulator.
@subheading See Also
@pxref{File System Extensions}
*/
--=====================_875062889==_
Content-Type: text/plain; charset="us-ascii"
--=====================_875062889==_--
- Raw text -