pike.git / src / modules / _Stdio / file.c

version» Context lines:

pike.git/src/modules/_Stdio/file.c:77: Inside #if defined(HAVE_WINSOCK_H) || defined(HAVE_WINSOCK2_H)
  #ifndef EWOULDBLOCK   #define EWOULDBLOCK WSAEWOULDBLOCK   #endif   #ifndef EADDRINUSE   #define EADDRINUSE WSAEADDRINUSE   #endif   #endif      #ifdef HAVE_SYS_STREAM_H   #include <sys/stream.h> -  - /* Ugly patch for AIX 3.2 */ - #ifdef u - #undef u +    #endif    - #endif -  +    #ifdef HAVE_SYS_PROTOSW_H   #include <sys/protosw.h>   #endif      #ifdef HAVE_SYS_SOCKETVAR_H   #include <sys/socketvar.h>   #endif      /* Fix warning on OSF/1    *
pike.git/src/modules/_Stdio/file.c:125:   #define THIS ((struct my_file *)(Pike_fp->current_storage))   #define FD (THIS->box.fd)   #define ERRNO (THIS->my_errno)      #define READ_BUFFER 8192   #define DIRECT_BUFSIZE (64*1024)   #define SMALL_NETBUF 2048   #define INUSE_BUSYWAIT_DELAY 0.01   #define INUSE_TIMEOUT 0.1    - /* Don't try to use socketpair() on AmigaOS, socketpair_ultra works better */ - #ifdef __amigaos__ - #undef HAVE_SOCKETPAIR - #endif -  +    #ifdef UNIX_SOCKETS_WORK_WITH_SHUTDOWN   #undef UNIX_SOCKET_CAPABILITIES   #define UNIX_SOCKET_CAPABILITIES (fd_INTERPROCESSABLE | fd_BIDIRECTIONAL | fd_CAN_NONBLOCK | fd_CAN_SHUTDOWN | fd_SEND_FD)   #endif      #ifndef HAVE_DIRFD   #ifdef HAVE_DIR_DD_FD   #define dirfd(dir__) (((DIR*)dir__)->dd_fd)   #define HAVE_DIRFD   #elif defined(HAVE_DIR_D_FD)
pike.git/src/modules/_Stdio/file.c:446: Inside #if defined(PIKE_DEBUG)
   /* Don't cause a fatal when opening fds by number    * if the fd belongs to a backend... */    if ((fd >= 0) && !(flags & FILE_NOT_OPENED))    debug_check_fd_not_in_use (fd);   #endif    change_fd_for_box(&THIS->box, fd);   }      /* Use ptrdiff_t for the fd since we're passed a void * and should    * read it as an integer of the same size. */ - static void do_close_fd(ptrdiff_t fd) + static int do_close_fd(ptrdiff_t fd)   {    int ret; -  if (fd < 0) return; +  int preve; +  if (fd < 0) return 0; +  errno = 0;    do { -  +  preve = errno;    ret = fd_close(fd);    } while ((ret == -1) && (errno == EINTR)); -  +  if ((ret == -1) && preve) return 0; +  return ret;   }      #ifdef HAVE_PIKE_SEND_FD   /* Close the queued fds in fd_info, either due to them being successfully    * sent, or due to the connection being closed. */   static void do_close_fd_info(int *fd_info)   {    int num_fds = fd_info[1];    int *fds = fd_info + 2;    while (num_fds) {
pike.git/src/modules/_Stdio/file.c:554: Inside #if defined(HAVE_PIKE_SEND_FD)
  #ifdef HAVE_PIKE_SEND_FD    if (THIS->fd_info) do_close_fd_info(THIS->fd_info);   #endif       for (ev = 0; ev < NELEM (THIS->event_cbs); ev++) {    free_svalue(& THIS->event_cbs[ev]);    SET_SVAL(THIS->event_cbs[ev], PIKE_T_INT, NUMBER_NUMBER, integer, 0);    }   }    - static void close_fd_quietly(void) + static void close_fd(int quiet)   {    int fd=FD; -  +  int olde = 0;    if(fd<0) return;       free_fd_stuff();    SUB_FD_EVENTS (THIS, ~0); -  +  /* NB: The fd will always be closed on return from fd_close() +  * (except for the EINTR case on eg HPUX). +  */    change_fd_for_box (&THIS->box, -1);    -  +  if ( (THIS->flags & FILE_NOT_OPENED) ) +  return; +     while(1)    {    int i, e;    THREADS_ALLOW_UID();    i=fd_close(fd);    e=errno;    THREADS_DISALLOW_UID();    -  +  /* fprintf(stderr, "fd_close(%d): ret: %d, errno: %d\n", fd, i, e); */ +     check_threads_etc();       if(i < 0)    { -  +  ERRNO = errno = e;    switch(e)    { -  default: { +  default: +  push_int(e); +  f_strerror(1); +  +  if (quiet) { +  /* NB: FIXME: This has quite a bit of overhead... */    JMP_BUF jmp;    if (SETJMP (jmp))    call_handle_error();    else { -  ERRNO=errno=e; -  change_fd_for_box (&THIS->box, fd); -  push_int(e); -  f_strerror(1); +     Pike_error("Failed to close file: %S\n", Pike_sp[-1].u.string);    }    UNSETJMP (jmp); -  break; +  } else { +  Pike_error("Failed to close file: %S\n", Pike_sp[-1].u.string);    } -  -  case EBADF: +     break;    - #ifdef SOLARIS -  /* It's actually OK. This is a bug in Solaris 8. */ -  case EAGAIN: + #if 0 + #ifdef ENOSPC +  case ENOSPC: +  /* FreeBSD: The underlying object did not fit, cached data was lost. */    break;   #endif -  -  case EINTR: -  continue; -  } -  } + #endif + #ifdef ECONNRESET +  case ECONNRESET: +  /* FreeBSD: The peer shut down the connection before all pending data +  * was delivered. +  */    break; -  } - } + #endif    - static void close_fd(void) - { -  int fd=FD; -  if(fd<0) return; -  -  free_fd_stuff(); -  SUB_FD_EVENTS (THIS, ~0); -  change_fd_for_box (&THIS->box, -1); -  -  if ( (THIS->flags & FILE_NOT_OPENED) ) -  return; -  -  while(1) -  { -  int i, e; -  THREADS_ALLOW_UID(); -  i=fd_close(fd); -  e=errno; -  THREADS_DISALLOW_UID(); -  -  check_threads_etc(); -  -  if(i < 0) -  { -  switch(e) -  { -  default: -  ERRNO=errno=e; -  change_fd_for_box (&THIS->box, fd); -  push_int(e); -  f_strerror(1); -  Pike_error("Failed to close file: %S\n", Pike_sp[-1].u.string); -  break; -  +     case EBADF: -  +  if (olde) { +  /* Probably an OS where fds are closed on EINTR (ie most). */ +  ERRNO = errno = 0; +  break; +  }    Pike_error("Internal error: Closing a non-active file descriptor %d.\n",fd);    break;      #ifdef SOLARIS    /* It's actually OK. This is a bug in Solaris 8. */    case EAGAIN:    break;   #endif -  +     case EINTR: -  +  olde = e;    continue;    }    }    break;    }   }      void my_set_close_on_exec(int fd, int to)   {    set_close_on_exec(fd, to);
