michael@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* OS2 IO module michael@0: * michael@0: * Assumes synchronous I/O. michael@0: * michael@0: */ michael@0: michael@0: #include "primpl.h" michael@0: #include "prio.h" michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: struct _MDLock _pr_ioq_lock; michael@0: michael@0: static PRBool isWSEB = PR_FALSE; /* whether we are using an OS/2 kernel that supports large files */ michael@0: michael@0: typedef APIRET (*DosOpenLType)(PSZ pszFileName, PHFILE pHf, PULONG pulAction, michael@0: LONGLONG cbFile, ULONG ulAttribute, michael@0: ULONG fsOpenFlags, ULONG fsOpenMode, michael@0: PEAOP2 peaop2); michael@0: michael@0: typedef APIRET (*DosSetFileLocksLType)(HFILE hFile, PFILELOCKL pflUnlock, michael@0: PFILELOCKL pflLock, ULONG timeout, michael@0: ULONG flags); michael@0: michael@0: typedef APIRET (*DosSetFilePtrLType)(HFILE hFile, LONGLONG ib, ULONG method, michael@0: PLONGLONG ibActual); michael@0: michael@0: DosOpenLType myDosOpenL; michael@0: DosSetFileLocksLType myDosSetFileLocksL; michael@0: DosSetFilePtrLType myDosSetFilePtrL; michael@0: michael@0: void michael@0: _PR_MD_INIT_IO() michael@0: { michael@0: APIRET rc; michael@0: HMODULE module; michael@0: michael@0: sock_init(); michael@0: michael@0: rc = DosLoadModule(NULL, 0, "DOSCALL1", &module); michael@0: if (rc != NO_ERROR) michael@0: { michael@0: return; michael@0: } michael@0: rc = DosQueryProcAddr(module, 981, NULL, (PFN*) &myDosOpenL); michael@0: if (rc != NO_ERROR) michael@0: { michael@0: return; michael@0: } michael@0: rc = DosQueryProcAddr(module, 986, NULL, (PFN*) &myDosSetFileLocksL); michael@0: if (rc != NO_ERROR) michael@0: { michael@0: return; michael@0: } michael@0: rc = DosQueryProcAddr(module, 988, NULL, (PFN*) &myDosSetFilePtrL); michael@0: if (rc != NO_ERROR) michael@0: { michael@0: return; michael@0: } michael@0: isWSEB = PR_TRUE; michael@0: } michael@0: michael@0: PRStatus michael@0: _PR_MD_WAIT(PRThread *thread, PRIntervalTime ticks) michael@0: { michael@0: PRInt32 rv; michael@0: ULONG count; michael@0: michael@0: PRUint32 msecs = (ticks == PR_INTERVAL_NO_TIMEOUT) ? michael@0: SEM_INDEFINITE_WAIT : PR_IntervalToMilliseconds(ticks); michael@0: rv = DosWaitEventSem(thread->md.blocked_sema, msecs); michael@0: DosResetEventSem(thread->md.blocked_sema, &count); michael@0: switch(rv) michael@0: { michael@0: case NO_ERROR: michael@0: return PR_SUCCESS; michael@0: break; michael@0: case ERROR_TIMEOUT: michael@0: _PR_THREAD_LOCK(thread); michael@0: if (thread->state == _PR_IO_WAIT) { michael@0: ; michael@0: } else { michael@0: if (thread->wait.cvar != NULL) { michael@0: thread->wait.cvar = NULL; michael@0: _PR_THREAD_UNLOCK(thread); michael@0: } else { michael@0: /* The CVAR was notified just as the timeout michael@0: * occurred. This led to us being notified twice. michael@0: * call SemRequest() to clear the semaphore. michael@0: */ michael@0: _PR_THREAD_UNLOCK(thread); michael@0: rv = DosWaitEventSem(thread->md.blocked_sema, 0); michael@0: DosResetEventSem(thread->md.blocked_sema, &count); michael@0: PR_ASSERT(rv == NO_ERROR); michael@0: } michael@0: } michael@0: return PR_SUCCESS; michael@0: break; michael@0: default: michael@0: break; michael@0: } michael@0: return PR_FAILURE; michael@0: } michael@0: PRStatus michael@0: _PR_MD_WAKEUP_WAITER(PRThread *thread) michael@0: { michael@0: if ( _PR_IS_NATIVE_THREAD(thread) ) michael@0: { michael@0: if (DosPostEventSem(thread->md.blocked_sema) != NO_ERROR) michael@0: return PR_FAILURE; michael@0: else michael@0: return PR_SUCCESS; michael@0: } michael@0: } michael@0: michael@0: michael@0: /* --- FILE IO ----------------------------------------------------------- */ michael@0: /* michael@0: * _PR_MD_OPEN() -- Open a file michael@0: * michael@0: * returns: a fileHandle michael@0: * michael@0: * The NSPR open flags (osflags) are translated into flags for OS/2 michael@0: * michael@0: * Mode seems to be passed in as a unix style file permissions argument michael@0: * as in 0666, in the case of opening the logFile. michael@0: * michael@0: */ michael@0: PRInt32 michael@0: _PR_MD_OPEN(const char *name, PRIntn osflags, int mode) michael@0: { michael@0: HFILE file; michael@0: PRInt32 access = OPEN_SHARE_DENYNONE; michael@0: PRInt32 flags = 0L; michael@0: APIRET rc = 0; michael@0: PRUword actionTaken; michael@0: michael@0: #ifdef MOZ_OS2_HIGH_MEMORY michael@0: /* michael@0: * All the pointer arguments (&file, &actionTaken and name) have to be in michael@0: * low memory for DosOpen to use them. michael@0: * The following moves name to low memory. michael@0: */ michael@0: if ((ULONG)name >= 0x20000000) michael@0: { michael@0: size_t len = strlen(name) + 1; michael@0: char *copy = (char *)alloca(len); michael@0: memcpy(copy, name, len); michael@0: name = copy; michael@0: } michael@0: #endif michael@0: michael@0: if (osflags & PR_SYNC) access |= OPEN_FLAGS_WRITE_THROUGH; michael@0: michael@0: if (osflags & PR_RDONLY) michael@0: access |= OPEN_ACCESS_READONLY; michael@0: else if (osflags & PR_WRONLY) michael@0: access |= OPEN_ACCESS_WRITEONLY; michael@0: else if(osflags & PR_RDWR) michael@0: access |= OPEN_ACCESS_READWRITE; michael@0: michael@0: if ( osflags & PR_CREATE_FILE && osflags & PR_EXCL ) michael@0: { michael@0: flags = OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_FAIL_IF_EXISTS; michael@0: } michael@0: else if (osflags & PR_CREATE_FILE) michael@0: { michael@0: if (osflags & PR_TRUNCATE) michael@0: flags = OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_REPLACE_IF_EXISTS; michael@0: else michael@0: flags = OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS; michael@0: } michael@0: else michael@0: { michael@0: if (osflags & PR_TRUNCATE) michael@0: flags = OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_REPLACE_IF_EXISTS; michael@0: else michael@0: flags = OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS; michael@0: } michael@0: michael@0: do { michael@0: if (isWSEB) michael@0: { michael@0: rc = myDosOpenL((char*)name, michael@0: &file, /* file handle if successful */ michael@0: &actionTaken, /* reason for failure */ michael@0: 0, /* initial size of new file */ michael@0: FILE_NORMAL, /* file system attributes */ michael@0: flags, /* Open flags */ michael@0: access, /* Open mode and rights */ michael@0: 0); /* OS/2 Extended Attributes */ michael@0: } michael@0: else michael@0: { michael@0: rc = DosOpen((char*)name, michael@0: &file, /* file handle if successful */ michael@0: &actionTaken, /* reason for failure */ michael@0: 0, /* initial size of new file */ michael@0: FILE_NORMAL, /* file system attributes */ michael@0: flags, /* Open flags */ michael@0: access, /* Open mode and rights */ michael@0: 0); /* OS/2 Extended Attributes */ michael@0: }; michael@0: if (rc == ERROR_TOO_MANY_OPEN_FILES) { michael@0: ULONG CurMaxFH = 0; michael@0: LONG ReqCount = 20; michael@0: APIRET rc2; michael@0: rc2 = DosSetRelMaxFH(&ReqCount, &CurMaxFH); michael@0: if (rc2 != NO_ERROR) { michael@0: break; michael@0: } michael@0: } michael@0: } while (rc == ERROR_TOO_MANY_OPEN_FILES); michael@0: michael@0: if (rc != NO_ERROR) { michael@0: _PR_MD_MAP_OPEN_ERROR(rc); michael@0: return -1; michael@0: } michael@0: michael@0: return (PRInt32)file; michael@0: } michael@0: michael@0: PRInt32 michael@0: _PR_MD_READ(PRFileDesc *fd, void *buf, PRInt32 len) michael@0: { michael@0: ULONG bytes; michael@0: int rv; michael@0: michael@0: rv = DosRead((HFILE)fd->secret->md.osfd, michael@0: (PVOID)buf, michael@0: len, michael@0: &bytes); michael@0: michael@0: if (rv != NO_ERROR) michael@0: { michael@0: /* ERROR_HANDLE_EOF can only be returned by async io */ michael@0: PR_ASSERT(rv != ERROR_HANDLE_EOF); michael@0: if (rv == ERROR_BROKEN_PIPE) michael@0: return 0; michael@0: else { michael@0: _PR_MD_MAP_READ_ERROR(rv); michael@0: return -1; michael@0: } michael@0: } michael@0: return (PRInt32)bytes; michael@0: } michael@0: michael@0: PRInt32 michael@0: _PR_MD_WRITE(PRFileDesc *fd, const void *buf, PRInt32 len) michael@0: { michael@0: PRInt32 bytes; michael@0: int rv; michael@0: michael@0: rv = DosWrite((HFILE)fd->secret->md.osfd, michael@0: (PVOID)buf, michael@0: len, michael@0: (PULONG)&bytes); michael@0: michael@0: if (rv != NO_ERROR) michael@0: { michael@0: _PR_MD_MAP_WRITE_ERROR(rv); michael@0: return -1; michael@0: } michael@0: michael@0: if (len != bytes) { michael@0: rv = ERROR_DISK_FULL; michael@0: _PR_MD_MAP_WRITE_ERROR(rv); michael@0: return -1; michael@0: } michael@0: michael@0: return bytes; michael@0: } /* --- end _PR_MD_WRITE() --- */ michael@0: michael@0: PRInt32 michael@0: _PR_MD_LSEEK(PRFileDesc *fd, PRInt32 offset, PRSeekWhence whence) michael@0: { michael@0: PRInt32 rv; michael@0: PRUword newLocation; michael@0: michael@0: rv = DosSetFilePtr((HFILE)fd->secret->md.osfd, offset, whence, &newLocation); michael@0: michael@0: if (rv != NO_ERROR) { michael@0: _PR_MD_MAP_LSEEK_ERROR(rv); michael@0: return -1; michael@0: } else michael@0: return newLocation; michael@0: } michael@0: michael@0: PRInt64 michael@0: _PR_MD_LSEEK64(PRFileDesc *fd, PRInt64 offset, PRSeekWhence whence) michael@0: { michael@0: #ifdef NO_LONG_LONG michael@0: PRInt64 result; michael@0: PRInt32 rv, low = offset.lo, hi = offset.hi; michael@0: PRUword newLocation; michael@0: michael@0: rv = DosSetFilePtr((HFILE)fd->secret->md.osfd, low, whence, &newLocation); michael@0: rv = DosSetFilePtr((HFILE)fd->secret->md.osfd, hi, FILE_CURRENT, &newLocation); michael@0: michael@0: if (rv != NO_ERROR) { michael@0: _PR_MD_MAP_LSEEK_ERROR(rv); michael@0: hi = newLocation = -1; michael@0: } michael@0: michael@0: result.lo = newLocation; michael@0: result.hi = hi; michael@0: return result; michael@0: michael@0: #else michael@0: PRInt32 where, rc, lo = (PRInt32)offset, hi = (PRInt32)(offset >> 32); michael@0: PRUint64 rv; michael@0: PRUint32 newLocation, uhi; michael@0: PRUint64 newLocationL; michael@0: michael@0: switch (whence) michael@0: { michael@0: case PR_SEEK_SET: michael@0: where = FILE_BEGIN; michael@0: break; michael@0: case PR_SEEK_CUR: michael@0: where = FILE_CURRENT; michael@0: break; michael@0: case PR_SEEK_END: michael@0: where = FILE_END; michael@0: break; michael@0: default: michael@0: PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); michael@0: return -1; michael@0: } michael@0: if (isWSEB) michael@0: { michael@0: rc = myDosSetFilePtrL((HFILE)fd->secret->md.osfd, offset, where, (PLONGLONG)&newLocationL); michael@0: } michael@0: else michael@0: { michael@0: rc = DosSetFilePtr((HFILE)fd->secret->md.osfd, lo, where, (PULONG)&newLocation); michael@0: } michael@0: michael@0: if (rc != NO_ERROR) { michael@0: _PR_MD_MAP_LSEEK_ERROR(rc); michael@0: return -1; michael@0: } michael@0: michael@0: if (isWSEB) michael@0: { michael@0: return newLocationL; michael@0: } michael@0: michael@0: uhi = (PRUint32)hi; michael@0: PR_ASSERT((PRInt32)uhi >= 0); michael@0: rv = uhi; michael@0: PR_ASSERT((PRInt64)rv >= 0); michael@0: rv = (rv << 32); michael@0: PR_ASSERT((PRInt64)rv >= 0); michael@0: rv += newLocation; michael@0: PR_ASSERT((PRInt64)rv >= 0); michael@0: return (PRInt64)rv; michael@0: #endif michael@0: } michael@0: michael@0: PRInt32 michael@0: _PR_MD_FSYNC(PRFileDesc *fd) michael@0: { michael@0: PRInt32 rc = DosResetBuffer((HFILE)fd->secret->md.osfd); michael@0: michael@0: if (rc != NO_ERROR) { michael@0: if (rc != ERROR_ACCESS_DENIED) { michael@0: _PR_MD_MAP_FSYNC_ERROR(rc); michael@0: return -1; michael@0: } michael@0: } michael@0: return 0; michael@0: } michael@0: michael@0: PRInt32 michael@0: _MD_CloseFile(PRInt32 osfd) michael@0: { michael@0: PRInt32 rv; michael@0: michael@0: rv = DosClose((HFILE)osfd); michael@0: if (rv != NO_ERROR) michael@0: _PR_MD_MAP_CLOSE_ERROR(rv); michael@0: return rv; michael@0: } michael@0: michael@0: michael@0: /* --- DIR IO ------------------------------------------------------------ */ michael@0: #define GetFileFromDIR(d) (isWSEB?(d)->d_entry.large.achName:(d)->d_entry.small.achName) michael@0: #define GetFileAttr(d) (isWSEB?(d)->d_entry.large.attrFile:(d)->d_entry.small.attrFile) michael@0: michael@0: void FlipSlashes(char *cp, int len) michael@0: { michael@0: while (--len >= 0) { michael@0: if (cp[0] == '/') { michael@0: cp[0] = PR_DIRECTORY_SEPARATOR; michael@0: } michael@0: cp++; michael@0: } michael@0: } michael@0: michael@0: /* michael@0: ** michael@0: ** Local implementations of standard Unix RTL functions which are not provided michael@0: ** by the VAC RTL. michael@0: ** michael@0: */ michael@0: michael@0: PRInt32 michael@0: _PR_MD_CLOSE_DIR(_MDDir *d) michael@0: { michael@0: PRInt32 rc; michael@0: michael@0: if ( d ) { michael@0: rc = DosFindClose(d->d_hdl); michael@0: if(rc == NO_ERROR){ michael@0: d->magic = (PRUint32)-1; michael@0: return PR_SUCCESS; michael@0: } else { michael@0: _PR_MD_MAP_CLOSEDIR_ERROR(rc); michael@0: return PR_FAILURE; michael@0: } michael@0: } michael@0: PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); michael@0: return PR_FAILURE; michael@0: } michael@0: michael@0: michael@0: PRStatus michael@0: _PR_MD_OPEN_DIR(_MDDir *d, const char *name) michael@0: { michael@0: char filename[ CCHMAXPATH ]; michael@0: PRUword numEntries, rc; michael@0: michael@0: numEntries = 1; michael@0: michael@0: PR_snprintf(filename, CCHMAXPATH, "%s%s%s", michael@0: name, PR_DIRECTORY_SEPARATOR_STR, "*.*"); michael@0: FlipSlashes( filename, strlen(filename) ); michael@0: michael@0: d->d_hdl = HDIR_CREATE; michael@0: michael@0: if (isWSEB) michael@0: { michael@0: rc = DosFindFirst( filename, michael@0: &d->d_hdl, michael@0: FILE_DIRECTORY | FILE_HIDDEN, michael@0: &(d->d_entry.large), michael@0: sizeof(d->d_entry.large), michael@0: &numEntries, michael@0: FIL_STANDARDL); michael@0: } michael@0: else michael@0: { michael@0: rc = DosFindFirst( filename, michael@0: &d->d_hdl, michael@0: FILE_DIRECTORY | FILE_HIDDEN, michael@0: &(d->d_entry.small), michael@0: sizeof(d->d_entry.small), michael@0: &numEntries, michael@0: FIL_STANDARD); michael@0: } michael@0: if ( rc != NO_ERROR ) { michael@0: _PR_MD_MAP_OPENDIR_ERROR(rc); michael@0: return PR_FAILURE; michael@0: } michael@0: d->firstEntry = PR_TRUE; michael@0: d->magic = _MD_MAGIC_DIR; michael@0: return PR_SUCCESS; michael@0: } michael@0: michael@0: char * michael@0: _PR_MD_READ_DIR(_MDDir *d, PRIntn flags) michael@0: { michael@0: PRUword numFiles = 1; michael@0: BOOL rv; michael@0: char *fileName; michael@0: USHORT fileAttr; michael@0: michael@0: if ( d ) { michael@0: while (1) { michael@0: if (d->firstEntry) { michael@0: d->firstEntry = PR_FALSE; michael@0: rv = NO_ERROR; michael@0: } else { michael@0: rv = DosFindNext(d->d_hdl, michael@0: &(d->d_entry), michael@0: sizeof(d->d_entry), michael@0: &numFiles); michael@0: } michael@0: if (rv != NO_ERROR) { michael@0: break; michael@0: } michael@0: fileName = GetFileFromDIR(d); michael@0: fileAttr = GetFileAttr(d); michael@0: if ( (flags & PR_SKIP_DOT) && michael@0: (fileName[0] == '.') && (fileName[1] == '\0')) michael@0: continue; michael@0: if ( (flags & PR_SKIP_DOT_DOT) && michael@0: (fileName[0] == '.') && (fileName[1] == '.') && michael@0: (fileName[2] == '\0')) michael@0: continue; michael@0: /* michael@0: * XXX michael@0: * Is this the correct definition of a hidden file on OS/2? michael@0: */ michael@0: if ((flags & PR_SKIP_NONE) && (fileAttr & FILE_HIDDEN)) michael@0: return fileName; michael@0: else if ((flags & PR_SKIP_HIDDEN) && (fileAttr & FILE_HIDDEN)) michael@0: continue; michael@0: return fileName; michael@0: } michael@0: PR_ASSERT(NO_ERROR != rv); michael@0: _PR_MD_MAP_READDIR_ERROR(rv); michael@0: return NULL; michael@0: } michael@0: PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); michael@0: return NULL; michael@0: } michael@0: michael@0: PRInt32 michael@0: _PR_MD_DELETE(const char *name) michael@0: { michael@0: PRInt32 rc = DosDelete((char*)name); michael@0: if(rc == NO_ERROR) { michael@0: return 0; michael@0: } else { michael@0: _PR_MD_MAP_DELETE_ERROR(rc); michael@0: return -1; michael@0: } michael@0: } michael@0: michael@0: PRInt32 michael@0: _PR_MD_STAT(const char *fn, struct stat *info) michael@0: { michael@0: PRInt32 rv; michael@0: char filename[CCHMAXPATH]; michael@0: michael@0: PR_snprintf(filename, CCHMAXPATH, "%s", fn); michael@0: FlipSlashes(filename, strlen(filename)); michael@0: michael@0: rv = _stat((char*)filename, info); michael@0: if (-1 == rv) { michael@0: /* michael@0: * Check for MSVC runtime library _stat() bug. michael@0: * (It's really a bug in FindFirstFile().) michael@0: * If a pathname ends in a backslash or slash, michael@0: * e.g., c:\temp\ or c:/temp/, _stat() will fail. michael@0: * Note: a pathname ending in a slash (e.g., c:/temp/) michael@0: * can be handled by _stat() on NT but not on Win95. michael@0: * michael@0: * We remove the backslash or slash at the end and michael@0: * try again. michael@0: * michael@0: * Not sure if this happens on OS/2 or not, michael@0: * but it doesn't hurt to be careful. michael@0: */ michael@0: michael@0: int len = strlen(fn); michael@0: if (len > 0 && len <= _MAX_PATH michael@0: && (fn[len - 1] == '\\' || fn[len - 1] == '/')) { michael@0: char newfn[_MAX_PATH + 1]; michael@0: michael@0: strcpy(newfn, fn); michael@0: newfn[len - 1] = '\0'; michael@0: rv = _stat(newfn, info); michael@0: } michael@0: } michael@0: michael@0: if (-1 == rv) { michael@0: _PR_MD_MAP_STAT_ERROR(errno); michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: PRInt32 michael@0: _PR_MD_GETFILEINFO(const char *fn, PRFileInfo *info) michael@0: { michael@0: struct stat sb; michael@0: PRInt32 rv; michael@0: PRInt64 s, s2us; michael@0: michael@0: if ( (rv = _PR_MD_STAT(fn, &sb)) == 0 ) { michael@0: if (info) { michael@0: if (S_IFREG & sb.st_mode) michael@0: info->type = PR_FILE_FILE ; michael@0: else if (S_IFDIR & sb.st_mode) michael@0: info->type = PR_FILE_DIRECTORY; michael@0: else michael@0: info->type = PR_FILE_OTHER; michael@0: info->size = sb.st_size; michael@0: LL_I2L(s2us, PR_USEC_PER_SEC); michael@0: LL_I2L(s, sb.st_mtime); michael@0: LL_MUL(s, s, s2us); michael@0: info->modifyTime = s; michael@0: LL_I2L(s, sb.st_ctime); michael@0: LL_MUL(s, s, s2us); michael@0: info->creationTime = s; michael@0: } michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: PRInt32 michael@0: _PR_MD_GETFILEINFO64(const char *fn, PRFileInfo64 *info) michael@0: { michael@0: PRFileInfo info32; michael@0: PRInt32 rv = _PR_MD_GETFILEINFO(fn, &info32); michael@0: if (rv != 0) michael@0: { michael@0: return rv; michael@0: } michael@0: info->type = info32.type; michael@0: LL_UI2L(info->size,info32.size); michael@0: info->modifyTime = info32.modifyTime; michael@0: info->creationTime = info32.creationTime; michael@0: michael@0: if (isWSEB) michael@0: { michael@0: APIRET rc ; michael@0: FILESTATUS3L fstatus; michael@0: michael@0: rc = DosQueryPathInfo(fn, FIL_STANDARDL, &fstatus, sizeof(fstatus)); michael@0: michael@0: if (NO_ERROR != rc) michael@0: { michael@0: _PR_MD_MAP_OPEN_ERROR(rc); michael@0: return -1; michael@0: } michael@0: michael@0: if (! (fstatus.attrFile & FILE_DIRECTORY)) michael@0: { michael@0: info->size = fstatus.cbFile; michael@0: } michael@0: } michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: PRInt32 michael@0: _PR_MD_GETOPENFILEINFO(const PRFileDesc *fd, PRFileInfo *info) michael@0: { michael@0: /* For once, the VAC compiler/library did a nice thing. michael@0: * The file handle used by the C runtime is the same one michael@0: * returned by the OS when you call DosOpen(). This means michael@0: * that you can take an OS HFILE and use it with C file michael@0: * functions. The only caveat is that you have to call michael@0: * _setmode() first to initialize some junk. This is michael@0: * immensely useful because I did not have a clue how to michael@0: * implement this function otherwise. The windows folks michael@0: * took the source from the Microsoft C library source, but michael@0: * IBM wasn't kind enough to ship the source with VAC. michael@0: * On second thought, the needed function could probably michael@0: * be gotten from the OS/2 GNU library source, but the michael@0: * point is now moot. michael@0: */ michael@0: struct stat hinfo; michael@0: PRInt64 s, s2us; michael@0: michael@0: _setmode(fd->secret->md.osfd, O_BINARY); michael@0: if(fstat((int)fd->secret->md.osfd, &hinfo) != NO_ERROR) { michael@0: _PR_MD_MAP_FSTAT_ERROR(errno); michael@0: return -1; michael@0: } michael@0: michael@0: if (hinfo.st_mode & S_IFDIR) michael@0: info->type = PR_FILE_DIRECTORY; michael@0: else michael@0: info->type = PR_FILE_FILE; michael@0: michael@0: info->size = hinfo.st_size; michael@0: LL_I2L(s2us, PR_USEC_PER_SEC); michael@0: LL_I2L(s, hinfo.st_mtime); michael@0: LL_MUL(s, s, s2us); michael@0: info->modifyTime = s; michael@0: LL_I2L(s, hinfo.st_ctime); michael@0: LL_MUL(s, s, s2us); michael@0: info->creationTime = s; michael@0: michael@0: return 0; michael@0: } michael@0: michael@0: PRInt32 michael@0: _PR_MD_GETOPENFILEINFO64(const PRFileDesc *fd, PRFileInfo64 *info) michael@0: { michael@0: PRFileInfo info32; michael@0: PRInt32 rv = _PR_MD_GETOPENFILEINFO(fd, &info32); michael@0: if (0 == rv) michael@0: { michael@0: info->type = info32.type; michael@0: LL_UI2L(info->size,info32.size); michael@0: michael@0: info->modifyTime = info32.modifyTime; michael@0: info->creationTime = info32.creationTime; michael@0: } michael@0: michael@0: if (isWSEB) michael@0: { michael@0: APIRET rc ; michael@0: FILESTATUS3L fstatus; michael@0: michael@0: rc = DosQueryFileInfo(fd->secret->md.osfd, FIL_STANDARDL, &fstatus, sizeof(fstatus)); michael@0: michael@0: if (NO_ERROR != rc) michael@0: { michael@0: _PR_MD_MAP_OPEN_ERROR(rc); michael@0: return -1; michael@0: } michael@0: michael@0: if (! (fstatus.attrFile & FILE_DIRECTORY)) michael@0: { michael@0: info->size = fstatus.cbFile; michael@0: } michael@0: } michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: michael@0: PRInt32 michael@0: _PR_MD_RENAME(const char *from, const char *to) michael@0: { michael@0: PRInt32 rc; michael@0: /* Does this work with dot-relative pathnames? */ michael@0: if ( (rc = DosMove((char *)from, (char *)to)) == NO_ERROR) { michael@0: return 0; michael@0: } else { michael@0: _PR_MD_MAP_RENAME_ERROR(rc); michael@0: return -1; michael@0: } michael@0: } michael@0: michael@0: PRInt32 michael@0: _PR_MD_ACCESS(const char *name, PRAccessHow how) michael@0: { michael@0: PRInt32 rv; michael@0: switch (how) { michael@0: case PR_ACCESS_WRITE_OK: michael@0: rv = access(name, 02); michael@0: break; michael@0: case PR_ACCESS_READ_OK: michael@0: rv = access(name, 04); michael@0: break; michael@0: case PR_ACCESS_EXISTS: michael@0: return access(name, 00); michael@0: break; michael@0: default: michael@0: PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); michael@0: return -1; michael@0: } michael@0: if (rv < 0) michael@0: _PR_MD_MAP_ACCESS_ERROR(errno); michael@0: return rv; michael@0: } michael@0: michael@0: PRInt32 michael@0: _PR_MD_MKDIR(const char *name, PRIntn mode) michael@0: { michael@0: PRInt32 rc; michael@0: /* XXXMB - how to translate the "mode"??? */ michael@0: if ((rc = DosCreateDir((char *)name, NULL))== NO_ERROR) { michael@0: return 0; michael@0: } else { michael@0: _PR_MD_MAP_MKDIR_ERROR(rc); michael@0: return -1; michael@0: } michael@0: } michael@0: michael@0: PRInt32 michael@0: _PR_MD_RMDIR(const char *name) michael@0: { michael@0: PRInt32 rc; michael@0: if ( (rc = DosDeleteDir((char *)name)) == NO_ERROR) { michael@0: return 0; michael@0: } else { michael@0: _PR_MD_MAP_RMDIR_ERROR(rc); michael@0: return -1; michael@0: } michael@0: } michael@0: michael@0: PRStatus michael@0: _PR_MD_LOCKFILE(PRInt32 f) michael@0: { michael@0: PRInt32 rv; michael@0: FILELOCK lock, unlock; michael@0: FILELOCKL lockL, unlockL; michael@0: michael@0: lock.lOffset = 0; michael@0: lockL.lOffset = 0; michael@0: lock.lRange = 0xffffffff; michael@0: lockL.lRange = 0xffffffffffffffff; michael@0: unlock.lOffset = 0; michael@0: unlock.lRange = 0; michael@0: unlockL.lOffset = 0; michael@0: unlockL.lRange = 0; michael@0: michael@0: /* michael@0: * loop trying to DosSetFileLocks(), michael@0: * pause for a few miliseconds when can't get the lock michael@0: * and try again michael@0: */ michael@0: for( rv = FALSE; rv == FALSE; /* do nothing */ ) michael@0: { michael@0: if (isWSEB) michael@0: { michael@0: rv = myDosSetFileLocksL( (HFILE) f, michael@0: &unlockL, &lockL, michael@0: 0, 0); michael@0: } michael@0: else michael@0: { michael@0: rv = DosSetFileLocks( (HFILE) f, michael@0: &unlock, &lock, michael@0: 0, 0); michael@0: } michael@0: if ( rv != NO_ERROR ) michael@0: { michael@0: DosSleep( 50 ); /* Sleep() a few milisecs and try again. */ michael@0: } michael@0: } /* end for() */ michael@0: return PR_SUCCESS; michael@0: } /* end _PR_MD_LOCKFILE() */ michael@0: michael@0: PRStatus michael@0: _PR_MD_TLOCKFILE(PRInt32 f) michael@0: { michael@0: return _PR_MD_LOCKFILE(f); michael@0: } /* end _PR_MD_TLOCKFILE() */ michael@0: michael@0: michael@0: PRStatus michael@0: _PR_MD_UNLOCKFILE(PRInt32 f) michael@0: { michael@0: PRInt32 rv; michael@0: FILELOCK lock, unlock; michael@0: FILELOCKL lockL, unlockL; michael@0: michael@0: lock.lOffset = 0; michael@0: lockL.lOffset = 0; michael@0: lock.lRange = 0; michael@0: lockL.lRange = 0; michael@0: unlock.lOffset = 0; michael@0: unlockL.lOffset = 0; michael@0: unlock.lRange = 0xffffffff; michael@0: unlockL.lRange = 0xffffffffffffffff; michael@0: michael@0: if (isWSEB) michael@0: { michael@0: rv = myDosSetFileLocksL( (HFILE) f, michael@0: &unlockL, &lockL, michael@0: 0, 0); michael@0: } michael@0: else michael@0: { michael@0: rv = DosSetFileLocks( (HFILE) f, michael@0: &unlock, &lock, michael@0: 0, 0); michael@0: } michael@0: michael@0: if ( rv != NO_ERROR ) michael@0: { michael@0: return PR_SUCCESS; michael@0: } michael@0: else michael@0: { michael@0: return PR_FAILURE; michael@0: } michael@0: } /* end _PR_MD_UNLOCKFILE() */ michael@0: michael@0: PRStatus michael@0: _PR_MD_SET_FD_INHERITABLE(PRFileDesc *fd, PRBool inheritable) michael@0: { michael@0: APIRET rc = 0; michael@0: ULONG flags; michael@0: switch (fd->methods->file_type) michael@0: { michael@0: case PR_DESC_PIPE: michael@0: case PR_DESC_FILE: michael@0: rc = DosQueryFHState((HFILE)fd->secret->md.osfd, &flags); michael@0: if (rc != NO_ERROR) { michael@0: PR_SetError(PR_UNKNOWN_ERROR, _MD_ERRNO()); michael@0: return PR_FAILURE; michael@0: } michael@0: michael@0: if (inheritable) michael@0: flags &= ~OPEN_FLAGS_NOINHERIT; michael@0: else michael@0: flags |= OPEN_FLAGS_NOINHERIT; michael@0: michael@0: /* Mask off flags DosSetFHState don't want. */ michael@0: flags &= (OPEN_FLAGS_WRITE_THROUGH | OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_NO_CACHE | OPEN_FLAGS_NOINHERIT); michael@0: rc = DosSetFHState((HFILE)fd->secret->md.osfd, flags); michael@0: if (rc != NO_ERROR) { michael@0: PR_SetError(PR_UNKNOWN_ERROR, _MD_ERRNO()); michael@0: return PR_FAILURE; michael@0: } michael@0: break; michael@0: michael@0: case PR_DESC_LAYERED: michael@0: /* what to do here? */ michael@0: PR_SetError(PR_UNKNOWN_ERROR, 87 /*ERROR_INVALID_PARAMETER*/); michael@0: return PR_FAILURE; michael@0: michael@0: case PR_DESC_SOCKET_TCP: michael@0: case PR_DESC_SOCKET_UDP: michael@0: /* These are global on OS/2. */ michael@0: break; michael@0: } michael@0: michael@0: return PR_SUCCESS; michael@0: } michael@0: michael@0: void michael@0: _PR_MD_INIT_FD_INHERITABLE(PRFileDesc *fd, PRBool imported) michael@0: { michael@0: /* XXX this function needs to be implemented */ michael@0: fd->secret->inheritable = _PR_TRI_UNKNOWN; michael@0: } michael@0: michael@0: void michael@0: _PR_MD_QUERY_FD_INHERITABLE(PRFileDesc *fd) michael@0: { michael@0: /* XXX this function needs to be reviewed */ michael@0: ULONG flags; michael@0: michael@0: PR_ASSERT(_PR_TRI_UNKNOWN == fd->secret->inheritable); michael@0: if (DosQueryFHState((HFILE)fd->secret->md.osfd, &flags) == 0) { michael@0: if (flags & OPEN_FLAGS_NOINHERIT) { michael@0: fd->secret->inheritable = _PR_TRI_FALSE; michael@0: } else { michael@0: fd->secret->inheritable = _PR_TRI_TRUE; michael@0: } michael@0: } michael@0: }