Message-Id: <3.0.1.32.19971015174930.006b2ef0@yacker.xiotech.com> Date: Wed, 15 Oct 1997 17:49:30 -0500 To: djgpp-workers AT delorie DOT com From: Randy Maas Subject: 971009: FileSysExt's Rev D. p6 Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=====================_876973770==_" Precedence: bulk --=====================_876973770==_ Content-Type: text/plain; charset="us-ascii" Attached are the new .c files. Randy Maas randym AT acm DOT org --=====================_876973770==_ Content-Type: text/plain; charset="us-ascii" Content-Disposition: attachment; filename="_def_fs.c" /* Default FS extension 1997, Randall Maas */ #include /* */ int _def_fsext(__FSEXT_Fnumber Op, int* rv, va_list Args, void* State) {/* */ return _DOS_FS_Entry(Op, rv, Args, State); } --=====================_876973770==_ Content-Type: text/plain; charset="us-ascii" Content-Disposition: attachment; filename="_copy.c" /* 1997, Randall Maas. Created this, but based it the _open example, and used DJ Delorie's copy code from _link. Major portions are: Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */ #include #include # include # include # include # include # if defined(__DJGPP__) # include # else # include "fsext.h" # endif static int _copy_emu(__FSEXT_Fnumber Op, int* rv, va_list Args, void* State); static int inited = 0; int _copy(const char* src, const char* dest) {/* 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.) */ int rv; /* Check to see if we added our link emulator. If not, add it */ if (!inited) __FSEXT_Emu_add(_copy_emu); inited = 1; if (__FSEXT_call_open_handlers(__FSEXT_copy, &rv, &src)) return rv; return -1; } /* This is taken almost verbatim from libc v2.01 */ static int _copy_emu(__FSEXT_Fnumber Op, int* rv, va_list Args, void* State) { struct stat statbuf1, statbuf2; struct utimbuf times; char buf[16384]; int fd1, fd2, nbyte, status1, status2; const char *path1, *path2; /* Double check to be sure that we should be doing a copy */ if (Op != __FSEXT_copy) return 0; 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; } --=====================_876973770==_ 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. Update to date with 971009. Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */ #include #include #include #include /* */ int _DOS_alloc_fd() {/* */ __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; } --=====================_876973770==_ Content-Type: text/plain; charset="us-ascii" Content-Disposition: attachment; filename="_DOS_fsext.c" /* DOS File System Extension for DJGPP. Almost all the code is by DJ Delorie and by Morten Welinder, these are: 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. Brought in DOS specific calls and made them a file system extension */ #include #include #include #include #include #include #include #include #include #include #include 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); static int _DOS_dup2 (va_list); /* */ int _DOS_FS_Entry(Op, RV, Args, State) __FSEXT_Fnumber Op; int* RV; va_list Args; void* State; {/* */ 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; /* Duplicate the DOS file handles */ case __FSEXT_dup2: *RV = _DOS_dup2(Args); break; default: return 0; /* Emulation was not done. */ } return 1; } /* */ static int _DOS_open(va_list Args) { /* Up to date with 971009 */ __dpmi_regs r; int use_lfn = _USE_LFN; const char* filename = va_arg(Args, const char*); int oflag = va_arg(Args, int); if (filename == 0) { errno = EINVAL; return -1; /* Bug: should simply indicate not handled. */ } _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) { /* Up to date with _creat.c in 971009 */ __dpmi_regs r; unsigned use_lfn = _USE_LFN; const char* filename = va_arg(Args, const char*); int attrib = va_arg(Args, int); if (filename == 0) { errno = EINVAL; return -1; /* BUG: We don't handle this... */ } _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) { /* Up to date with 971009 */ __dpmi_regs r; int handle = va_arg(Args, int); /* The file descriptor. */ 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) { /* Up to date with 971009 */ __dpmi_regs r; int handle = va_arg(Args, int); off_t offset = va_arg(Args, off_t); int 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) { /* Up to date with 971009 */ size_t j, i; int nput; unsigned long tbsize; __dpmi_regs r; int handle = va_arg(Args, int); const void* buffer = va_arg(Args, void*); size_t 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) { /* Up to date with 971009 */ size_t j, k; int ngot; unsigned long tbsize; __dpmi_regs r; int handle = va_arg(Args, int); void* buffer = va_arg(Args, void*); size_t 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) { /* Up to date with 971009 */ __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; } static int _DOS_dup2(va_list Args) { /* Up to date with 971009 */ int fd = va_arg(Args, int); int newfd = va_arg(Args, int); __dpmi_regs r; __file_handle_set(newfd, __file_handle_modes[fd] ^ (O_BINARY|O_TEXT)); r.h.ah = 0x46; r.x.bx = fd; r.x.cx = newfd; __dpmi_int(0x21, &r); if (r.x.flags & 1) { errno = __doserr_to_errno(r.x.ax); return -1; } setmode(newfd, __file_handle_modes[fd]); return newfd; } /* */ --=====================_876973770==_ 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 /* The test is her for using this code on a couple of non DJGPP platforms as well */ #if defined(__djgpp__) # include # else # include "fsext.h" #endif #include /* */ int __FSEXT_Call(__FSEXT_Fnumber Op, int Handle, va_list Args) {/* */ __FSEXT_Function *func; void* state; int rv, Done = 0; if (__FSEXT_get_handler(Handle, &func, &state) && func) { /* Try to call the function. */ Done = func(Op, &rv, Args, state); } 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 */ Done = _def_fsext(Op, &rv, Args, NULL); } if (Done) 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; } errno = EINVAL; return -1; } --=====================_876973770==_ 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 /* */ #include int _nop(int handle) {/* */ return __FSEXT_Call(__FSEXT_nop, handle, &handle); } --=====================_876973770==_ Content-Type: text/plain; charset="us-ascii" Content-Disposition: attachment; filename="_ipc_ext.c" /* IPC Pipe File System Extension 1997, Randall Maas */ #include "_ipc.h" static int _ipc_close(bd_pipe*, va_list); static void _ipc_lseek(bd_pipe*, va_list); static int _ipc_pipe_ready(bd_pipe*); static void _tranarea_skip(int FD, off_t Ofs, size_t Dist); static ssize_t _tranarea_read(int FD, void* Buffer, size_t Size, off_t Ofs); static int _tranarea_read_ready(int FD, off_t Ofs); static ssize_t _tranarea_write(int FD, void* Buffer, size_t Size, off_t Ofs); static int _tranarea_write_ready(int FD, off_t Ofs); /* This is the actual extension called */ int _ipc_ext (Op, RV, Args, State) __FSEXT_Fnumber Op; int* RV; va_list Args; void* State; { bd_pipe* BDPtr = State; switch (Op) { case __FSEXT_nop: /* Gives the other end a chance to work the pipe */ *RV = 1; __dpmi_yield(); return 1; break; case __FSEXT_close: /* Close one instance of the pipe */ if (!BDPtr) return 0; *RV = _ipc_close(BDPtr, Args); return 1; break; case __FSEXT_lseek: if (!BDPtr) return 0; _ipc_lseek(BDPtr, Args); *RV = 0; /* Our position is always at the beginning. */ return 1; break; case __FSEXT_dup2: /* This dup2's the IO handle through a cheat. We increment our reference count, and then claim we didn't handle the operation. The emulation portion will handle this for us. */ if (BDPtr) BDPtr->RefCount++; break; case __FSEXT_read: /* We only read if the mode is proper */ if ((BDPtr->Mode & O_RDWR) == O_RDWR || (BDPtr->Mode & O_WRONLY) != O_WRONLY) { int FD = va_arg(Args, int); void* Buffer = va_arg(Args, void*); size_t Size = va_arg(Args, size_t); /* Check to see if the flag and index area are locked */ if (IPC_Use_lock && !lock(BDPtr->Sink.FD, BDPtr->Sink.Ofs+2, 2)) { *RV = 0; /* Read failed */ return 1; } *RV = _tranarea_read(BDPtr->Sink.FD, Buffer, Size, BDPtr->Sink.Ofs); /* Unlock the flag and index */ if (IPC_Use_lock) unlock(BDPtr->Sink.FD, BDPtr->Sink.Ofs+2, 2); return 1; } return 0; break; case __FSEXT_write: /* We only write if the mode is proper */ if ((BDPtr->Mode & O_RDWR) == O_RDWR || (BDPtr->Mode & O_WRONLY) == O_WRONLY) { int FD = va_arg(Args, int); void* Buffer = va_arg(Args, void*); size_t Size = va_arg(Args, size_t); /* Check to see if the flag and index area are locked */ if (IPC_Use_lock && !lock(BDPtr->Source.FD, BDPtr->Source.Ofs+4, 2)) { *RV = 0; /* Write failed */ return 1; } *RV = _tranarea_write(BDPtr->Source.FD, Buffer, Size, BDPtr->Source.Ofs); /* Unlock the flag and index */ if (IPC_Use_lock) unlock(BDPtr->Source.FD, BDPtr->Source.Ofs+4, 2); return 1; break; } case __FSEXT_ready: /* Check to see if the flag and index area are locked */ *RV = _ipc_pipe_ready(BDPtr); return 1; break; default: break; } return 0; } // --- IPC Pipe Procedures -------------------------------------------------- static int _ipc_close(BDPtr, Args) bd_pipe* BDPtr; va_list Args; { /* This closes one end of the pipe. */ int fd = va_arg(Args, int); /* Get out file descriptor */ /* First decrement the Reference Count */ if (BDPtr->RefCount) BDPtr->RefCount--; /* Only purge our structure if neccessary */ if (!BDPtr->RefCount) { /* Close the sink. Note: should I hold out if it is in the standard IO stream? */ if (BDPtr->Sink.FD >= 0) close(BDPtr->Sink.FD); /* Close the sink. */ /* Close the source. */ if (BDPtr->Source.FD != BDPtr->Sink.FD && BDPtr->Source.FD >= 0) close(BDPtr->Source.FD); free(BDPtr); } /* Now double clutch to close the OS file handle */ __FSEXT_set_function(fd, NULL, NULL); /* No longer an emulated call */ return close(fd); } static void _ipc_lseek(BDPtr, Args) bd_pipe* BDPtr; va_list Args; { /* This emulates lseek, but only on read pipes. */ int FD = va_arg(Args, int); /* We completely ignore it */ off_t Ofs = va_arg(Args, off_t); int Mode = va_arg(Args, int); if ((BDPtr->Mode & O_WRONLY) == O_WRONLY) return; if (Mode == SEEK_CUR || Mode == SEEK_END) { /* Bump the tail up. */ _tranarea_skip(BDPtr->Sink.FD, BDPtr->Sink.Ofs, Mode==SEEK_END?250:Ofs); } } static int _ipc_pipe_ready(BDPtr) bd_pipe* BDPtr; { /* The checks to see how ready the transfer area is for any work. */ int Ret = 0; /* Check the read end of the pipe */ if ((BDPtr->Mode & O_RDWR) == O_RDWR || (BDPtr->Mode & O_RDONLY) == O_RDONLY) { /* We need to check the status of the read end of the pipe. */ if (!IPC_Use_lock || lock(BDPtr->Sink.FD, BDPtr->Sink.Ofs+2, 2)) { if (_tranarea_read_ready(BDPtr->Sink.FD, BDPtr->Sink.Ofs)) Ret |= __FSEXT_ready_read; /* Unlock the flag and index */ if (IPC_Use_lock) unlock(BDPtr->Sink.FD, BDPtr->Sink.Ofs+2, 2); } } /* Check the write end of the pipe */ if ((BDPtr->Mode & O_RDWR) == O_RDWR || (BDPtr->Mode & O_WRONLY) == O_WRONLY) { /* Check to see if the flag and index area are locked */ if (!IPC_Use_lock || lock(BDPtr->Source.FD, BDPtr->Source.Ofs+4, 2)) { if (_tranarea_write_ready(BDPtr->Source.FD, BDPtr->Source.Ofs)) Ret |= __FSEXT_ready_write; /* Unlock the flag and index */ if (IPC_Use_lock) unlock(BDPtr->Source.FD, BDPtr->Source.Ofs+4, 2); } } return Ret; } // --- Transfer Area Read procedures ---------------------------------------- static int _tranarea_read_ready(int FD, off_t Ofs) { /* This does not lock */ unsigned char Area[4]; /* read in the transfer area header */ lseek(FD, Ofs+2, SEEK_SET); read(FD, Area, 4); /* Check for read lock or no data to read */ return (Area[0]&0x80 || /* The read lock flag is raised? */ Area[3] == Area[3]) /* Tail == Head? */ ? 0 :1; } static void _tranarea_skip(int FD, off_t Ofs, size_t Dist) { /* This does not lock */ unsigned char Area[4]; if (Ofs <= 0) return; /* Bogus dude */ /* read in the transfer area header */ lseek(FD, Ofs+2, SEEK_SET); read(FD, Area, 4); /* Check for read lock or no data to read */ if (Area[0]&0x80 || /* The read lock flag is raised? */ Area[1] == Area[3]) /* Tail == Head? */ return; if (Area[1] < Area[3]) { if (Area[3]-Area[1] > Dist) Area[1] = Area[3]; /* End */ else Area[1] += Dist; } else if (250-Area[1]+Area[1] >= Dist) Area[1] = (Area[1]+Dist)%250; else Area[1] = Area[3]; /* End */ /* Update the pointer */ lseek(FD, Ofs+3, SEEK_SET); write(FD, Area+1, 1); } static ssize_t _tranarea_read(int FD, void* Buffer, size_t Size, off_t Ofs) { /* This does not lock */ unsigned char Area[256], RSize; unsigned char* B = Buffer; unsigned I; /* read in the whole transfer area */ lseek(FD, Ofs, SEEK_SET); read(FD, Area, 256); /* Check for read lock or no data to read */ if (Area[2]&0x80 || /* The read lock flag is raised? */ Area[3] == Area[5]) /* Tail == Head? */ return 0; /* Raise the read lock flag */ Area[2] |= 0x80; lseek(FD, Ofs+2, SEEK_SET); write(FD, Area+2, 1); /* Copy into our buffer the data; more efficient than memcpy */ for (I = Area[3], RSize = 0; RSize < Size && I != Area[5]; I = (I+1)%250, RSize++) {B[RSize] = Area[6+I];} /* Lower the read lock flag and update the tail index*/ Area[2] &= 0x7f; Area[3] = I; lseek(FD, Ofs+2, SEEK_SET); write(FD, Area+2, 2); return RSize; } // --- Transfer Area Write procedures --------------------------------------- static int _tranarea_write_ready(int FD, off_t Ofs) { /* read in the transfer area header */ unsigned char Area[4]; lseek(FD, Ofs+2, SEEK_SET); read(FD, Area, 4); /* Check for read lock or no data to read */ if (Area[2]&0x80 || /* The write lock flag is raised? */ (Area[1] == (Area[3]+1)%250)) /* Tail == Head? */ return 1; return 0; } static ssize_t _tranarea_write(int FD, void* Buffer, size_t Size, off_t Ofs) { /* This is designed to make the minimum of read/write calls */ /* This does not lock */ unsigned char Area[256], TSize, RSize, REnd =0; /* read in the whole transfer area */ lseek(FD, Ofs, SEEK_SET); read(FD, Area, 256); /* Check for read lock or no data to read */ if (Area[4]&0x80u || /* The write lock flag is raised? */ Area[3] == (Area[5]+1)%250) /* Tail == Head? */ { return 0; } /* Raise the write lock flag */ Area[4] |= 0x80; lseek(FD, Ofs+4, SEEK_SET); write(FD, Area+4, 1) ; /* Write out part till end of buffer */ RSize = 0; if (Area[5] >= Area[3]) { TSize = Min(250-Area[5], Size-RSize); if (TSize) { /* Write the data to part of the area buffer */ memmove(Area+Area[5]+6, Buffer+RSize, TSize); RSize += TSize; REnd = Max(REnd, Area[5]+6+TSize-4); Area[5] = (Area[5]+TSize) % 250; } } /* Now write out the part at the beginning of the buffer */ if (RSize < Size) { TSize = Min(Area[3]-Area[5], Size-RSize); if (TSize) { /* Write the data to part of the area buffer */ memmove(Area+Area[5]+6, Buffer+RSize, TSize); RSize += TSize; REnd = Max(REnd, Area[5]+6+TSize -4); Area[5] = (Area[5]+TSize) %250; } } /* Clear the write lock */ Area[4] &= 0x7f; /* And update the buffer as neccessary */ lseek(FD, Ofs+4, SEEK_SET); write(FD, Area+4, Max(2, REnd)); return RSize; } --=====================_876973770==_ Content-Type: text/plain; charset="us-ascii" Content-Disposition: attachment; filename="_ipcpipe.c" /* IPC low-level pipe emulator 1997 Randall Maas */ #include "_ipc.h" extern int _ipc_ext (__FSEXT_Fnumber, int*, va_list, void*); /* */ ssize_t _ipc_pipe(int Transfer_FD, int filedes[2], int mode) {/*/* */ bd_pipe *BDPtr1 = malloc(sizeof(bd_pipe)), *BDPtr2 = malloc(sizeof(bd_pipe)); /* Store the file descriptor and location. */ BDPtr1->Sink.FD = Transfer_FD; BDPtr1->Source.FD = Transfer_FD; BDPtr1->Sink.Ofs = tell(Transfer_FD); BDPtr1->Source.Ofs = BDPtr1->Sink.Ofs+256; BDPtr1->RefCount = 1; BDPtr1->Mode = mode; filedes[0] = __FSEXT_alloc_fd(_ipc_ext, BDPtr1); /* Clear out the transfer area */ _ipc_clear_header(Transfer_FD, BDPtr1->Sink.Ofs); _ipc_clear_header(Transfer_FD, BDPtr1->Source.Ofs); /* We dup it so we can close one end of the pipe */ BDPtr2->Sink.FD = Transfer_FD; /* Dup later? */ BDPtr2->Source.FD = BDPtr2->Sink.FD; BDPtr2->Sink.Ofs = BDPtr1->Source.Ofs; /* Link source and sink */ BDPtr2->Source.Ofs = BDPtr1->Sink.Ofs; /* Link sink and source */ BDPtr2->RefCount = 1; BDPtr2->Mode = mode; filedes[1] = __FSEXT_alloc_fd(_ipc_ext, BDPtr2); return 256*2; } #if defined(TEST) #include main() { int fd= fileno(tmpfile()); int fildes[2]; char tmp[100]; _ipc_pipe(fd, fildes, O_RDWR); dup2(fildes[0], 0); // Set the stdin dup2(fildes[1], 1); // Set the stdout puts("hello\n"); fflush(stdout); tmp[0]=0; fgets(tmp, 99, stdin); fprintf(stderr, "%s", tmp); } #endif --=====================_876973770==_ Content-Type: text/plain; charset="us-ascii" Content-Disposition: attachment; filename="_link.c" /* 1997, Randall Maas. Created this, but based it the _open example, so portions are: Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */ #include #include # if defined(__DJGPP__) # include # else # include "fsext.h" # endif static int _link_emu(__FSEXT_Fnumber Op, int* rv, va_list Args, void* State); static int inited = 0; int _link(const char* src, const char* dest) { int rv; /* Check to see if we added our link emulator. If not, add it */ if (!inited) __FSEXT_Emu_add(_link_emu); inited = 1; if (__FSEXT_call_open_handlers(__FSEXT_link, &rv, &src)) return rv; return -1; } static int _link_emu(__FSEXT_Fnumber Op, int* rv, va_list Args, void* State) { /* This emulates a link by calling copy. */ const char *path1, *path2; if (Op != __FSEXT_link) return 0; /* Get the two link arguments */ 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. */ *rv = _copy(path1, path2); /* We only "emulated" the link command if the copy succeeded! */ return *rv == 0 ? 1 :0; } --=====================_876973770==_ 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 #include off_t _lseek(int handle, off_t offset, int whence) { return __FSEXT_Call(__FSEXT_lseek, handle, &handle); } --=====================_876973770==_ Content-Type: text/plain; charset="us-ascii" Content-Disposition: attachment; filename="_pipe.c" /* A _pipe implementation via _ipc_pipe 1997, Randall Maas Pipe perhaps should be a file system extension. There are two or three obvious extensions that may benefit from this: serial ports parallel ports tcp streams There isn't any obvious call for these being opened through the pipe call yet, however. */ # include # include # include # include /* We are going to use a single file for all of the IPC pipes, reducing some overhead. */ static _ipc_fd = -1; /* Grounded until we get a _pipe call */ static off_t _ipc_Ofs = 0; void _pipe(int filedes[2]) { ssize_t Pipe_Size = 0; /* First we need to make a ipc file section */ if (_ipc_fd < 0) { char buf[L_tmpnam]; /* Note for future: make it possible (?) to use a RAM disk for internal pipes. */ tmpname(buf); /* Get a temporary file name */ /* open the temporary file for reading and writing */ _ipc_fd = creat(buf, S_IRUSR|S_IWUSR); _ipc_Ofs = 0; } lseek(_ipc_fd, _ipc_Ofs, SEEK_SET); /* Make the _ipc_pipe */ Pipe_Size = _ipc_pipe(_ipc_fd, filedes, O_RDWR); /* Increment the offset of the next area in the file to use */ if (Pipe_Size > 0) _ipc_Ofs += Pipe_Size; } #if defined(TEST) main() { int fildes[2]; char tmp[100]; _pipe(fildes); dup2(fildes[0], 0); // Set the stdin dup2(fildes[1], 1); // Set the stdout puts("hello\n"); fflush(stdout); tmp[0]=0; fgets(tmp, 99, stdin); fprintf(stderr, "%s", tmp); } #endif --=====================_876973770==_ Content-Type: text/plain; charset="us-ascii" Content-Disposition: attachment; filename="_unlink.c" /* 1997, Randall Maas. Created this, but based it the _open example, so portions are: Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */ #include #include # if defined(__DJGPP__) # include # else # include "fsext.h" # endif /* */ int _unlink(const char* src) {/* */ int rv; if (__FSEXT_call_open_handlers(__FSEXT_unlink, &rv, &src)) return rv; else if (__FSEXT_Emu(__FSEXT_unlink, &rv, &src, NULL)) return rv; errno = EINVAL; /* The file was not copied */ return -1; } --=====================_876973770==_ 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 Emulates functions not implemented by some FS extensions. Some portability to non-DJGPP environments added. */ # if defined(__DJGPP__) # include # else # include "fsext.h" # endif # include # include static __FSEXT_Function** Emus = NULL; static unsigned NEmus = 0; /* */ void __FSEXT_Emu_add(__FSEXT_Function* Func) {/* */ if (!Func) return; /* Catch a bogus function being added. */ Emus = realloc(Emus, sizeof(__FSEXT_Function*)*(NEmus+1)); Emus[NEmus] = Func; } /* */ int __FSEXT_Emu(__FSEXT_Fnumber Op, int* rv, va_list Args, void* State) {/* Note: future version should explore the possibility of employing a state subcomponent */ unsigned I; if (!NEmus || !Emus) return 0; for (I = NEmus; I; I--) if ((Emus[I-1])(Op, rv, Args, State)) return 1; return 0; } --=====================_876973770==_ Content-Type: text/plain; charset="us-ascii" Content-Disposition: attachment; filename="ipccom.c" /* IPC Common routines 1997, Randall Maas */ #include #include #include #include int IPC_Use_lock = 0; void _ipc_clear_header(int fd, off_t Ofs) { /* This nukes the header of the file. It does not affect the current position pointer*/ unsigned char Tmp[6] = {0,0,0,0,0,0}; off_t Here = tell(fd); lseek(fd, Ofs, SEEK_SET); write(fd, Tmp, sizeof(Tmp)); lseek(fd, Here, SEEK_SET); } --=====================_876973770==_ Content-Type: text/plain; charset="us-ascii" --=====================_876973770==_--