pike.git/src/modules/_Stdio/file.c:733:    case FILE_READ | FILE_WRITE: ret=fd_RDWR; break;    }    if(flags & FILE_APPEND) ret|=fd_APPEND;    if(flags & FILE_CREATE) ret|=fd_CREAT;    if(flags & FILE_TRUNC) ret|=fd_TRUNC;    if(flags & FILE_EXCLUSIVE) ret|=fd_EXCL;    ret |= fd_LARGEFILE;    return ret;   }    + /* read only once */ + #define PIKE_READ_ONCE 1U +  + /* ignore the number of bytes, read as much as possible. +  * count is used as the numer of bytes read per call +  * to read(2). */ + #define PIKE_READ_NO_LENGTH 2U +    static struct pike_string *do_read(int fd, -  INT32 r, -  int all, +  size_t count, +  unsigned int mode,    INT_TYPE *err)   { -  size_t bytes = r; +     struct byte_buffer buf = BUFFER_INIT();    int e = 0;       buffer_set_flags(&buf, BUFFER_GROW_EXACT);    -  +  while (1) { +     THREADS_ALLOW();    -  while (bytes) { -  size_t len = MINIMUM(DIRECT_BUFSIZE, bytes); -  ptrdiff_t i; +  while (count) { +  size_t len = MINIMUM(DIRECT_BUFSIZE, count); +  ptrdiff_t bytes_read;    -  /* make space for exactly len bytes plus the terminating null byte */ +  /* make space for exactly len bytes plus the terminating null byte. */ +  /* NOTE: as long as count comes from pike, it was signed, i.e. len+1 +  * cannot overflow */    if (UNLIKELY(!buffer_ensure_space_nothrow(&buf, len+1))) { -  buffer_free(&buf); +     e = ENOMEM;    break;    }    -  i = fd_read(fd, buffer_alloc_unsafe(&buf, len), len); +  bytes_read = fd_read(fd, buffer_alloc_unsafe(&buf, len), len);    -  if (LIKELY(i >= 0)) { -  if ((size_t)i < len) buffer_remove(&buf, len - i); -  bytes -= i; -  if (!i || !all) break; +  if (LIKELY(bytes_read >= 0)) { +  /* if less than len were read, rewind the buffer to +  * the last byte */ +  if ((size_t)bytes_read < len) +  buffer_remove(&buf, len - bytes_read); +  +  if (!(mode & PIKE_READ_NO_LENGTH)) +  count -= bytes_read; +  +  if (!bytes_read || mode & PIKE_READ_ONCE) break;    } else {    e=errno; -  +  buffer_remove(&buf, len); +  break; +  } +  } +  +  THREADS_DISALLOW(); +  +  check_threads_etc(); +     if (e == EINTR) {    e = 0; -  buffer_remove(&buf, len); +     continue;    }    -  buffer_free(&buf); +     break;    } -  +  +  if (e && !buffer_content_length(&buf)) { +  buffer_free(&buf); +  *err = e; +  return NULL;    }    -  THREADS_DISALLOW(); +  if(!SAFE_IS_ZERO(& THIS->event_cbs[PIKE_FD_READ])) +  ADD_FD_EVENTS (THIS, PIKE_BIT_FD_READ);    -  +  return buffer_finish_pike_string(&buf); + } +  + static ptrdiff_t do_read_into_buffer(int fd, +  void * ptr, +  size_t len, +  INT_TYPE *err) + { +  int e; +  ptrdiff_t bytes_read; +  +  do { +  e = 0; +  bytes_read = fd_read(fd, ptr, len); +  +  if (UNLIKELY(bytes_read == 0)) { +  e=errno; +  } +     check_threads_etc(); -  +  } while (e == EINTR);    -  if (e) { +  if (e && !bytes_read) {    *err = e; -  return NULL; +  return -1;    }       if(!SAFE_IS_ZERO(& THIS->event_cbs[PIKE_FD_READ]))    ADD_FD_EVENTS (THIS, PIKE_BIT_FD_READ);    -  return buffer_finish_pike_string(&buf); +  return bytes_read;   }      /* This function is used to analyse anonymous fds, so that    * my_file->open_mode can be set properly. */   static int low_fd_query_properties(int fd)   {    struct stat st;    PIKE_SOCKADDR addr;    ACCEPT_SIZE_T len;    int i;
pike.git/src/modules/_Stdio/file.c:963:   #else    receive_fds((int *)msg->msg_accrights, msg->msg_accrightslen/sizeof(int));   #endif   }      #ifndef HAVE_STRUCT_MSGHDR_MSG_CONTROL   /* BSD */   #define CMSG_LEN(x) (x)   #endif    - static struct pike_string *do_recvmsg(INT32 r, int all) + static struct pike_string *do_recvmsg(int fd, size_t count, unsigned INT32 mode, INT_TYPE *err)   { -  ONERROR ebuf; -  ptrdiff_t bytes_read = 0, i; -  int fd = FD; +     struct {    struct msghdr msg;    struct iovec iov;    char cmsgbuf[CMSG_LEN(sizeof(int)*128)];    } message; -  +  struct byte_buffer buf = BUFFER_INIT(); +  int e = 0; +  ptrdiff_t bytes_read = 0;    -  ERRNO=0; -  +     message.msg.msg_name = NULL;    message.msg.msg_namelen = 0;    message.msg.msg_iov = &message.iov;    message.msg.msg_iovlen = 1;   #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL    /* XPG 4.2 */    message.msg.msg_flags = 0;   #endif    -  { -  /* For some reason, 8k seems to work faster than 64k. -  * (4k seems to be about 2% faster than 8k when using linux though) -  * /Hubbe (Per pointed it out to me..) -  */ -  struct byte_buffer b = BUFFER_INIT(); +  buffer_set_flags(&buf, BUFFER_GROW_EXACT);    -  buffer_set_flags(&b, BUFFER_GROW_EXACT); +  while (1) {    -  /* for small reads we allocate the whole size in the beginning, -  * instead of only by individual chunks. We may want to change -  * what small means. -  */ -  if (r < 65*1024) buffer_ensure_space(&b, r+1); +  THREADS_ALLOW();    -  SET_ONERROR(ebuf, buffer_free, &b); -  do{ -  int e; -  const INT32 CHUNK = 1024 * 8; -  INT32 try_read=MINIMUM(CHUNK,r); +  while (count) { +  size_t len = MINIMUM(DIRECT_BUFSIZE, count);    -  /* allocate try_read bytes + the trailing null byte */ -  buffer_ensure_space(&b, try_read+1); +  /* make space for exactly len bytes plus the terminating null byte */ +  /* as long as count comes from pike, it was signed, i.e. len+1 is safe */ +  if (UNLIKELY(!buffer_ensure_space_nothrow(&buf, len+1))) { +  e = ENOMEM; +  break; +  }      #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL    message.msg.msg_control = &message.cmsgbuf;    message.msg.msg_controllen = sizeof(message.cmsgbuf);   #else    message.msg.msg_accrights = (void *)&message.cmsgbuf;    message.msg.msg_accrightslen = sizeof(message.cmsgbuf);   #endif -  message.iov.iov_base = buffer_alloc(&b, try_read); -  message.iov.iov_len = try_read; +  message.iov.iov_base = buffer_alloc_unsafe(&buf, len); +  message.iov.iov_len = len;    -  THREADS_ALLOW(); -  i = recvmsg(fd, &message.msg, 0); +  bytes_read = recvmsg(fd, &message.msg, 0);    e=errno; -  THREADS_DISALLOW(); +     -  check_threads_etc(); +  if (LIKELY(bytes_read >= 0)) { +  /* if less than len were read, rewind the buffer to +  * the last byte */ +  if ((size_t)bytes_read < len) +  buffer_remove(&buf, len - bytes_read);    -  if(i>0) -  { -  bytes_read+=i; -  r-=i; +  if (!(mode & PIKE_READ_NO_LENGTH)) +  count -= bytes_read; +  +  if (!bytes_read || mode & PIKE_READ_ONCE) break; +     if (   #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL    message.msg.msg_controllen   #else    message.msg.msg_accrightslen   #endif    ) { -  check_message(&message.msg); +  /* we have to call receive_fds, so break out of the loop */ +  break;    } -  if (i != try_read) { -  buffer_remove(&b, try_read - i); +  } else { +  e=errno; +  buffer_remove(&buf, len); +  break;    } -  if(!all) break; +     } -  else if(i==0) -  { -  buffer_remove(&b, try_read); +  +  THREADS_DISALLOW(); +  +  check_threads_etc(); +  +  if (e) { +  if (e == EINTR) { +  e = 0; +  continue; +  }    break;    } -  else -  { -  buffer_remove(&b, try_read); -  if(e != EINTR) -  { -  ERRNO=e; -  if(!bytes_read) -  { -  buffer_free(&b); +  +  if (UNLIKELY( + #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL +  message.msg.msg_controllen + #else +  message.msg.msg_accrightslen + #endif +  )) { +  ONERROR ebuf; +  SET_ONERROR(ebuf, buffer_free, &buf); +  check_message(&message.msg);    UNSET_ONERROR(ebuf); -  return 0; +  if (bytes_read && !(mode & PIKE_READ_ONCE)) continue;    }    break;    } -  } -  }while(r); +     -  UNSET_ONERROR(ebuf); -  +     if(!SAFE_IS_ZERO(& THIS->event_cbs[PIKE_FD_READ]))    ADD_FD_EVENTS (THIS, PIKE_BIT_FD_READ);    -  return buffer_finish_pike_string(&b); +  if (e) { +  *err = e; +  +  if (!buffer_content_length(&buf)) { +  buffer_free(&buf); +  return NULL;    }    }    -  +  return buffer_finish_pike_string(&buf); + } +    /* Send a set of iovecs and fds over an fd. */   static int writev_fds(int fd, struct iovec *iov, int iovcnt,    int *fds, int num_fds)   {    int retval, e;    struct msghdr msg;   #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL    /* XPG 4.2 */      #ifndef CMSG_SPACE
pike.git/src/modules/_Stdio/file.c:1132: Inside #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
   e = errno;    free(cmsg);    errno = e;   #endif    return retval;   }      #endif /* HAVE_PIKE_SEND_FD */      static struct pike_string *do_read_oob(int UNUSED(fd), -  INT32 r, +  ptrdiff_t r,    int all,    INT_TYPE *err)   {    ONERROR ebuf;    INT32 bytes_read,i;    struct pike_string *str;       bytes_read=0;    *err=0;   
