/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Netscape Portable Runtime (NSPR). * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998-2000 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "primpl.h" #include #include #include #include /* ** Sleep this many milliseconds on each I/O operation ** to cause an intentional thread switch. */ #define _PR_MD_WIN16_DELAY 1 /* ** PR_MD_RegisterW16StdioCallbacks() -- Register Win16 stdio callback functions ** ** This public function call is unique to Win16. ** ... Sigh ... So much for platform independence. ** ** To get stdio to work from a command line executable, the stdio stream ** calls must be issued from the .EXE file; calling them from the .DLL ** sends the output to the bit-bucket. Therefore, the .EXE wanting to ** do stdio to the console window (must be built as a "quickwin" application) ** must have the wrapper functions defined in this module statically linked ** into the .EXE. ** ** There appears to be nothing you can do to get stdio to work from a ** Win16 GUI application. Oh Well! ** */ PRStdinRead _pr_md_read_stdin = 0; PRStdoutWrite _pr_md_write_stdout = 0; PRStderrWrite _pr_md_write_stderr = 0; PRStatus PR_MD_RegisterW16StdioCallbacks( PRStdinRead inReadf, PRStdoutWrite outWritef, PRStderrWrite errWritef ) { _pr_md_write_stdout = outWritef; _pr_md_write_stderr = errWritef; _pr_md_read_stdin = inReadf; return(PR_SUCCESS); } /* end PR_MD_RegisterW16StdioCallbacks() */ /* ** _PR_MD_OPEN() -- Open a file ** ** Returns: a fileHandle or -1 ** ** */ PRInt32 _PR_MD_OPEN(const char *name, PRIntn osflags, int mode) { PRInt32 file; int access = O_BINARY; int rights = 0; /* ** Map NSPR open flags to os open flags */ if (osflags & PR_RDONLY ) access |= O_RDONLY; if (osflags & PR_WRONLY ) access |= O_WRONLY; if (osflags & PR_RDWR ) access |= O_RDWR; if (osflags & PR_CREATE_FILE ) { access |= O_CREAT; rights |= S_IRWXU; } if (osflags & PR_TRUNCATE) access |= O_TRUNC; if (osflags & PR_APPEND) access |= O_APPEND; else access |= O_RDONLY; /* ** Open the file */ file = (PRInt32) sopen( name, access, SH_DENYNO, rights ); if ( -1 == (PRInt32)file ) { _PR_MD_MAP_OPEN_ERROR( errno ); } PR_Sleep( _PR_MD_WIN16_DELAY ); return file; } /* ** _PR_MD_READ() - Read something ** ** Returns: bytes read or -1 ** */ PRInt32 _PR_MD_READ(PRFileDesc *fd, void *buf, PRInt32 len) { PRInt32 rv; if ( (PR_GetDescType(fd) == PR_DESC_FILE) && ( fd->secret->md.osfd == PR_StandardInput ) && ( _pr_md_write_stdout )) { rv = (*_pr_md_read_stdin)( buf, len); } else { rv = read( fd->secret->md.osfd, buf, len ); } if ( rv == -1) { _PR_MD_MAP_READ_ERROR( errno ); } PR_Sleep( _PR_MD_WIN16_DELAY ); return rv; } /* ** _PR_MD_WRITE() - Write something ** ** Returns: bytes written or -1 ** ** Note: for file handles 1 and 2 (stdout and stderr) ** call the Win16 NSPR stdio callback functions, if they are ** registered. ** */ PRInt32 _PR_MD_WRITE(PRFileDesc *fd, const void *buf, PRInt32 len) { PRInt32 rv; if ( (PR_GetDescType(fd) == PR_DESC_FILE)) { switch ( fd->secret->md.osfd ) { case PR_StandardOutput : if ( _pr_md_write_stdout ) rv = (*_pr_md_write_stdout)( (void *)buf, len); else rv = len; /* fake success */ break; case PR_StandardError : if ( _pr_md_write_stderr ) rv = (*_pr_md_write_stderr)( (void *)buf, len); else rv = len; /* fake success */ break; default: rv = write( fd->secret->md.osfd, buf, len ); if ( rv == -1 ) { _PR_MD_MAP_WRITE_ERROR( errno ); } break; } } else { rv = write( fd->secret->md.osfd, buf, len ); if ( rv == -1 ) { _PR_MD_MAP_WRITE_ERROR( errno ); } } PR_Sleep( _PR_MD_WIN16_DELAY ); return rv; } /* --- end _PR_MD_WRITE() --- */ /* ** _PR_MD_LSEEK() - Seek to position in a file ** ** Note: 'whence' maps directly to PR_... ** ** Returns: ** */ PRInt32 _PR_MD_LSEEK(PRFileDesc *fd, PRInt32 offset, int whence) { PRInt32 rv; rv = lseek( fd->secret->md.osfd, offset, whence ); if ( rv == -1 ) { _PR_MD_MAP_LSEEK_ERROR( errno ); } PR_Sleep( _PR_MD_WIN16_DELAY ); return( rv ); } /* ** _PR_MD_LSEEK64() -- Seek to position in file, 64bit offset. ** */ PRInt64 _PR_MD_LSEEK64( PRFileDesc *fd, PRInt64 offset, int whence ) { PRInt64 test; PRInt32 rv, off; LL_SHR(test, offset, 32); if (!LL_IS_ZERO(test)) { PR_SetError(PR_FILE_TOO_BIG_ERROR, 0); LL_I2L(test, -1); return test; } LL_L2I(off, offset); rv = _PR_MD_LSEEK(fd, off, whence); LL_I2L(test, rv); return test; } /* end _PR_MD_LSEEK64() */ /* ** _PR_MD_FSYNC() - Flush file buffers. ** ** Returns: ** ** */ PRInt32 _PR_MD_FSYNC(PRFileDesc *fd) { PRInt32 rv; rv = (PRInt32) fsync( fd->secret->md.osfd ); if ( rv == -1 ) { _PR_MD_MAP_FSYNC_ERROR( errno ); } PR_Sleep( _PR_MD_WIN16_DELAY ); return(rv); } /* ** _PR_MD_CLOSE() - Close an open file handle ** ** Returns: ** ** */ PRInt32 _PR_MD_CLOSE_FILE(PRInt32 osfd) { PRInt32 rv; rv = (PRInt32) close( osfd ); if ( rv == -1 ) { _PR_MD_MAP_CLOSE_ERROR( errno ); } PR_Sleep( _PR_MD_WIN16_DELAY ); return(rv); } /* --- end _MD_CloseFile() --- */ /* --- DIR IO ------------------------------------------------------------ */ #define GetFileFromDIR(d) (d)->d_entry.cFileName /* ** FlipSlashes() - Make forward slashes ('/') into backslashes ** ** Returns: void ** ** */ void FlipSlashes(char *cp, int len) { while (--len >= 0) { if (cp[0] == '/') { cp[0] = PR_DIRECTORY_SEPARATOR; } cp++; } } /* ** _PR_MD_OPEN_DIR() - Open a Directory. ** ** Returns: ** ** */ PRStatus _PR_MD_OPEN_DIR(_MDDir *d, const char *name) { d->dir = opendir( name ); if ( d->dir == NULL ) { _PR_MD_MAP_OPENDIR_ERROR( errno ); return( PR_FAILURE ); } PR_Sleep( _PR_MD_WIN16_DELAY ); return( PR_SUCCESS ); } /* ** _PR_MD_READ_DIR() - read next directory entry ** ** */ char * _PR_MD_READ_DIR(_MDDir *d, PRIntn flags) { struct dirent *de; int err; for (;;) { de = readdir( d->dir ); if ( de == NULL ) { _PR_MD_MAP_READDIR_ERROR( errno); return 0; } if ((flags & PR_SKIP_DOT) && (de->d_name[0] == '.') && (de->d_name[1] == 0)) continue; if ((flags & PR_SKIP_DOT_DOT) && (de->d_name[0] == '.') && (de->d_name[1] == '.') && (de->d_name[2] == 0)) continue; break; } PR_Sleep( _PR_MD_WIN16_DELAY ); return de->d_name; } /* ** _PR_MD_CLOSE_DIR() - Close a directory. ** ** */ PRInt32 _PR_MD_CLOSE_DIR(_MDDir *d) { PRInt32 rv; if ( d->dir ) { rv = closedir( d->dir ); if (rv != 0) { _PR_MD_MAP_CLOSEDIR_ERROR( errno ); } } PR_Sleep( _PR_MD_WIN16_DELAY ); return rv; } /* ** _PR_MD_DELETE() - Delete a file. ** ** Returns: ** ** */ PRInt32 _PR_MD_DELETE(const char *name) { PRInt32 rv; rv = (PRInt32) remove( name ); if ( rv != 0 ) { _PR_MD_MAP_DELETE_ERROR( errno ); } PR_Sleep( _PR_MD_WIN16_DELAY ); return(rv); } /* ** _PR_MD_STAT() - Get file attributes by filename ** ** Returns: ** ** */ PRInt32 _PR_MD_STAT(const char *fn, struct stat *info) { PRInt32 rv; rv = _stat(fn, (struct _stat *)info); if ( rv == -1 ) { _PR_MD_MAP_STAT_ERROR( errno ); } PR_Sleep( _PR_MD_WIN16_DELAY ); return( rv ); } /* ** _PR_MD_GETFILEINFO() - Get file attributes by filename ** ** Returns: ** ** */ PRInt32 _PR_MD_GETFILEINFO(const char *fn, PRFileInfo *info) { struct _stat sb; PRInt32 rv; if ( (rv = _stat(fn, &sb)) == 0 ) { if (info) { if (S_IFREG & sb.st_mode) info->type = PR_FILE_FILE ; else if (S_IFDIR & sb.st_mode) info->type = PR_FILE_DIRECTORY; else info->type = PR_FILE_OTHER; info->size = sb.st_size; LL_I2L(info->modifyTime, sb.st_mtime); LL_I2L(info->creationTime, sb.st_ctime); } } else { _PR_MD_MAP_STAT_ERROR( errno ); } PR_Sleep( _PR_MD_WIN16_DELAY ); return rv; } PRInt32 _PR_MD_GETFILEINFO64(const char *fn, PRFileInfo64 *info) { PRFileInfo info32; PRInt32 rv = _PR_MD_GETFILEINFO(fn, &info32); if (0 == rv) { info->type = info32.type; info->modifyTime = info32.modifyTime; info->creationTime = info32.creationTime; LL_I2L(info->size, info32.size); } return(rv); } /* ** _PR_MD_GETOPENFILEINFO() - Get file attributes from an open file handle ** ** Returns: ** ** */ PRInt32 _PR_MD_GETOPENFILEINFO(const PRFileDesc *fd, PRFileInfo *info) { struct stat statBuf; PRInt32 rv = PR_SUCCESS; rv = fstat( fd->secret->md.osfd, &statBuf ); if ( rv == 0) { if (statBuf.st_mode & S_IFREG ) info->type = PR_FILE_FILE; else if ( statBuf.st_mode & S_IFDIR ) info->type = PR_FILE_DIRECTORY; else info->type = PR_FILE_OTHER; info->size = statBuf.st_size; LL_I2L(info->modifyTime, statBuf.st_mtime); LL_I2L(info->creationTime, statBuf.st_ctime); } else { _PR_MD_MAP_FSTAT_ERROR( errno ); } PR_Sleep( _PR_MD_WIN16_DELAY ); return(rv); } PRInt32 _PR_MD_GETOPENFILEINFO64(const PRFileDesc *fd, PRFileInfo64 *info) { PRFileInfo info32; PRInt32 rv = _PR_MD_GETOPENFILEINFO(fd, &info32); if (0 == rv) { info->type = info32.type; info->modifyTime = info32.modifyTime; info->creationTime = info32.creationTime; LL_I2L(info->size, info32.size); } return(rv); } /* ** _PR_MD_RENAME() - Rename a file ** ** Returns: ** ** */ PRInt32 _PR_MD_RENAME(const char *from, const char *to) { PRInt32 rv; rv = rename( from, to ); if ( rv == -1 ) { _PR_MD_MAP_RENAME_ERROR( errno ); } PR_Sleep( _PR_MD_WIN16_DELAY ); return( rv ); } /* ** _PR_MD_ACCESS() - Return file acesss attribute. ** ** Returns: ** ** */ PRInt32 _PR_MD_ACCESS(const char *name, PRIntn how) { PRInt32 rv; int mode = 0; if ( how & PR_ACCESS_WRITE_OK ) mode |= W_OK; if ( how & PR_ACCESS_READ_OK ) mode |= R_OK; rv = (PRInt32) access( name, mode ); if ( rv == -1 ) { _PR_MD_MAP_ACCESS_ERROR( errno ); } PR_Sleep( _PR_MD_WIN16_DELAY ); return(rv); } /* ** _PR_MD_MKDIR() - Make a directory ** ** Returns: ** ** */ PRInt32 _PR_MD_MKDIR(const char *name, PRIntn mode) { PRInt32 rv; rv = mkdir( name ); if ( rv == 0 ) { PR_Sleep( _PR_MD_WIN16_DELAY ); return PR_SUCCESS; } else { _PR_MD_MAP_MKDIR_ERROR( errno ); PR_Sleep( _PR_MD_WIN16_DELAY ); return PR_FAILURE; } } /* ** _PR_MD_RMDIR() - Delete a directory ** ** Returns: ** ** */ PRInt32 _PR_MD_RMDIR(const char *name) { PRInt32 rv; rv = (PRInt32) rmdir( name ); if ( rv == -1 ) { _PR_MD_MAP_RMDIR_ERROR( errno ); } PR_Sleep( _PR_MD_WIN16_DELAY ); return(rv); } /* ** _PR_MD_LOCKFILE() - Lock a file. ** ** The _locking() call locks relative to the current file pointer. ** This function is required to lock all of the file, so, ** 1. Seek to the beginning of the file, preserving the original position. ** 2. Lock the file, pausing if it is locked by someone else, and ** try again. ** 3. Re-position to the original position in the file. ** ** For unlocking, a similar protocol of positioning is required. ** */ PRStatus _PR_MD_LOCKFILE(PRInt32 f) { PRInt32 rv = PR_SUCCESS; /* What we return to our caller */ long seekOrigin; /* original position in file */ PRInt32 rc; /* what the system call returns to us */ /* ** Seek to beginning of file, saving original position. */ seekOrigin = lseek( f, 0l, SEEK_SET ); if ( rc == -1 ) { _PR_MD_MAP_LSEEK_ERROR( errno ); return( PR_FAILURE ); } /* ** Attempt to lock the file. ** If someone else has it, Sleep-a-while and try again. */ for( rc = -1; rc != 0; ) { rc = _locking( f, _LK_NBLCK , 0x7fffffff ); if ( rc == -1 ) { if ( errno == EACCES ) { PR_Sleep( 100 ); continue; } else { _PR_MD_MAP_LOCKF_ERROR( errno ); rv = PR_FAILURE; break; } } } /* end for() */ /* ** Now that the file is locked, re-position to ** the original file position. ** */ rc = lseek( f, seekOrigin, SEEK_SET ); if ( rc == -1 ) { _PR_MD_MAP_LSEEK_ERROR( errno ); rv = PR_FAILURE; } PR_Sleep( _PR_MD_WIN16_DELAY ); return PR_SUCCESS; } /* end _PR_MD_LOCKFILE() */ /* ** _PR_MD_TLOCKFILE() - Test and Lock file. ** ** The _locking() call locks relative to the current file pointer. ** This function is required to lock all of the file, so, ** 1. Seek to the beginning of the file, preserving the original position. ** 2. Attempt to Lock the file. ** If the file is locked by someone else, try NO MORE. ** 3. Re-position to the original position in the file. ** ** See the discussion of _PR_MD_LOCKFILE ** ** */ PRStatus _PR_MD_TLOCKFILE(PRInt32 f) { PRInt32 rv = PR_SUCCESS; /* What we return */ long seekOrigin; /* original position in file */ PRInt32 rc; /* return value from system call */ /* ** Seek to beginning of file, saving original position. */ seekOrigin = lseek( f, 0l, SEEK_SET ); if ( rc == -1 ) { _PR_MD_MAP_LSEEK_ERROR( errno ); return( PR_FAILURE ); } /* ** Attempt to lock the file. One ping; one ping only, Vasily. ** If someone else has it, Reposition and return failure. */ rc = _locking( f, _LK_NBLCK , 0x7fffffff ); if ( rc == -1 ) { if ( errno != EACCES ) _PR_MD_MAP_LOCKF_ERROR( errno ); rv = PR_FAILURE; } /* ** Now that the file is locked, maybe, re-position to ** the original file position. */ rc = lseek( f, seekOrigin, SEEK_SET ); if ( rc == -1 ) { _PR_MD_MAP_LSEEK_ERROR( errno ); rv = PR_FAILURE; } PR_Sleep( _PR_MD_WIN16_DELAY ); return rv; } /* end _PR_MD_TLOCKFILE() */ /* ** _PR_MD_UNLOCKFILE() - Unlock a file. ** ** See the discussion of _PR_MD_LOCKFILE ** */ PRStatus _PR_MD_UNLOCKFILE(PRInt32 f) { PRInt32 rv = PR_SUCCESS; /* What we return */ long seekOrigin; /* original position in file */ PRInt32 rc; /* return value from system call */ /* ** Seek to beginning of file, saving original position. */ seekOrigin = lseek( f, 0l, SEEK_SET ); if ( rc == -1 ) { _PR_MD_MAP_LSEEK_ERROR( errno ); return( PR_FAILURE ); } /* ** Unlock the file. */ rc = _locking( f, _LK_UNLCK , 0x7fffffff ); if ( rc == -1 ) { _PR_MD_MAP_LOCKF_ERROR( errno ); rv = PR_FAILURE; } /* ** Now that the file is unlocked, re-position to ** the original file position. */ rc = lseek( f, seekOrigin, SEEK_SET ); if ( rc == -1 ) { _PR_MD_MAP_LSEEK_ERROR( errno ); rv = PR_FAILURE; } PR_Sleep( _PR_MD_WIN16_DELAY ); return rv; } /* end _PR_MD_UNLOCKFILE() */ /* ** PR_Stat() -- Return status on a file ** ** This is a hack! ... See BugSplat: 98516 ** Basically, this hack takes a name and stat buffer as input. ** The input stat buffer is presumed to be a Microsoft stat buffer. ** The functions does a Watcom stat() then maps the result to ** the MS stat buffer. ... ** */ PR_IMPLEMENT(PRInt32) PR_Stat(const char *name, struct stat *buf) { PRInt32 rv; _MDMSStat *mssb = (_MDMSStat*) buf; /* this is Microsoft's stat buffer */ struct stat statBuf; /* this is Watcom's stat buffer */ /* First, get Watcom's idea of stat ** then reformat it into a Microsoft idea of stat */ rv = (PRInt32) _stat( name, &statBuf); if (rv == 0l ) { mssb->st_dev = statBuf.st_dev; mssb->st_ino = statBuf.st_ino; /* not used, really */ mssb->st_mode = statBuf.st_mode; mssb->st_nlink = 1; /* always 1, says MS */ mssb->st_uid = statBuf.st_uid; mssb->st_gid = statBuf.st_gid; mssb->st_rdev = statBuf.st_rdev; /* please Gh0d! Let these be the same */ mssb->st_size = statBuf.st_size; mssb->st_atime = statBuf.st_atime; mssb->st_mtime = statBuf.st_mtime; mssb->st_ctime = statBuf.st_ctime; } return rv; } /* end PR_Stat() */ /* $$ end W16io.c */