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

version» Context lines:

pike.git/src/modules/_Stdio/file.c:786:    *err = e;    return NULL;    }       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 && !bytes_read) { +  *err = e; +  return -1; +  } +  +  if(!SAFE_IS_ZERO(& THIS->event_cbs[PIKE_FD_READ])) +  ADD_FD_EVENTS (THIS, PIKE_BIT_FD_READ); +  +  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;    int orig_errno = errno;    int open_mode = 0;
pike.git/src/modules/_Stdio/file.c:1263:    *!    *! @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 my_file *file = THIS; +  +  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(FD < 0) -  Pike_error("File not open.\n"); -  +     if(!args)    {    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;
pike.git/src/modules/_Stdio/file.c:1300:       if(args > 1 && !UNSAFE_IS_ZERO(Pike_sp+1-args))    {    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(FD, count, mode, & ERRNO))) +  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, count, mode, & 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:1691:   #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:1754:    *! @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:1916: 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