pike.git/src/modules/_Stdio/file.c:1260:    *!    *! @note    *! When at the end of a file or stream, repeated calls to @[read()]    *! will return the empty string since it's not considered an error.    *! The empty string is never returned in other cases, unless nonblocking    *! mode is used or @[len] is zero.    *!    *! @seealso    *! @[read_oob()], @[write()], @[receive_fd()], @[send_fd()]    */ +  + /*! +  *! @decl int read(Stdio.Buffer|String.Buffer dst) +  *! +  *! Reads data from a file or stream into the buffer @[dst]. Tries to +  *! read as many bytes as buffer space available. +  *! Will advance the write position in @[dst] by the number of bytes +  *! read. +  *! +  *! @returns +  *! The number of bytes read. Returns @expr{-1@} on error and +  *! @[errno()] will return the corresponding error code. +  */ +  + /*! +  *! @decl int read(System.Memory dst, void|int(0..) offset) +  *! +  *! Reads data from a file or stream into the buffer @[dst] at offset +  *! @[offset]. Tries to read as many bytes as buffer space available. +  *! +  *! @returns +  *! The number of bytes read. Returns @expr{-1@} on error and +  *! @[errno()] will return the corresponding error code. +  */   static void file_read(INT32 args)   { -  struct pike_string *tmp; -  INT32 all, len; +  struct my_file *file = THIS;    -  if(FD < 0) +  int fd = file->box.fd; +  +  if(fd < 0)    Pike_error("File not open.\n");    -  +  if (args && TYPEOF(Pike_sp[-args]) == PIKE_T_OBJECT) { +  struct pike_memory_object m; +  struct object *o = Pike_sp[-args].u.object; +  enum memobj_type type = pike_get_memory_object(o, &m, 1); +  ptrdiff_t bytes_read; +  +  if (type == MEMOBJ_NONE) +  SIMPLE_BAD_ARG_ERROR("read()", 1, "int(0..)|Stdio.Buffer|String.Buffer|System.Memory"); +  +  if (m.shift) +  Pike_error("Cannot read into wide-string buffer.\n"); +  +  if (args > 1) +  { +  INT_TYPE offset; +  +  if (TYPEOF(Pike_sp[-args+1]) != PIKE_T_INT || Pike_sp[-args+1].u.integer < 0) +  SIMPLE_BAD_ARG_ERROR("read()", 2, "int(0..)"); +  +  if (type != MEMOBJ_SYSTEM_MEMORY) +  SIMPLE_BAD_ARG_ERROR("read()", 1, "System.Memory"); +  +  offset = Pike_sp[-args+1].u.integer; +  +  if ((size_t)offset > m.len) +  Pike_error("Offset out of bounds.\n"); +  +  m.len -= offset; +  m.ptr = (char*)m.ptr + offset; +  } +  +  if (!m.len) +  Pike_error("No buffer space.\n"); +  +  bytes_read = do_read_into_buffer(fd, m.ptr, (size_t)m.len, &file->my_errno); +  +  if (bytes_read > 0) +  pike_advance_memory_object(o, type, bytes_read); +  +  pop_n_elems(args); +  push_int(bytes_read); +  } else { +  struct pike_string *tmp; +  unsigned INT32 mode = 0; +  size_t count = DIRECT_BUFSIZE; +     if(!args)    { -  len=0x7fffffff; +  mode |= PIKE_READ_NO_LENGTH;    }    else    { -  +  INT_TYPE len;    if(TYPEOF(Pike_sp[-args]) != PIKE_T_INT)    SIMPLE_ARG_TYPE_ERROR("read", 1, "int");    len=Pike_sp[-args].u.integer;    if(len<0)    Pike_error("Cannot read negative number of characters.\n");    if (!len && SUBTYPEOF(Pike_sp[-args])) { -  len = 0x7fffffff; +  mode |= PIKE_READ_NO_LENGTH; +  } else { +  count = len;    }    }       if(args > 1 && !UNSAFE_IS_ZERO(Pike_sp+1-args))    { -  all=0; -  }else{ -  all=1; +  mode |= PIKE_READ_ONCE;    }       pop_n_elems(args);      #ifdef HAVE_PIKE_SEND_FD    /* Check if there's any need to use recvmsg(2). */ -  if ((THIS->open_mode & fd_SEND_FD) && -  (THIS->flags & FILE_HAVE_RECV_FD)) { -  if ((tmp = do_recvmsg(len, all))) +  if ((file->open_mode & fd_SEND_FD) && +  (file->flags & FILE_HAVE_RECV_FD)) { +  if ((tmp = do_recvmsg(fd, count, mode, & file->my_errno)))    push_string(tmp);    else { -  errno = ERRNO; +  errno = file->my_errno;    push_int(0);    }    } else   #endif /* HAVE_PIKE_SEND_FD */ -  if((tmp=do_read(FD, len, all, & ERRNO))) +  { +  if((tmp=do_read(fd, count, mode, & file->my_errno)))    push_string(tmp);    else { -  errno = ERRNO; +  errno = file->my_errno;    push_int(0);    } -  +  } +  }    -  if (!(THIS->open_mode & FILE_NONBLOCKING)) +  if (!(file->open_mode & FILE_NONBLOCKING))    INVALIDATE_CURRENT_TIME();       /* Race: A backend in another thread might have managed to set these    * again for something that arrived after the read above. Not that    * bad - it will get through in a later backend round. */ -  THIS->box.revents &= ~(PIKE_BIT_FD_READ|PIKE_BIT_FD_READ_OOB); +  file->box.revents &= ~(PIKE_BIT_FD_READ|PIKE_BIT_FD_READ_OOB);   }      #ifdef HAVE_AND_USE_POLL   #ifdef HAVE_POLL_H   #include <poll.h>   #else /* !HAVE_POLL_H */   #ifdef HAVE_SYS_POLL_H   #include <sys/poll.h>   #else /* !HAVE_SYS_POLL_H */   #undef HAVE_AND_USE_POLL
pike.git/src/modules/_Stdio/file.c:1394:    *! The function may be interrupted prematurely    *! of the timeout (due to signals);    *! check the timing manually if this is imporant.    */   static void file_peek(INT32 args)   {    int ret;    int not_eof = 0;    FLOAT_TYPE tf = 0.0;    -  get_all_args("peek",args,".%F%d",&tf,&not_eof); +  get_all_args(NULL, args, ".%F%d", &tf, &not_eof);       {   #ifdef HAVE_AND_USE_POLL    struct pollfd fds;    int timeout = 0;    if (args && !IS_UNDEFINED(Pike_sp - args)) {    timeout = (int)(tf*1000); /* ignore overflow for now */    }    fds.fd=FD;    fds.events=POLLIN;
pike.git/src/modules/_Stdio/file.c:1686:   #endif       SUB_FD_EVENTS (f, ~0);   }         /*! @decl int write(string data)    *! @decl int write(string format, mixed ... extras)    *! @decl int write(array(string) data)    *! @decl int write(array(string) format, mixed ... extras) +  *! @decl int write(Stdio.Buffer|String.Buffer|System.Memory data, void|int(0..) offset)    *!    *! Write data to a file or a stream.    *!    *! If there are any file descriptors that have been queued for sending    *! (with @[send_fd()]), they will be sent.    *!    *! @param data    *! Data to write.    *!    *! If @[data] is an array of strings, they are written in sequence.    *!    *! @param format    *! @param extras    *! If more than one argument is given, @[sprintf()] is used to format    *! them using @[format]. If @[format] is an array, the strings in it    *! are concatenated and the result is used as format string.    *! -  +  *! @param offset +  *! The offset in data to start writing from. +  *!    *! @returns    *! Writes @[data] and returns the number of bytes that were    *! actually written.    *!    *! @int    *! @value 1..    *! The number of bytes successfully written to the OS buffers.    *!    *! This can be less than the size of the given data if eg:    *! @ul
pike.git/src/modules/_Stdio/file.c:1749:    *! @endint    *!    *! If everything went fine, a call to @[errno()] directly afterwards    *! returns zero.    *!    *! @note    *! Writing of wide strings is not supported. You have to encode the    *! data somehow, e.g. with @[string_to_utf8] or with one of the    *! charsets supported by @[Charset.encoder].    *! +  *! @note +  *! The variant of this function using a buffer object does not release +  *! the interpreter lock. +  *!    *! @seealso    *! @[read()], @[write_oob()], @[send_fd()]    */ - static void file_write(INT32 args) + #ifdef HAVE_WRITEV + static ptrdiff_t file_write_array(struct my_file *file, struct array *a)   {    ptrdiff_t written, i; -  struct pike_string *str; +  struct iovec *iovbase = xalloc(sizeof(struct iovec)*a->size); +  struct iovec *iov = iovbase; +  int iovcnt = a->size; +  int e = 0;    -  if(args<1 || ((TYPEOF(Pike_sp[-args]) != PIKE_T_STRING) && -  (TYPEOF(Pike_sp[-args]) != PIKE_T_ARRAY))) -  SIMPLE_ARG_TYPE_ERROR("write", 1, "string|array(string)"); -  -  if(FD < 0) -  Pike_error("File not open for write.\n"); -  -  if (TYPEOF(Pike_sp[-args]) == PIKE_T_ARRAY) { -  struct array *a = Pike_sp[-args].u.array; -  -  if( (a->type_field & ~BIT_STRING) && -  (array_fix_type_field(a) & ~BIT_STRING) ) -  SIMPLE_ARG_TYPE_ERROR("write", 1, "string|array(string)"); -  +     i = a->size; -  while(i--) -  if (a->item[i].u.string->size_shift) +  while(i--) { +  struct pike_string *s = a->item[i].u.string; +  +  if (s->size_shift) { +  free(iovbase);    Pike_error("Bad argument 1 to file->write().\n"    "Element %ld is a wide string.\n",    (long)i); -  - #ifdef HAVE_WRITEV -  if (args > 1) { - #endif /* HAVE_WRITEV */ -  ref_push_array(a); -  push_empty_string(); -  o_multiply(); -  Pike_sp--; -  dmalloc_touch_svalue(Pike_sp); -  Pike_sp[-args] = *Pike_sp; -  free_array(a); -  - #ifdef PIKE_DEBUG -  if (TYPEOF(Pike_sp[-args]) != PIKE_T_STRING) { -  Pike_error("Bad return value from string multiplication.\n"); +     } - #endif /* PIKE_DEBUG */ - #ifdef HAVE_WRITEV -  } else if (!a->size) { -  /* Special case for empty array */ -  ERRNO = 0; -  pop_stack(); -  push_int(0); -  return; -  } else { -  struct iovec *iovbase = xalloc(sizeof(struct iovec)*a->size); -  struct iovec *iov = iovbase; -  int iovcnt = a->size; +     -  if (!(THIS->open_mode & FILE_NONBLOCKING)) -  INVALIDATE_CURRENT_TIME(); -  -  i = a->size; -  while(i--) { -  if (a->item[i].u.string->len) { -  iov[i].iov_base = a->item[i].u.string->str; -  iov[i].iov_len = a->item[i].u.string->len; +  if (s->len) { +  iov[i].iov_base = s->str; +  iov[i].iov_len = s->len;    } else {    iov++;    iovcnt--;    }    }       for(written = 0; iovcnt; check_signals(0,0,0)) { -  int fd = FD; -  int e; +  int fd = file->box.fd;    int cnt = iovcnt;   #ifdef HAVE_PIKE_SEND_FD    int *fd_info = NULL;    int num_fds = 0; -  if (THIS->fd_info && (num_fds = THIS->fd_info[1])) { -  fd_info = THIS->fd_info; -  THIS->fd_info = NULL; + #endif +  + #ifdef _REENTRANT +  /* check_signals() may have done something... */ +  if (fd < 0) break; + #endif +  + #ifdef HAVE_PIKE_SEND_FD +  if (file->fd_info && (num_fds = file->fd_info[1])) { +  fd_info = file->fd_info; +  file->fd_info = NULL;    }   #endif    THREADS_ALLOW();      #ifdef IOV_MAX    if (cnt > IOV_MAX) cnt = IOV_MAX;   #endif      #ifdef MAX_IOVEC    if (cnt > MAX_IOVEC) cnt = MAX_IOVEC;   #endif   #ifdef HAVE_PIKE_SEND_FD    if (fd_info) {    i = writev_fds(fd, iov, cnt, fd_info + 2, num_fds);    } else   #endif    i = writev(fd, iov, cnt); -  +  +  if (i < 0) e = errno; +     THREADS_DISALLOW();       /* fprintf(stderr, "writev(%d, 0x%08x, %d) => %d\n",    fd, (unsigned int)iov, cnt, i); */    -  e=errno; /* check_threads_etc may effect errno */ +     check_threads_etc();       if(i<0)    {   #ifdef HAVE_PIKE_SEND_FD    if (fd_info) {    restore_fd_info(fd_info);    }   #endif    switch(e)    { -  default: -  free(iovbase); -  ERRNO=errno=e; -  pop_n_elems(args); -  if (!written) { -  push_int(-1); -  } else { -  push_int(written); -  } -  /* Minor race - see below. */ -  THIS->box.revents &= ~(PIKE_BIT_FD_WRITE|PIKE_BIT_FD_WRITE_OOB); -  return; -  +  default: break;    case EINTR: continue; -  case EWOULDBLOCK: break; +  case EWOULDBLOCK: +  e = 0; +  break;    /* FIXME: Special case for ENOTSOCK? */    }    break;    }else{    written += i;      #ifdef HAVE_PIKE_SEND_FD    if (fd_info) { -  THIS->fd_info = fd_info; +  file->fd_info = fd_info;    if (i) { -  do_close_fd_info(THIS->fd_info = fd_info); +  do_close_fd_info(file->fd_info = fd_info);    }    }   #endif       /* Avoid extra writev() */    if(THIS->open_mode & FILE_NONBLOCKING)    break;       while(i) {    if ((ptrdiff_t)iov->iov_len <= i) {
pike.git/src/modules/_Stdio/file.c:1911: Inside #if defined(HAVE_WRITEV)
   iov++;    iovcnt--;    } else {    /* Use cast since iov_base might be a void pointer */    iov->iov_base = ((char *) iov->iov_base) + i;    iov->iov_len -= i;    i = 0;    }    }    } - #ifdef _REENTRANT -  if (FD<0) { +  } +     free(iovbase); -  Pike_error("File closed while in file->write.\n"); +  +  file->my_errno = errno = e; +  +  return written;   } -  + #endif /* HAVE_WRITEV */ +  + static ptrdiff_t file_write_buffer(struct my_file *file, void *ptr, size_t len) + { +  ptrdiff_t written; +  int e = 0; +  +  for(written=0;(size_t)written < len;check_signals(0,0,0)) +  { +  int fd=file->box.fd; +  int i; +  void *start = (char*)ptr + written; + #ifdef HAVE_PIKE_SEND_FD +  int *fd_info = NULL; +  int num_fds = 0;   #endif -  } +     -  free(iovbase); + #ifdef _REENTRANT +  /* check_signals() may have done something... */ +  if (fd < 0) break; + #endif    -  /* Minor race - see below. */ -  THIS->box.revents &= ~(PIKE_BIT_FD_WRITE|PIKE_BIT_FD_WRITE_OOB); + #ifdef HAVE_PIKE_SEND_FD + /* fprintf(stderr, "fd_info: %p\n", file->fd_info); */ +  if (file->fd_info && (num_fds = file->fd_info[1])) { +  fd_info = file->fd_info; +  file->fd_info = NULL; +  } + #endif + #ifdef HAVE_PIKE_SEND_FD +  if (fd_info) { +  struct iovec iov; +  iov.iov_base = start; +  iov.iov_len = len - written; +  i = writev_fds(fd, &iov, 1, fd_info + 2, num_fds); +  } else + #endif +  i=fd_write(fd, start, len - written); +  if (i < 0 ) e = errno;    -  if(!SAFE_IS_ZERO(& THIS->event_cbs[PIKE_FD_WRITE])) -  ADD_FD_EVENTS (THIS, PIKE_BIT_FD_WRITE); -  ERRNO=0; +  if(i<0) +  { + #ifdef HAVE_PIKE_SEND_FD +  if (fd_info) { +  restore_fd_info(fd_info); +  } + #endif +  switch(e) +  { +  default: break; +  case EINTR: continue; +  case EWOULDBLOCK: +  e = 0; +  break; +  /* FIXME: Special case for ENOTSOCK? */ +  } +  break; +  }else{ +  written+=i;    -  pop_stack(); -  push_int(written); -  return; + #ifdef HAVE_PIKE_SEND_FD +  if (i && fd_info) { +  do_close_fd_info(file->fd_info = fd_info);    } - #endif /* HAVE_WRITEV */ + #endif +  /* Avoid extra write() */ +  if(file->open_mode & FILE_NONBLOCKING) +  break;    } -  +  }    -  /* At this point TYPEOF(Pike_sp[-args]) is PIKE_T_STRING */ +  file->my_errno=errno=e;    -  if(args > 1) -  { -  f_sprintf(args); -  args=1; +  return written;   }    -  str=Pike_sp[-args].u.string; + static ptrdiff_t file_write_string(struct my_file *file, struct pike_string *str) + { +  ptrdiff_t written = 0; +  int e = 0; +     if(str->size_shift)    Pike_error("Stdio.File->write(): cannot output wide strings.\n");       for(written=0;written < str->len;check_signals(0,0,0))    { -  int fd=FD; -  int e; +  int fd=file->box.fd; +  int i;   #ifdef HAVE_PIKE_SEND_FD    int *fd_info = NULL;    int num_fds = 0; - /* fprintf(stderr, "fd_info: %p\n", THIS->fd_info); */ -  if (THIS->fd_info && (num_fds = THIS->fd_info[1])) { -  fd_info = THIS->fd_info; -  THIS->fd_info = NULL; + #endif +  + #ifdef _REENTRANT +  /* check_signals() may have done something... */ +  if (fd < 0) break; + #endif +  + #ifdef HAVE_PIKE_SEND_FD + /* fprintf(stderr, "fd_info: %p\n", file->fd_info); */ +  if (file->fd_info && (num_fds = file->fd_info[1])) { +  fd_info = file->fd_info; +  file->fd_info = NULL;    }   #endif -  +     THREADS_ALLOW(); -  +    #ifdef HAVE_PIKE_SEND_FD    if (fd_info) {    struct iovec iov;    iov.iov_base = str->str + written;    iov.iov_len = str->len - written;    i = writev_fds(fd, &iov, 1, fd_info + 2, num_fds);    } else   #endif    i=fd_write(fd, str->str + written, str->len - written); -  e=errno; +  if (i < 0) e = errno;    THREADS_DISALLOW();       check_threads_etc();    -  if (!(THIS->open_mode & FILE_NONBLOCKING)) -  INVALIDATE_CURRENT_TIME(); -  +     if(i<0)    {   #ifdef HAVE_PIKE_SEND_FD    if (fd_info) {    restore_fd_info(fd_info);    }   #endif    switch(e)    { -  default: -  ERRNO=errno=e; -  pop_n_elems(args); -  if (!written) { -  push_int(-1); -  } else { -  push_int64(written); -  } -  /* Minor race - see below. */ -  THIS->box.revents &= ~(PIKE_BIT_FD_WRITE|PIKE_BIT_FD_WRITE_OOB); -  return; -  +  default: break;    case EINTR: continue; -  case EWOULDBLOCK: break; +  case EWOULDBLOCK: +  e = 0; +  break;    /* FIXME: Special case for ENOTSOCK? */    }    break;    }else{    written+=i;      #ifdef HAVE_PIKE_SEND_FD    if (i && fd_info) { -  do_close_fd_info(THIS->fd_info = fd_info); +  do_close_fd_info(file->fd_info = fd_info);    }   #endif    /* Avoid extra write() */ -  if(THIS->open_mode & FILE_NONBLOCKING) +  if(file->open_mode & FILE_NONBLOCKING)    break;    } - #ifdef _REENTRANT -  if(FD<0) Pike_error("File closed while in file->write.\n"); - #endif +     }    -  +  /* Why do we reset errno ? */ +  file->my_errno = errno = e; +  +  return written; + } +  + static void file_write(INT32 args) + { +  enum PIKE_TYPE first_arg = args > 0 ? TYPEOF(Pike_sp[-args]) : T_VOID; +  ptrdiff_t written; +  +  struct my_file *file = THIS; +  +  if(file->box.fd < 0) +  Pike_error("File not open for write.\n"); +  +  if (!(file->open_mode & FILE_NONBLOCKING)) +  INVALIDATE_CURRENT_TIME(); +  +  switch (first_arg) { +  case PIKE_T_ARRAY: +  { +  struct array *a = Pike_sp[-args].u.array; +  +  if (!a->size) { +  file->my_errno = 0; +  written = 0; +  break; +  } +  + #ifdef HAVE_WRITEV +  if (args == 1) +  { +  if( (a->type_field & ~BIT_STRING) && +  (array_fix_type_field(a) & ~BIT_STRING) ) +  SIMPLE_ARG_TYPE_ERROR("write", 1, "string|array(string)"); +  +  written = file_write_array(file, a); +  break; +  } + #endif /* HAVE_WRITEV */ +  ref_push_array(a); +  push_empty_string(); +  o_multiply(); +  Pike_sp--; +  dmalloc_touch_svalue(Pike_sp); +  Pike_sp[-args] = *Pike_sp; +  free_array(a); +  + #ifdef PIKE_DEBUG +  if (TYPEOF(Pike_sp[-args]) != PIKE_T_STRING) { +  Pike_error("Bad return value from string multiplication.\n"); +  } + #endif /* PIKE_DEBUG */ +  } +  /* FALL THROUGH */ +  case PIKE_T_STRING: +  if (args > 1) +  { +  f_sprintf(args); +  args=1; +  } +  written = file_write_string(file, Pike_sp[-args].u.string); +  break; +  case PIKE_T_OBJECT: +  { +  struct object *o = Pike_sp[-args].u.object; +  size_t len; +  int shift; +  void *src; +  +  enum memobj_type type = get_memory_object_memory(o, &src, &len, &shift); +  +  if (type != MEMOBJ_NONE) { +  INT_TYPE offset = 0; +  +  if (shift) +  Pike_error("Stdio.File->write(): cannot output wide strings.\n"); +  +  if (args > 1 && TYPEOF(Pike_sp[-args+1]) == PIKE_T_INT) +  { +  offset = Pike_sp[-args+1].u.integer; +  +  if (UNLIKELY(offset < 0 || (size_t)offset > len)) { +  Pike_error("Offset out of bounds.\n"); +  } +  } +  +  written = file_write_buffer(file, (char*)src + offset, len - offset); +  break; +  } +  } +  /* FALL THROUGH */ +  default: +  SIMPLE_ARG_TYPE_ERROR("write", 1, "string|array(string)|Stdio.Buffer|String.Buffer|System.Memory"); +  } +    #ifdef _REENTRANT -  /* check_signals() may have done something... */ -  if(FD<0) Pike_error("File closed while in file->write.\n"); +  if (file->box.fd < 0) +  Pike_error("File closed while in file->write.\n");   #endif -  +  +  if (!file->my_errno) { +  if(!SAFE_IS_ZERO(& file->event_cbs[PIKE_FD_WRITE])) +  ADD_FD_EVENTS (file, PIKE_BIT_FD_WRITE); +  } else { +  if (!written) written = -1; +  } +     /* Race: A backend in another thread might have managed to set these    * again for buffer space available after the write above. Not that    * bad - it will get through in a later backend round. */ -  THIS->box.revents &= ~(PIKE_BIT_FD_WRITE|PIKE_BIT_FD_WRITE_OOB); +  file->box.revents &= ~(PIKE_BIT_FD_WRITE|PIKE_BIT_FD_WRITE_OOB);    -  if(!SAFE_IS_ZERO(& THIS->event_cbs[PIKE_FD_WRITE])) -  ADD_FD_EVENTS (THIS, PIKE_BIT_FD_WRITE); -  ERRNO=0; -  +     pop_n_elems(args);    push_int64(written);   }      /*! @decl int write_oob(string data)    *! @decl int write_oob(string format, mixed ... extras)    *!    *! Write out-of-band data to a stream.    *!    *! Writes out-of-band data to a stream and returns how many bytes
