| /* -*- Mode: C++; tab-width: 8; c-basic-offset: 8 -*- */ |
| /* ***** 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" |
| |
| /* |
| ** Global lock variable used to bracket calls into rusty libraries that |
| ** aren't thread safe (like libc, libX, etc). |
| */ |
| static PRLock *_pr_rename_lock = NULL; |
| |
| void |
| _MD_InitIO (void) |
| { |
| } |
| |
| PRStatus |
| _MD_open_dir (_MDDir *md,const char *name) |
| { |
| int err; |
| |
| md->d = opendir(name); |
| if (!md->d) { |
| err = _MD_ERRNO(); |
| _PR_MD_MAP_OPENDIR_ERROR(err); |
| return PR_FAILURE; |
| } |
| return PR_SUCCESS; |
| } |
| |
| char* |
| _MD_read_dir (_MDDir *md, PRIntn flags) |
| { |
| struct dirent *de; |
| int err; |
| |
| for (;;) { |
| /* |
| * XXX: readdir() is not MT-safe |
| */ |
| _MD_ERRNO() = 0; |
| de = readdir(md->d); |
| |
| if (!de) { |
| err = _MD_ERRNO(); |
| _PR_MD_MAP_READDIR_ERROR(err); |
| 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; |
| |
| if ((flags & PR_SKIP_HIDDEN) && (de->d_name[1] == '.')) |
| continue; |
| |
| break; |
| } |
| return de->d_name; |
| } |
| |
| |
| PRInt32 |
| _MD_close_dir (_MDDir *md) |
| { |
| int rv = 0, err; |
| |
| if (md->d) { |
| rv = closedir(md->d); |
| if (rv == -1) { |
| err = _MD_ERRNO(); |
| _PR_MD_MAP_CLOSEDIR_ERROR(err); |
| } |
| } |
| return(rv); |
| } |
| |
| void |
| _MD_make_nonblock (PRFileDesc *fd) |
| { |
| int blocking = 1; |
| setsockopt(fd->secret->md.osfd, SOL_SOCKET, SO_NONBLOCK, &blocking, sizeof(blocking)); |
| |
| } |
| |
| PRStatus |
| _MD_set_fd_inheritable (PRFileDesc *fd, PRBool inheritable) |
| { |
| int rv; |
| |
| rv = fcntl(fd->secret->md.osfd, F_SETFD, inheritable ? 0 : FD_CLOEXEC); |
| if (-1 == rv) { |
| PR_SetError(PR_UNKNOWN_ERROR, _MD_ERRNO()); |
| return PR_FAILURE; |
| } |
| return PR_SUCCESS; |
| } |
| |
| void |
| _MD_init_fd_inheritable (PRFileDesc *fd, PRBool imported) |
| { |
| if (imported) { |
| fd->secret->inheritable = _PR_TRI_UNKNOWN; |
| } else { |
| int flags = fcntl(fd->secret->md.osfd, F_GETFD, 0); |
| if (flags == -1) { |
| PR_SetError(PR_UNKNOWN_ERROR, _MD_ERRNO()); |
| return; |
| } |
| fd->secret->inheritable = (flags & FD_CLOEXEC) ? |
| _PR_TRI_TRUE : _PR_TRI_FALSE; |
| } |
| } |
| |
| void |
| _MD_query_fd_inheritable (PRFileDesc *fd) |
| { |
| int flags; |
| |
| PR_ASSERT(_PR_TRI_UNKNOWN == fd->secret->inheritable); |
| flags = fcntl(fd->secret->md.osfd, F_GETFD, 0); |
| PR_ASSERT(-1 != flags); |
| fd->secret->inheritable = (flags & FD_CLOEXEC) ? |
| _PR_TRI_FALSE : _PR_TRI_TRUE; |
| } |
| |
| PRInt32 |
| _MD_open (const char *name, PRIntn flags, PRIntn mode) |
| { |
| PRInt32 osflags; |
| PRInt32 rv, err; |
| |
| if (flags & PR_RDWR) { |
| osflags = O_RDWR; |
| } else if (flags & PR_WRONLY) { |
| osflags = O_WRONLY; |
| } else { |
| osflags = O_RDONLY; |
| } |
| |
| if (flags & PR_EXCL) |
| osflags |= O_EXCL; |
| if (flags & PR_APPEND) |
| osflags |= O_APPEND; |
| if (flags & PR_TRUNCATE) |
| osflags |= O_TRUNC; |
| if (flags & PR_SYNC) { |
| /* Ummmm. BeOS doesn't appear to |
| support sync in any way shape or |
| form. */ |
| return PR_NOT_IMPLEMENTED_ERROR; |
| } |
| |
| /* |
| ** On creations we hold the 'create' lock in order to enforce |
| ** the semantics of PR_Rename. (see the latter for more details) |
| */ |
| if (flags & PR_CREATE_FILE) |
| { |
| osflags |= O_CREAT ; |
| if (NULL !=_pr_rename_lock) |
| PR_Lock(_pr_rename_lock); |
| } |
| |
| rv = open(name, osflags, mode); |
| |
| if (rv < 0) { |
| err = _MD_ERRNO(); |
| _PR_MD_MAP_OPEN_ERROR(err); |
| } |
| |
| if ((flags & PR_CREATE_FILE) && (NULL !=_pr_rename_lock)) |
| PR_Unlock(_pr_rename_lock); |
| return rv; |
| } |
| |
| PRInt32 |
| _MD_close_file (PRInt32 osfd) |
| { |
| PRInt32 rv, err; |
| |
| rv = close(osfd); |
| if (rv == -1) { |
| err = _MD_ERRNO(); |
| _PR_MD_MAP_CLOSE_ERROR(err); |
| } |
| return(rv); |
| } |
| |
| PRInt32 |
| _MD_read (PRFileDesc *fd, void *buf, PRInt32 amount) |
| { |
| PRInt32 rv, err; |
| PRInt32 osfd = fd->secret->md.osfd; |
| |
| rv = read( osfd, buf, amount ); |
| if (rv < 0) { |
| err = _MD_ERRNO(); |
| _PR_MD_MAP_READ_ERROR(err); |
| } |
| return(rv); |
| } |
| |
| PRInt32 |
| _MD_write (PRFileDesc *fd, const void *buf, PRInt32 amount) |
| { |
| PRInt32 rv, err; |
| PRInt32 osfd = fd->secret->md.osfd; |
| |
| rv = write( osfd, buf, amount ); |
| |
| if( rv < 0 ) { |
| |
| err = _MD_ERRNO(); |
| _PR_MD_MAP_WRITE_ERROR(err); |
| } |
| return( rv ); |
| } |
| |
| #ifndef BONE_VERSION /* Writev moves to bnet.c with BONE */ |
| PRInt32 |
| _MD_writev (PRFileDesc *fd, const PRIOVec *iov, PRInt32 iov_size, |
| PRIntervalTime timeout) |
| { |
| return PR_NOT_IMPLEMENTED_ERROR; |
| } |
| #endif |
| |
| PRInt32 |
| _MD_lseek (PRFileDesc *fd, PRInt32 offset, int whence) |
| { |
| PRInt32 rv, err; |
| |
| rv = lseek (fd->secret->md.osfd, offset, whence); |
| if (rv == -1) { |
| err = _MD_ERRNO(); |
| _PR_MD_MAP_LSEEK_ERROR(err); |
| } |
| return( rv ); |
| } |
| |
| PRInt64 |
| _MD_lseek64 (PRFileDesc *fd, PRInt64 offset, int whence) |
| { |
| PRInt32 rv, err; |
| |
| /* According to the BeOS headers, lseek accepts a |
| * variable of type off_t for the offset, and off_t |
| * is defined to be a 64-bit value. So no special |
| * cracking needs to be done on "offset". |
| */ |
| |
| rv = lseek (fd->secret->md.osfd, offset, whence); |
| if (rv == -1) { |
| err = _MD_ERRNO(); |
| _PR_MD_MAP_LSEEK_ERROR(err); |
| } |
| return( rv ); |
| } |
| |
| PRInt32 |
| _MD_fsync (PRFileDesc *fd) |
| { |
| PRInt32 rv, err; |
| |
| rv = fsync(fd->secret->md.osfd); |
| if (rv == -1) { |
| err = _MD_ERRNO(); |
| _PR_MD_MAP_FSYNC_ERROR(err); |
| } |
| return(rv); |
| } |
| |
| PRInt32 |
| _MD_delete (const char *name) |
| { |
| PRInt32 rv, err; |
| |
| rv = unlink(name); |
| if (rv == -1) |
| { |
| err = _MD_ERRNO(); |
| _PR_MD_MAP_UNLINK_ERROR(err); |
| } |
| return (rv); |
| } |
| |
| PRInt32 |
| _MD_getfileinfo (const char *fn, PRFileInfo *info) |
| { |
| struct stat sb; |
| PRInt32 rv, err; |
| PRInt64 s, s2us; |
| |
| rv = stat(fn, &sb); |
| if (rv < 0) { |
| err = _MD_ERRNO(); |
| _PR_MD_MAP_STAT_ERROR(err); |
| } else 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; |
| |
| /* Must truncate file size for the 32 bit |
| version */ |
| info->size = (sb.st_size & 0xffffffff); |
| LL_I2L(s, sb.st_mtime); |
| LL_I2L(s2us, PR_USEC_PER_SEC); |
| LL_MUL(s, s, s2us); |
| info->modifyTime = s; |
| LL_I2L(s, sb.st_ctime); |
| LL_MUL(s, s, s2us); |
| info->creationTime = s; |
| } |
| return rv; |
| } |
| |
| PRInt32 |
| _MD_getfileinfo64 (const char *fn, PRFileInfo64 *info) |
| { |
| struct stat sb; |
| PRInt32 rv, err; |
| PRInt64 s, s2us; |
| |
| rv = stat(fn, &sb); |
| if (rv < 0) { |
| err = _MD_ERRNO(); |
| _PR_MD_MAP_STAT_ERROR(err); |
| } else 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; |
| |
| /* For the 64 bit version we can use |
| * the native st_size without modification |
| */ |
| info->size = sb.st_size; |
| LL_I2L(s, sb.st_mtime); |
| LL_I2L(s2us, PR_USEC_PER_SEC); |
| LL_MUL(s, s, s2us); |
| info->modifyTime = s; |
| LL_I2L(s, sb.st_ctime); |
| LL_MUL(s, s, s2us); |
| info->creationTime = s; |
| } |
| return rv; |
| } |
| |
| PRInt32 |
| _MD_getopenfileinfo (const PRFileDesc *fd, PRFileInfo *info) |
| { |
| struct stat sb; |
| PRInt64 s, s2us; |
| PRInt32 rv, err; |
| |
| rv = fstat(fd->secret->md.osfd, &sb); |
| if (rv < 0) { |
| err = _MD_ERRNO(); |
| _PR_MD_MAP_FSTAT_ERROR(err); |
| } else if (info) { |
| 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; |
| /* Use lower 32 bits of file size */ |
| info->size = ( sb.st_size & 0xffffffff); |
| LL_I2L(s, sb.st_mtime); |
| LL_I2L(s2us, PR_USEC_PER_SEC); |
| LL_MUL(s, s, s2us); |
| info->modifyTime = s; |
| LL_I2L(s, sb.st_ctime); |
| LL_MUL(s, s, s2us); |
| info->creationTime = s; |
| } |
| } |
| return rv; |
| } |
| |
| PRInt32 |
| _MD_getopenfileinfo64 (const PRFileDesc *fd, PRFileInfo64 *info) |
| { |
| struct stat sb; |
| PRInt64 s, s2us; |
| PRInt32 rv, err; |
| |
| rv = fstat(fd->secret->md.osfd, &sb); |
| if (rv < 0) { |
| err = _MD_ERRNO(); |
| _PR_MD_MAP_FSTAT_ERROR(err); |
| } else if (info) { |
| 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(s, sb.st_mtime); |
| LL_I2L(s2us, PR_USEC_PER_SEC); |
| LL_MUL(s, s, s2us); |
| info->modifyTime = s; |
| LL_I2L(s, sb.st_ctime); |
| LL_MUL(s, s, s2us); |
| info->creationTime = s; |
| } |
| } |
| return rv; |
| } |
| |
| PRInt32 |
| _MD_rename (const char *from, const char *to) |
| { |
| PRInt32 rv = -1, err; |
| |
| /* |
| ** This is trying to enforce the semantics of WINDOZE' rename |
| ** operation. That means one is not allowed to rename over top |
| ** of an existing file. Holding a lock across these two function |
| ** and the open function is known to be a bad idea, but .... |
| */ |
| if (NULL != _pr_rename_lock) |
| PR_Lock(_pr_rename_lock); |
| if (0 == access(to, F_OK)) |
| PR_SetError(PR_FILE_EXISTS_ERROR, 0); |
| else |
| { |
| rv = rename(from, to); |
| if (rv < 0) { |
| err = _MD_ERRNO(); |
| _PR_MD_MAP_RENAME_ERROR(err); |
| } |
| } |
| if (NULL != _pr_rename_lock) |
| PR_Unlock(_pr_rename_lock); |
| return rv; |
| } |
| |
| PRInt32 |
| _MD_access (const char *name, PRIntn how) |
| { |
| PRInt32 rv, err; |
| int checkFlags; |
| struct stat buf; |
| |
| switch (how) { |
| case PR_ACCESS_WRITE_OK: |
| checkFlags = S_IWUSR | S_IWGRP | S_IWOTH; |
| break; |
| |
| case PR_ACCESS_READ_OK: |
| checkFlags = S_IRUSR | S_IRGRP | S_IROTH; |
| break; |
| |
| case PR_ACCESS_EXISTS: |
| /* we don't need to examine st_mode. */ |
| break; |
| |
| default: |
| PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); |
| return -1; |
| } |
| |
| rv = stat(name, &buf); |
| if (rv == 0 && how != PR_ACCESS_EXISTS && (!(buf.st_mode & checkFlags))) { |
| PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, 0); |
| return -1; |
| } |
| |
| if (rv < 0) { |
| err = _MD_ERRNO(); |
| _PR_MD_MAP_STAT_ERROR(err); |
| } |
| |
| return(rv); |
| } |
| |
| PRInt32 |
| _MD_stat (const char *name, struct stat *buf) |
| { |
| return PR_NOT_IMPLEMENTED_ERROR; |
| } |
| |
| PRInt32 |
| _MD_mkdir (const char *name, PRIntn mode) |
| { |
| status_t rv; |
| int err; |
| |
| /* |
| ** This lock is used to enforce rename semantics as described |
| ** in PR_Rename. Look there for more fun details. |
| */ |
| if (NULL !=_pr_rename_lock) |
| PR_Lock(_pr_rename_lock); |
| |
| rv = mkdir(name, mode); |
| if (rv < 0) { |
| err = _MD_ERRNO(); |
| _PR_MD_MAP_MKDIR_ERROR(err); |
| } |
| if (NULL !=_pr_rename_lock) |
| PR_Unlock(_pr_rename_lock); |
| return rv; |
| } |
| |
| PRInt32 |
| _MD_rmdir (const char *name) |
| { |
| int rv, err; |
| |
| rv = rmdir(name); |
| if (rv == -1) { |
| err = _MD_ERRNO(); |
| _PR_MD_MAP_RMDIR_ERROR(err); |
| } |
| return rv; |
| } |
| |
| PRInt32 |
| _MD_pr_poll(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout) |
| { |
| PRInt32 rv = 0; |
| PRThread *me = _PR_MD_CURRENT_THREAD(); |
| /* |
| * This code is almost a duplicate of w32poll.c's _PR_MD_PR_POLL(). |
| */ |
| fd_set rd, wt, ex; |
| PRFileDesc *bottom; |
| PRPollDesc *pd, *epd; |
| PRInt32 maxfd = -1, ready, err; |
| PRIntervalTime remaining, elapsed, start; |
| |
| struct timeval tv, *tvp = NULL; |
| |
| if (_PR_PENDING_INTERRUPT(me)) |
| { |
| me->flags &= ~_PR_INTERRUPT; |
| PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); |
| return -1; |
| } |
| |
| if (0 == npds) { |
| PR_Sleep(timeout); |
| return rv; |
| } |
| |
| FD_ZERO(&rd); |
| FD_ZERO(&wt); |
| FD_ZERO(&ex); |
| |
| ready = 0; |
| for (pd = pds, epd = pd + npds; pd < epd; pd++) |
| { |
| PRInt16 in_flags_read = 0, in_flags_write = 0; |
| PRInt16 out_flags_read = 0, out_flags_write = 0; |
| |
| if ((NULL != pd->fd) && (0 != pd->in_flags)) |
| { |
| if (pd->in_flags & PR_POLL_READ) |
| { |
| in_flags_read = (pd->fd->methods->poll)(pd->fd, pd->in_flags & ~PR_POLL_WRITE, &out_flags_read); |
| } |
| if (pd->in_flags & PR_POLL_WRITE) |
| { |
| in_flags_write = (pd->fd->methods->poll)(pd->fd, pd->in_flags & ~PR_POLL_READ, &out_flags_write); |
| } |
| if ((0 != (in_flags_read & out_flags_read)) |
| || (0 != (in_flags_write & out_flags_write))) |
| { |
| /* this one's ready right now */ |
| if (0 == ready) |
| { |
| /* |
| * We will have to return without calling the |
| * system poll/select function. So zero the |
| * out_flags fields of all the poll descriptors |
| * before this one. |
| */ |
| PRPollDesc *prev; |
| for (prev = pds; prev < pd; prev++) |
| { |
| prev->out_flags = 0; |
| } |
| } |
| ready += 1; |
| pd->out_flags = out_flags_read | out_flags_write; |
| } |
| else |
| { |
| pd->out_flags = 0; /* pre-condition */ |
| |
| /* make sure this is an NSPR supported stack */ |
| bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); |
| PR_ASSERT(NULL != bottom); /* what to do about that? */ |
| if ((NULL != bottom) |
| && (_PR_FILEDESC_OPEN == bottom->secret->state)) |
| { |
| if (0 == ready) |
| { |
| PRInt32 osfd = bottom->secret->md.osfd; |
| if (osfd > maxfd) maxfd = osfd; |
| if (in_flags_read & PR_POLL_READ) |
| { |
| pd->out_flags |= _PR_POLL_READ_SYS_READ; |
| FD_SET(osfd, &rd); |
| } |
| if (in_flags_read & PR_POLL_WRITE) |
| { |
| pd->out_flags |= _PR_POLL_READ_SYS_WRITE; |
| FD_SET(osfd, &wt); |
| } |
| if (in_flags_write & PR_POLL_READ) |
| { |
| pd->out_flags |= _PR_POLL_WRITE_SYS_READ; |
| FD_SET(osfd, &rd); |
| } |
| if (in_flags_write & PR_POLL_WRITE) |
| { |
| pd->out_flags |= _PR_POLL_WRITE_SYS_WRITE; |
| FD_SET(osfd, &wt); |
| } |
| if (pd->in_flags & PR_POLL_EXCEPT) FD_SET(osfd, &ex); |
| } |
| } |
| else |
| { |
| if (0 == ready) |
| { |
| PRPollDesc *prev; |
| for (prev = pds; prev < pd; prev++) |
| { |
| prev->out_flags = 0; |
| } |
| } |
| ready += 1; /* this will cause an abrupt return */ |
| pd->out_flags = PR_POLL_NVAL; /* bogii */ |
| } |
| } |
| } |
| else |
| { |
| pd->out_flags = 0; |
| } |
| } |
| |
| if (0 != ready) return ready; /* no need to block */ |
| |
| remaining = timeout; |
| start = PR_IntervalNow(); |
| |
| retry: |
| if (timeout != PR_INTERVAL_NO_TIMEOUT) |
| { |
| PRInt32 ticksPerSecond = PR_TicksPerSecond(); |
| tv.tv_sec = remaining / ticksPerSecond; |
| tv.tv_usec = PR_IntervalToMicroseconds( remaining % ticksPerSecond ); |
| tvp = &tv; |
| } |
| |
| ready = _MD_SELECT(maxfd + 1, &rd, &wt, &ex, tvp); |
| |
| if (ready == -1 && errno == EINTR) |
| { |
| if (timeout == PR_INTERVAL_NO_TIMEOUT) goto retry; |
| else |
| { |
| elapsed = (PRIntervalTime) (PR_IntervalNow() - start); |
| if (elapsed > timeout) ready = 0; /* timed out */ |
| else |
| { |
| remaining = timeout - elapsed; |
| goto retry; |
| } |
| } |
| } |
| |
| /* |
| ** Now to unravel the select sets back into the client's poll |
| ** descriptor list. Is this possibly an area for pissing away |
| ** a few cycles or what? |
| */ |
| if (ready > 0) |
| { |
| ready = 0; |
| for (pd = pds, epd = pd + npds; pd < epd; pd++) |
| { |
| PRInt16 out_flags = 0; |
| if ((NULL != pd->fd) && (0 != pd->in_flags)) |
| { |
| PRInt32 osfd; |
| bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); |
| PR_ASSERT(NULL != bottom); |
| |
| osfd = bottom->secret->md.osfd; |
| |
| if (FD_ISSET(osfd, &rd)) |
| { |
| if (pd->out_flags & _PR_POLL_READ_SYS_READ) |
| out_flags |= PR_POLL_READ; |
| if (pd->out_flags & _PR_POLL_WRITE_SYS_READ) |
| out_flags |= PR_POLL_WRITE; |
| } |
| if (FD_ISSET(osfd, &wt)) |
| { |
| if (pd->out_flags & _PR_POLL_READ_SYS_WRITE) |
| out_flags |= PR_POLL_READ; |
| if (pd->out_flags & _PR_POLL_WRITE_SYS_WRITE) |
| out_flags |= PR_POLL_WRITE; |
| } |
| if (FD_ISSET(osfd, &ex)) out_flags |= PR_POLL_EXCEPT; |
| |
| /* Workaround for nonblocking connects under net_server */ |
| #ifndef BONE_VERSION |
| if (out_flags) |
| { |
| /* check if it is a pending connect */ |
| int i = 0, j = 0; |
| PR_Lock( _connectLock ); |
| for( i = 0; i < connectCount; i++ ) |
| { |
| if(connectList[i].osfd == osfd) |
| { |
| int connectError; |
| int connectResult; |
| |
| connectResult = connect(connectList[i].osfd, |
| &connectList[i].addr, |
| connectList[i].addrlen); |
| connectError = errno; |
| |
| if(connectResult < 0 ) |
| { |
| if(connectError == EINTR || connectError == EWOULDBLOCK || |
| connectError == EINPROGRESS || connectError == EALREADY) |
| { |
| break; |
| } |
| } |
| |
| if(i == (connectCount - 1)) |
| { |
| connectList[i].osfd = -1; |
| } else { |
| for(j = i; j < connectCount; j++ ) |
| { |
| memcpy( &connectList[j], &connectList[j+1], |
| sizeof(connectList[j])); |
| } |
| } |
| connectCount--; |
| |
| bottom->secret->md.connectReturnValue = connectResult; |
| bottom->secret->md.connectReturnError = connectError; |
| bottom->secret->md.connectValueValid = PR_TRUE; |
| break; |
| } |
| } |
| PR_Unlock( _connectLock ); |
| } |
| #endif |
| } |
| pd->out_flags = out_flags; |
| if (out_flags) ready++; |
| } |
| PR_ASSERT(ready > 0); |
| } |
| else if (ready < 0) |
| { |
| err = _MD_ERRNO(); |
| if (err == EBADF) |
| { |
| /* Find the bad fds */ |
| ready = 0; |
| for (pd = pds, epd = pd + npds; pd < epd; pd++) |
| { |
| pd->out_flags = 0; |
| if ((NULL != pd->fd) && (0 != pd->in_flags)) |
| { |
| bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); |
| if (fcntl(bottom->secret->md.osfd, F_GETFL, 0) == -1) |
| { |
| pd->out_flags = PR_POLL_NVAL; |
| ready++; |
| } |
| } |
| } |
| PR_ASSERT(ready > 0); |
| } |
| else _PR_MD_MAP_SELECT_ERROR(err); |
| } |
| |
| return ready; |
| } /* _MD_pr_poll */ |
| |
| /* |
| * File locking. |
| */ |
| |
| PRStatus |
| _MD_lockfile (PRInt32 osfd) |
| { |
| PRInt32 rv; |
| struct flock linfo; |
| |
| linfo.l_type = |
| linfo.l_whence = SEEK_SET; |
| linfo.l_start = 0; |
| linfo.l_len = 0; |
| |
| rv = fcntl(osfd, F_SETLKW, &linfo); |
| if (rv == 0) |
| return PR_SUCCESS; |
| |
| _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO()); |
| return PR_FAILURE; |
| } |
| |
| PRStatus |
| _MD_tlockfile (PRInt32 osfd) |
| { |
| PRInt32 rv; |
| struct flock linfo; |
| |
| linfo.l_type = |
| linfo.l_whence = SEEK_SET; |
| linfo.l_start = 0; |
| linfo.l_len = 0; |
| |
| rv = fcntl(osfd, F_SETLK, &linfo); |
| if (rv == 0) |
| return PR_SUCCESS; |
| |
| _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO()); |
| return PR_FAILURE; |
| } |
| |
| PRStatus |
| _MD_unlockfile (PRInt32 osfd) |
| { |
| PRInt32 rv; |
| struct flock linfo; |
| |
| linfo.l_type = |
| linfo.l_whence = SEEK_SET; |
| linfo.l_start = 0; |
| linfo.l_len = 0; |
| |
| rv = fcntl(osfd, F_UNLCK, &linfo); |
| |
| if (rv == 0) |
| return PR_SUCCESS; |
| |
| _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO()); |
| return PR_FAILURE; |
| } |
| |