pike.git/src/modules/_Stdio/file.c:2279: Inside #if defined(SO_LINGER)
   */   static void file_linger(INT32 args)   {    int fd = FD;    int linger = -1;    struct linger li;       if(fd < 0)    Pike_error("File not open.\n");    -  get_all_args("linger", args, ".%d", &linger); +  get_all_args(NULL, args, ".%d", &linger);       if ((linger < -1) || (linger > 0xffff)) {    SIMPLE_ARG_TYPE_ERROR("linger", 1, "int(-1..65535)");    }       if (linger == -1) {    li.l_onoff = 0;    li.l_linger = 15;    } else {    li.l_onoff = 1;
pike.git/src/modules/_Stdio/file.c:2337: Inside #if defined(TCP_NODELAY)
   *! setsockopt()    */   static void file_nodelay(INT32 args)   {    int fd = FD;    int state = 1;       if(fd < 0)    Pike_error("File not open.\n");    -  get_all_args("set_nodelay", args, ".%d", &state); +  get_all_args(NULL, args, ".%d", &state);       if (state && state != 1) { -  SIMPLE_BAD_ARG_ERROR("set_nodelay()", 1, "int(0..1)"); +  SIMPLE_ARG_TYPE_ERROR("set_nodelay()", 1, "int(0..1)");    }       errno = 0;    while ((fd_setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,    &state, sizeof(state)) < 0) &&    (errno == EINTR)) {    errno = 0;    }    if (errno) {    ERRNO = errno;    push_int(0);    } else {    push_int(1);    }   }   #endif    -  + #ifndef SHUT_RD + #define SHUT_RD 0 + #endif + #ifndef SHUT_WR + #define SHUT_WR 1 + #endif +    static int do_close(int flags)   {    struct my_file *f = THIS;    if(FD == -1) return 1; /* already closed */    ERRNO=0;       flags &= f->open_mode;       switch(flags & (FILE_READ | FILE_WRITE))    {    case 0:    return 0;       case FILE_READ:    if(f->open_mode & FILE_WRITE)    {    SUB_FD_EVENTS (f, PIKE_BIT_FD_READ|PIKE_BIT_FD_READ_OOB|PIKE_BIT_FD_FS_EVENT); -  fd_shutdown(FD, 0); +  fd_shutdown(FD, SHUT_RD);    f->open_mode &=~ FILE_READ;    return 0;    }else{    f->flags&=~FILE_NOT_OPENED; -  close_fd(); +  close_fd(0);    return 1;    }       case FILE_WRITE:    if(f->open_mode & FILE_READ)    {    SUB_FD_EVENTS (f, PIKE_BIT_FD_WRITE|PIKE_BIT_FD_WRITE_OOB|PIKE_BIT_FD_FS_EVENT); -  fd_shutdown(FD, 1); +  fd_shutdown(FD, SHUT_WR);    f->open_mode &=~ FILE_WRITE;   #ifdef HAVE_PIKE_SEND_FD    if (f->fd_info) do_close_fd_info(f->fd_info);   #endif    return 0;    }else{    f->flags&=~FILE_NOT_OPENED; -  close_fd(); +  close_fd(0);    return 1;    }       case FILE_READ | FILE_WRITE:    f->flags&=~FILE_NOT_OPENED; -  close_fd(); +  close_fd(0);    return 1;       default:    Pike_fatal("Bug in switch implementation!\n");    UNREACHABLE(return 0);    }   }      /*! @decl string grantpt()    *!
pike.git/src/modules/_Stdio/file.c:2489:   #endif   }   #endif /* HAVE_GRANTPT || USE_PT_CHMOD || USE_CHGPT */      /*! @decl int close()    *! @decl int close(string direction)    *!    *! Close a file or stream.    *!    *! If direction is not specified, both the read and the write -  *! direction is closed. Otherwise only the directions specified is +  *! direction are closed. Otherwise only the directions specified is    *! closed.    *!    *! @returns -  *! Nonzero is returned if the file or stream wasn't open in the -  *! specified direction, zero otherwise. +  *! Returns @expr{1@} if the file or stream now is closed in +  *! all directions, and @expr{0@} otherwise.    *!    *! @throws    *! An exception is thrown if an I/O error occurs.    *!    *! The default behaviour for sockets is typically to flush buffered    *! data in the background, but this can be changed with @[linger()].    *!    *! @note    *! @[close()] has no effect if this file object has been associated    *! with an already opened file, i.e. if @[open()] was given an
pike.git/src/modules/_Stdio/file.c:2612:    *!    *! @seealso    *! @[close()]    */   static void file_open(INT32 args)   {    int flags,fd;    int access;    int err;    struct pike_string *str, *flag_str; -  close_fd(); +  close_fd(0);       if(args < 2)    SIMPLE_WRONG_NUM_ARGS_ERROR("open", 2);       if(TYPEOF(Pike_sp[-args]) != PIKE_T_STRING &&    TYPEOF(Pike_sp[-args]) != PIKE_T_INT)    SIMPLE_ARG_TYPE_ERROR("open", 1, "string|int");       if(TYPEOF(Pike_sp[1-args]) != PIKE_T_STRING)    SIMPLE_ARG_TYPE_ERROR("open", 2, "string");
pike.git/src/modules/_Stdio/file.c:2716: Inside #if defined(HAVE_OPENAT)
  static void file_openat(INT32 args)   {    int flags, fd, dir_fd;    int access = 00666;    int err;    struct pike_string *str, *flag_str;       if((dir_fd = FD) < 0)    Pike_error("File not open.\n");    -  get_all_args("openat", args, "%S%S.%d", &str, &flag_str, &access); +  get_all_args(NULL, args, "%S%S.%d", &str, &flag_str, &access);       flags = parse(flag_str->str);       if (string_has_null(str)) {    /* Filenames with NUL are not supported. */    ERRNO = errno = ENOENT;    pop_n_elems(args);    push_int(0);    return;    }
pike.git/src/modules/_Stdio/file.c:2772: Inside #if !defined(__NT__) && (defined(HAVE_POSIX_OPENPT) || defined(PTY_MASTER_PATHNAME))
   *!    *! @seealso    *! @[grantpt()]    */   static void file_openpt(INT32 args)   {    int flags,fd;   #ifdef HAVE_POSIX_OPENPT    struct pike_string *flag_str;   #endif -  close_fd(); +  close_fd(0);       if(args < 1)    SIMPLE_WRONG_NUM_ARGS_ERROR("openpt", 1);       if(TYPEOF(Pike_sp[-args]) != PIKE_T_STRING)    SIMPLE_ARG_TYPE_ERROR("openpt", 1, "string");      #ifdef HAVE_POSIX_OPENPT    flags = parse((flag_str = Pike_sp[-args].u.string)->str);   
pike.git/src/modules/_Stdio/file.c:3099:   #endif    if(TYPEOF(Pike_sp[-args]) != PIKE_T_INT)    SIMPLE_ARG_TYPE_ERROR("truncate", 1, "int");    else    len = Pike_sp[-args].u.integer;       if(FD < 0)    Pike_error("File not open.\n");       ERRNO=0; - #ifdef HAVE_FTRUNCATE64 -  res = ftruncate64 (FD, len); - #else +     res=fd_ftruncate(FD, len); - #endif +        pop_n_elems(args);       if(res<0)    ERRNO=errno;       push_int(!res);   }      /*! @decl Stat stat()
pike.git/src/modules/_Stdio/file.c:3191: Inside #if defined(HAVE_FSTATAT)
  {    int fd;    PIKE_STAT_T s;    int tmp;    struct pike_string *path;    int nofollow = 0;       if(FD < 0)    Pike_error("File not open.\n");    -  get_all_args("statat", args, "%S.%d", &path, &nofollow); +  get_all_args(NULL, args, "%S.%d", &path, &nofollow);       if (string_has_null(path)) {    /* Filenames with NUL are not supported. */    ERRNO = errno = ENOENT;    pop_n_elems(args);    push_int(0);    return;    }       fd=FD;
pike.git/src/modules/_Stdio/file.c:3246: Inside #if defined(HAVE_FSTATAT) and #if defined(HAVE_UNLINKAT)
   int dir_fd;    PIKE_STAT_T st;    struct pike_string *str;    INT32 i;       destruct_objects_to_destruct();       if((dir_fd = FD) < 0)    Pike_error("File not open.\n");    -  get_all_args("unlinkat", args, "%S", &str); +  get_all_args(NULL, args, "%S", &str);       if (string_has_null(str)) {    /* Filenames with NUL are not supported. */    ERRNO = ENOENT;    pop_n_elems(args);    push_int(0);    return;    }       THREADS_ALLOW_UID();
pike.git/src/modules/_Stdio/file.c:3310: Inside #if defined(HAVE_FDOPENDIR) && defined(HAVE_OPENAT)
  {    int fd;    int dfd;    struct pike_string *path = NULL;    ptrdiff_t name_max = -1;    DIR *dir = NULL;       if(FD < 0)    Pike_error("File not open.\n");    -  get_all_args("get_dir", args, ".%S", &path); +  get_all_args(NULL, args, ".%S", &path);       if (path && string_has_null(path)) { -  fprintf(stderr, "NULL\n"); +     /* Filenames with NUL are not supported. */    ERRNO = errno = ENOENT;    pop_n_elems(args);    push_int(0);    return;    }       fd = FD;    dfd = -1;       while(1) {    THREADS_ALLOW_UID(); -  if (!path) { +  /* NB: The empty string is also an alias for the current directory. +  * This is a convenience eg when recursing with dirname(). +  */ +  if (!path || !path->len) {    dfd = dup(fd);    } else {    dfd = openat(fd, path->str, O_RDONLY);    }    THREADS_DISALLOW_UID();       if ((dfd == -1) && (errno == EINTR)) {    check_threads_etc();    continue;    }
pike.git/src/modules/_Stdio/file.c:3451:    *! Return the value of a specified attribute, or 0 if it does not exist    */   static void file_getxattr(INT32 args)   {    char buffer[1024];    char *ptr = buffer;    int mfd = FD, do_free = 0;    ssize_t res;    char *name;    -  get_all_args( "getxattr", args, "%s", &name ); +  get_all_args( NULL, args, "%s", &name );       THREADS_ALLOW();    do {   #ifdef HAVE_DARWIN_XATTR    res = fgetxattr( mfd, name, buffer, sizeof(buffer), 0, 0 ); /* First try, for speed.*/   #else    res = fgetxattr( mfd, name, buffer, sizeof(buffer) ); /* First try, for speed.*/   #endif /* HAVE_DARWIN_XATTR */    } while( res < 0 && errno == EINTR );    THREADS_DISALLOW();
pike.git/src/modules/_Stdio/file.c:3511:         /*! @decl void removexattr( string attr )    *! Remove the specified extended attribute.    */   static void file_removexattr( INT32 args )   {    char *name;    int mfd = FD;    int rv; -  get_all_args( "removexattr", args, "%s", &name ); +  get_all_args( NULL, args, "%s", &name );    THREADS_ALLOW();   #ifdef HAVE_DARWIN_XATTR    while( ((rv=fremovexattr( mfd, name, 0 )) < 0) && (errno == EINTR))    ;   #else    while( ((rv=fremovexattr( mfd, name )) < 0) && (errno == EINTR))    ;   #endif /* HAVE_DARWIN_XATTR */    THREADS_DISALLOW();   
pike.git/src/modules/_Stdio/file.c:3559:    *! @returns    *! 1 if successful, 0 otherwise, setting errno.    */   static void file_setxattr( INT32 args )   {    char *ind;    struct pike_string *val;    int flags;    int rv;    int mfd = FD; -  get_all_args( "setxattr", args, "%s%S%d", &ind, &val, &flags ); +  get_all_args( NULL, args, "%s%S%d", &ind, &val, &flags );    THREADS_ALLOW();   #ifdef HAVE_DARWIN_XATTR    while( ((rv=fsetxattr( mfd, ind, val->str,    (val->len<<val->size_shift), 0, flags )) < 0) &&    (errno == EINTR))    ;   #else    while( ((rv=fsetxattr( mfd, ind, val->str,    (val->len<<val->size_shift), flags )) < 0) &&    (errno == EINTR))
pike.git/src/modules/_Stdio/file.c:3865:    */    ONERROR err;    SET_ONERROR(err, do_close_fd, (ptrdiff_t) fd);    o = clone_object_from_object(Pike_fp->current_object, 0);    UNSET_ONERROR(err);    if (!o->prog) return NULL; /* Destructed in create() or __INIT(). */    f = (struct my_file *)(o->storage + Pike_fp->context->storage_offset);    f->flags |= (THIS->flags & FILE_HAVE_RECV_FD);    } else {    /* Clone a plain Fd object. */ -  o = low_clone(file_program); +  o = fast_clone_object(file_program);    f = (struct my_file *) o->storage + file_program->inherits->storage_offset; -  call_c_initializers(o); +     }    change_fd_for_box(&f->box, fd);    if (fd >= 0) {    f->open_mode=mode | fd_query_properties(fd, guess);   #ifdef PIKE_DEBUG    debug_check_fd_not_in_use (fd);   #endif    } else {    f->open_mode = 0;    }
pike.git/src/modules/_Stdio/file.c:4271:    *! @decl Stdio.File pipe(int flags)    */   static void file_pipe(INT32 args)   {    int inout[2] = { -1, -1 };    int i = 0;       int type=fd_CAN_NONBLOCK | fd_BIDIRECTIONAL;    int reverse;    -  check_all_args("file->pipe",args, BIT_INT | BIT_VOID, 0); +  check_all_args(NULL, args, BIT_INT | BIT_VOID, 0);    if(args && !SUBTYPEOF(Pike_sp[-1])) type = Pike_sp[-args].u.integer;       reverse = type & fd_REVERSE;    type &= ~fd_REVERSE;    -  close_fd(); +  close_fd(0);    pop_n_elems(args);    ERRNO=0;       do    {   #ifdef PIPE_CAPABILITIES    if(!(type & ~(PIPE_CAPABILITIES)))    {    i=fd_pipe(&inout[0]);    if (i >= 0) {
pike.git/src/modules/_Stdio/file.c:4390:    IDENTIFIER_PIKE_FUNCTION) && (i->func.offset != -1)) {    /* receive_fd() is not a prototype. */    f->flags |= FILE_HAVE_RECV_FD;    }    break;       case PROG_EVENT_EXIT:    if(!(f->flags & (FILE_NO_CLOSE_ON_DESTRUCT |    FILE_LOCK_FD |    FILE_NOT_OPENED))) -  close_fd_quietly(); +  close_fd(1);    else    free_fd_stuff();   #ifdef HAVE_PIKE_SEND_FD    if (f->fd_info) {    free(f->fd_info);    f->fd_info = NULL;    }   #endif    unhook_fd_callback_box (&f->box);    break;
pike.git/src/modules/_Stdio/file.c:4573:   }      /*! @decl int(0..1) open_socket(int|void port, string|void addr, @    *! int|string|void family_hint)    */   static void file_open_socket(INT32 args)   {    int fd;    int family=-1;    -  close_fd(); +  close_fd(0);       if (args > 2 && TYPEOF(Pike_sp[2-args]) == PIKE_T_INT &&    Pike_sp[2-args].u.integer != 0)    family = Pike_sp[2-args].u.integer;    else if (args > 2 && TYPEOF(Pike_sp[2-args]) == PIKE_T_STRING &&    !Pike_sp[2-args].u.string->size_shift) {    PIKE_SOCKADDR addr;    get_inet_addr(&addr, (char *) STR0(Pike_sp[2-args].u.string),    NULL, -1, 0);    family = SOCKADDR_FAMILY(addr);
pike.git/src/modules/_Stdio/file.c:4768:    *!    *! Equivalent to setsockopt(Stdio.SO_KEEPALIVE, on_off), but will set errno    *! if SO_KEEPALIVE is not supported, rather than issuing a compilation error    *! for the missing constant.    */   static void file_set_keepalive(INT32 args)   {    int tmp, i;    INT_TYPE t;    -  get_all_args("set_keepalive", args, "%i", &t); +  get_all_args(NULL, args, "%i", &t);       /* In case int and INT_TYPE have different sizes */    tmp = t;      #ifdef SO_KEEPALIVE    i = fd_setsockopt(FD,SOL_SOCKET, SO_KEEPALIVE, (char *)&tmp, sizeof(tmp));    if(i)    {    ERRNO=errno;    }else{
pike.git/src/modules/_Stdio/file.c:4813:    *! 1 if successful, 0 if not (and sets errno())    *!    *! @seealso    *! @[set_keepalive()]    */   static void file_setsockopt(INT32 args)   {    int tmp, i, opt, level;    INT_TYPE o, t, l;    -  get_all_args("setsockopt", args, "%i%i%i", &l, &o, &t); +  get_all_args(NULL, args, "%i%i%i", &l, &o, &t);       /* In case int and INT_TYPE have different sizes */    tmp = t; opt = o; level = l;       i = fd_setsockopt(FD, level, opt, (char *)&tmp, sizeof(tmp));    if(i)    {    ERRNO=errno;    }else{    ERRNO=0;
pike.git/src/modules/_Stdio/file.c:4889:    name = xalloc(addr_len);       name->sun_family=AF_UNIX;    strcpy( name->sun_path, Pike_sp[-args].u.string->str );   #ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN    /* Length including NUL. */    name->sun_len = Pike_sp[-args].u.string->len + 1;   #endif    pop_n_elems(args);    -  close_fd(); +  close_fd(0);    change_fd_for_box (&THIS->box, socket(AF_UNIX,SOCK_STREAM,0));       if( FD < 0 )    {    free(name);    ERRNO = errno;    push_int(0);    return;    }   
pike.git/src/modules/_Stdio/file.c:4963:    struct svalue *src_port = NULL;       int tmp, was_closed = FD < 0;    int fd, sent = 0;    int nb_mode;    int old_events;    int e;       if (args < 4)    { -  get_all_args("connect", args, "%S%*", &dest_addr, &dest_port); +  get_all_args(NULL, args, "%S%*", &dest_addr, &dest_port);    }    else if( args == 5 )    {    struct svalue *src_sv; -  get_all_args("connect", args, "%S%*%*%*%S", +  get_all_args(NULL, args, "%S%*%*%*%S",    &dest_addr, &dest_port, &src_sv, &src_port, &data);    if(TYPEOF(*src_sv) != PIKE_T_INT )    {    if (TYPEOF(*src_sv) != PIKE_T_STRING || src_sv->u.string->size_shift)    SIMPLE_ARG_TYPE_ERROR("connect", 3, "int|string(8bit)");    src_addr = src_sv->u.string;    }    } else { -  get_all_args("connect", args, "%S%*%S%*", +  get_all_args(NULL, args, "%S%*%S%*",    &dest_addr, &dest_port, &src_addr, &src_port);    }       if(TYPEOF(*dest_port) != PIKE_T_INT &&    (TYPEOF(*dest_port) != PIKE_T_STRING || dest_port->u.string->size_shift))    SIMPLE_ARG_TYPE_ERROR("connect", 2, "int|string(8bit)");       if(src_port && TYPEOF(*src_port) != PIKE_T_INT &&    (TYPEOF(*src_port) != PIKE_T_STRING || src_port->u.string->size_shift))    SIMPLE_ARG_TYPE_ERROR("connect", 4, "int|string(8bit)");
pike.git/src/modules/_Stdio/file.c:5206:    *! @seealso    *! @[open()]    */   static void file_create(INT32 args)   {    if(!args) return;    if(TYPEOF(Pike_sp[-args]) != PIKE_T_STRING &&    TYPEOF(Pike_sp[-args]) != PIKE_T_INT)    SIMPLE_ARG_TYPE_ERROR("create", 1, "int|string");    -  close_fd(); +  close_fd(0);    file_open(args); -  +  pop_stack();   }      #ifdef _REENTRANT      struct new_thread_data   {    INT32 from, to;    char buffer[READ_BUFFER];   };   
pike.git/src/modules/_Stdio/file.c:5279: Inside #if defined(_REENTRANT)
   *! @seealso    *! @[Stdio.sendfile()]    */   void file_proxy(INT32 args)   {    struct my_file *f;    struct new_thread_data *p;    int from, to;       THREAD_T id; -  check_all_args("Stdio.File->proxy",args, BIT_OBJECT,0); +  check_all_args(NULL, args, BIT_OBJECT,0);    f=get_file_storage(Pike_sp[-args].u.object);    if(!f)    SIMPLE_ARG_TYPE_ERROR("proxy", 1, "Stdio.File");       from=fd_dup(f->box.fd);    if(from<0)    {    ERRNO=errno;    Pike_error("Failed to dup proxy fd. (errno=%d)\n",errno);    }
pike.git/src/modules/_Stdio/file.c:5487:    err=fd_flock(fd, fd_LOCK_UN);   #else    err=fd_lockf(fd, fd_LOCK_UN);   #endif    THREADS_DISALLOW();    if ((err < 0) && (errno == EINTR)) {    check_threads_etc();    }    }while(err<0 && errno==EINTR);    - #ifdef _REENTRANT -  THIS_KEY->owner = NULL; -  if(THIS_KEY->owner_obj) -  { -  free_object(THIS_KEY->owner_obj); -  THIS_KEY->owner_obj = NULL; -  } - #endif +     THIS_KEY->f->key = 0; -  THIS_KEY->f = 0; +     }   }      static void init_file_locking(void)   {    ptrdiff_t off;    START_NEW_PROGRAM_ID (STDIO_FILE_LOCK_KEY);    off = ADD_STORAGE(struct file_lock_key_storage);   #ifdef _REENTRANT    PIKE_MAP_VARIABLE("_owner",
pike.git/src/modules/_Stdio/file.c:5546:    */   static void f_get_all_active_fd(INT32 args)   {    int i,fds=0;    PIKE_STAT_T foo;    struct svalue *sp;       pop_n_elems(args);    sp = Pike_sp;    { + #ifndef __NT__    DIR *tmp; -  + #endif    THREADS_ALLOW();   #ifndef __NT__    if( (tmp = opendir(   #ifdef HAVE_DARWIN_XATTR    "/dev/fd"   #else    "/proc/self/fd"   #endif    )) )    {   #ifdef HAVE_DIRFD    INT_TYPE dfd = dirfd(tmp);   #endif       while(1)    {    INT_TYPE fd;    char *ep; -  struct dirent ent, *res; +  struct dirent *res;    /* solaris, linux, cygwin, darwin, netbsd et.al. */    res = NULL; -  while( UNLIKELY(readdir_r( tmp, &ent, &res )) -  && UNLIKELY(errno==EINTR)) +  while( UNLIKELY(!(res = readdir(tmp))) && UNLIKELY(errno==EINTR))    ;    if( !res )    break;       fd = strtol(res->d_name, &ep, 10);       if( LIKELY(ep != res->d_name)   #ifdef HAVE_DIRFD    && (fd != dfd)   #endif
pike.git/src/modules/_Stdio/file.c:5979:    *!    *! Returns the protocol number of the protocol @expr{name@}.    *! This calls the POSIX function getprotobyname.    *! If the protocol cannot be found an error is thrown.    */   static void f_getprotobyname(INT32 args) {   #ifdef HAVE_GETPROTOBYNAME    struct protoent *proto;    const char *name;    -  get_all_args("getprotobyname", args, "%c", &name); +  get_all_args(NULL, args, "%c", &name);       proto = getprotobyname(name);       if (proto) {    push_int(proto->p_proto);    return;    }   #endif    Pike_error("Could not find protocol.\n");   }
pike.git/src/modules/_Stdio/file.c:6250:   #endif /* HAVE_KQUEUE */         #if 0    /* Not implemented yet. */   #ifdef HAVE_UNLINKAT    add_integer_constant("__HAVE_UNLINKAT__",1,0);   #endif   #endif /* 0 */    + #ifdef __NT__ +  add_integer_constant("__HAVE_UTF8_FS__", 1, 0); + #endif +    #ifdef HAVE_PIKE_SEND_FD    add_integer_constant("__HAVE_SEND_FD__", 1, 0);   #endif    /* function(:array(int)) */    ADD_FUNCTION2("get_all_active_fd", f_get_all_active_fd,    tFunc(tNone,tArr(tInt)), 0, OPT_EXTERNAL_DEPEND);       /* function(void:mapping) */    ADD_FUNCTION2("gethostip", f_gethostip, tFunc(tNone,tMapping),    0, OPT_EXTERNAL_DEPEND);