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

version» Context lines:

pike.git/src/modules/_Stdio/efuns.c:12:   #include "array.h"   #include "mapping.h"   #include "pike_macros.h"   #include "fd_control.h"   #include "threads.h"   #include "module_support.h"   #include "constants.h"   #include "backend.h"   #include "operators.h"   #include "builtin_functions.h" - #include "pike_security.h" +    #include "bignum.h"      #include "file_machine.h"   #include "file.h"    - #ifdef HAVE_SYS_TYPES_H - #include <sys/types.h> - #endif +    #include <sys/stat.h>   #ifdef HAVE_SYS_PARAM_H   #include <sys/param.h>   #endif   #include <signal.h>   #include <errno.h>    - #ifdef HAVE_LIMITS_H - #include <limits.h> - #endif /* HAVE_LIMITS_H */ -  - #ifdef HAVE_DIRENT_H - # include <dirent.h> - # define NAMLEN(dirent) strlen((dirent)->d_name) - #else - # ifdef HAVE_SYS_NDIR_H - # include <sys/ndir.h> - # define dirent direct - # define NAMLEN(dirent) (dirent)->d_namlen - # else /* !HAVE_SYS_NDIR_H */ - # ifdef HAVE_SYS_DIR_H - # include <sys/dir.h> - # define dirent direct - # define NAMLEN(dirent) (dirent)->d_namlen - # else /* !HAVE_SYS_DIR_H */ - # ifdef HAVE_NDIR_H - # include <ndir.h> - # define dirent direct - # define NAMLEN(dirent) (dirent)->d_namlen - # else /* !HAVE_NDIR_H */ - # ifdef HAVE_DIRECT_H - # include <direct.h> - # define NAMLEN(dirent) strlen((dirent)->d_name) - # endif /* HAVE_DIRECT_H */ - # endif /* HAVE_NDIR_H */ - # endif /* HAVE_SYS_DIR_H */ - # endif /* HAVE_SYS_NDIR_H */ - #endif /* HAVE_DIRENT_H */ -  - #include "dmalloc.h" -  +    #ifdef HAVE_PROCESS_H   #include <process.h>   #endif      #ifdef HAVE_SYS_XATTR_H   #include <sys/xattr.h>   #endif /* HAVE_SYS_XATTR_H */      #if 0   #ifdef HAVE_LIBZFS_INIT   #ifdef HAVE_LIBZFS_H   #include <libzfs.h>   #endif /* HAVE_LIBZFS_H */   static libzfs_handle_t *libzfs_handle;   #endif /* HAVE_LIBZFS_INIT */   #endif /* 0 */      #define sp Pike_sp    - /* #define DEBUG_FILE */ +    /* #define READDIR_DEBUG */ -  + #ifdef READDIR_DEBUG + #define RDWERR(...) fprintf(stderr,__VA_ARGS__) + #else + #define RDWERR(...) + #endif      #ifdef __NT__      #include <winbase.h>   #include <io.h> -  + #include <direct.h>      /* Old versions of the headerfiles don't have this constant... */   #ifndef INVALID_SET_FILE_POINTER   #define INVALID_SET_FILE_POINTER ((DWORD)-1)   #endif      /* Dynamic load of functions that doesn't exist in all Windows versions. */      static HINSTANCE kernel32lib;   
pike.git/src/modules/_Stdio/efuns.c:129:    push_int64((INT64)s->st_size);    stack_pop_to_no_free (ITEM(a) + 1);    if (TYPEOF(ITEM(a)[1]) == T_OBJECT) a->type_field |= BIT_OBJECT;    break;       case S_IFDIR: ITEM(a)[1].u.integer=-2; break;   #ifdef S_IFLNK    case S_IFLNK: ITEM(a)[1].u.integer=-3; break;   #endif    default: - #ifdef DEBUG_FILE -  fprintf(stderr, "encode_stat(): mode:%ld\n", (long)S_IFMT & s->st_mode); - #endif /* DEBUG_FILE */ +     ITEM(a)[1].u.integer=-4;    break;    } -  ITEM(a)[2].u.integer = DO_NOT_WARN ((INT_TYPE) s->st_atime); -  ITEM(a)[3].u.integer = DO_NOT_WARN ((INT_TYPE) s->st_mtime); -  ITEM(a)[4].u.integer = DO_NOT_WARN ((INT_TYPE) s->st_ctime); +  ITEM(a)[2].u.integer = (INT_TYPE) s->st_atime; +  ITEM(a)[3].u.integer = (INT_TYPE) s->st_mtime; +  ITEM(a)[4].u.integer = (INT_TYPE) s->st_ctime;    ITEM(a)[5].u.integer=s->st_uid;    ITEM(a)[6].u.integer=s->st_gid;    return a;   }      #if defined(HAVE_FSETXATTR) && defined(HAVE_FGETXATTR) && defined(HAVE_FLISTXATTR)   /*! @decl array(string) listxattr( string file, void|int(0..1) symlink )    *!    *! Return an array of all extended attributes set on the file    */
pike.git/src/modules/_Stdio/efuns.c:430:    *!    *! @seealso    *! @[Stdio.Stat], @[Stdio.File->stat()]    */   void f_file_stat(INT32 args)   {    PIKE_STAT_T st;    int i, l;    struct pike_string *str;    -  VALID_FILE_IO("file_stat","read"); -  +     if(args<1) -  SIMPLE_TOO_FEW_ARGS_ERROR("file_stat", 1); +  SIMPLE_WRONG_NUM_ARGS_ERROR("file_stat", 1);    if((TYPEOF(sp[-args]) != T_STRING) || sp[-args].u.string->size_shift) -  SIMPLE_BAD_ARG_ERROR("file_stat", 1, "string(0..255)"); +  SIMPLE_ARG_TYPE_ERROR("file_stat", 1, "string(0..255)");       str = sp[-args].u.string;    l = (args>1 && !UNSAFE_IS_ZERO(sp+1-args))?1:0;       if (string_has_null(str)) {    /* Filenames with NUL are not supported. */    errno = ENOENT;    pop_n_elems(args);    push_int(0);    return;
pike.git/src/modules/_Stdio/efuns.c:477:      /*! @decl int file_truncate(string file, int length)    *!    *! Truncates the file @[file] to the length specified in @[length].    *!    *! @returns    *! Returns 1 if ok, 0 if failed.    */   void f_file_truncate(INT32 args)   { - #if defined(INT64) +     INT64 len = 0; - #else -  off_t len = 0; - #endif +     struct pike_string *str;    int res;    -  VALID_FILE_IO("file_truncate","write"); -  -  if(args < 2) -  SIMPLE_TOO_FEW_ARGS_ERROR("file_truncate", 2); +  if(args != 2) +  SIMPLE_WRONG_NUM_ARGS_ERROR("file_truncate", 2);    if(TYPEOF(sp[-args]) != T_STRING) -  SIMPLE_BAD_ARG_ERROR("file_truncate", 1, "string"); +  SIMPLE_ARG_TYPE_ERROR("file_truncate", 1, "string");    - #if defined (INT64) +    #if defined (HAVE_FTRUNCATE64) || SIZEOF_OFF_T > SIZEOF_INT_TYPE    if(is_bignum_object_in_svalue(&Pike_sp[1-args])) {    if (!int64_from_bignum(&len, Pike_sp[1-args].u.object))    Pike_error ("Bad argument 2 to file_truncate(). Length too large.\n");    }    else   #endif - #endif +     if(TYPEOF(sp[1-args]) != T_INT) -  SIMPLE_BAD_ARG_ERROR("file_truncate", 2, "int"); +  SIMPLE_ARG_TYPE_ERROR("file_truncate", 2, "int");    else    len = sp[1-args].u.integer;       str = sp[-args].u.string;       if (string_has_null(str)) {    /* Filenames with NUL are not supported. */    errno = ENOENT;    pop_n_elems(args);    push_int(0);    return;    }    - #ifdef __NT__ -  { -  HANDLE h = CreateFile(str->str, GENERIC_WRITE, -  FILE_SHARE_READ|FILE_SHARE_WRITE, -  NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); -  if(h == DO_NOT_WARN(INVALID_HANDLE_VALUE)) { -  errno = GetLastError(); -  res=-1; -  } else { -  LONG high; -  DWORD err; - #ifdef INT64 -  high = DO_NOT_WARN ((LONG) (len >> 32)); -  len &= ((INT64) 1 << 32) - 1; - #else -  high = 0; - #endif -  if (SetFilePointer(h, DO_NOT_WARN ((LONG) len), &high, FILE_BEGIN) == -  INVALID_SET_FILE_POINTER && -  (err = GetLastError()) != NO_ERROR) { -  errno = err; -  res = -1; -  } -  else if (!SetEndOfFile(h)) { -  errno = GetLastError(); -  res=-1; -  } -  else -  res = 0; -  CloseHandle(h); -  } -  } - #else /* !__NT__ */ - #ifdef HAVE_TRUNCATE64 -  res = truncate64 (str->str, len); - #else -  res=truncate(str->str, len); - #endif - #endif /* __NT__ */ +  res = fd_truncate(str->str, len);       pop_n_elems(args);       push_int(!res);   }      /*! @decl mapping(string:int) filesystem_stat(string path)    *!    *! Returns a mapping describing the properties of the filesystem    *! containing the path specified by @[path].
pike.git/src/modules/_Stdio/efuns.c:595:    *! Number of free files in the filesystem.    *! @member int "favail"    *! Number of available files in the filesystem.    *! This is usually the same as the @expr{"ffree"@} value, and can    *! usually be adjusted with eg tunefs(1M).    *! @member string "fsname"    *! Name assigned to the filesystem. This item is not available    *! on all systems.    *! @member string "fstype"    *! Type of filesystem (eg @expr{"nfs"@}). This item is not -  *! available on all systems. +  *! available on all systems. For some more uncommon filesystems +  *! this may be an integer representing the magic number for the +  *! filesystem type (cf @tt{statfs(2)@} on eg Linux systems).    *! @endmapping    *!    *! @note    *! Please note that not all members are present on all OSs.    *!    *! @seealso    *! @[file_stat()]    */   #ifdef __NT__      void f_filesystem_stat( INT32 args )   {    char *path;    DWORD sectors_per_cluster = -1;    DWORD bytes_per_sector = -1;    DWORD free_clusters = -1;    DWORD total_clusters = -1; -  +  p_wchar1 *root;    char _p[4];    char *p = _p;    unsigned int free_sectors;    unsigned int total_sectors;    -  VALID_FILE_IO("filesystem_stat","read"); -  +     get_all_args( "filesystem_stat", args, "%s", &path );    -  if(sp[-1].u.string->len < 2 || path[1] != ':') -  { -  p = 0; +  root = pike_dwim_utf8_to_utf16(path); +  if (root[0] && root[1] == ':') { +  root[2] = '\\'; +  root[3] = 0;    } else { -  p[0] = path[0]; -  p[1] = ':'; -  p[2] = '\\'; -  p[3] = 0; +  free(root); +  root = NULL;    }    -  if(!GetDiskFreeSpace( p, &sectors_per_cluster, +  if(!GetDiskFreeSpaceW( root, &sectors_per_cluster,    &bytes_per_sector,    &free_clusters,    &total_clusters ))    { -  +  if (root) free(root);    pop_n_elems(args);    push_int( 0 );    return;    }    -  +  if (root) free(root); +     free_sectors = sectors_per_cluster * free_clusters;    total_sectors = sectors_per_cluster * total_clusters;       pop_n_elems( args ); -  push_text("blocksize"); +  push_static_text("blocksize");    push_int(bytes_per_sector); -  push_text("blocks"); +  push_static_text("blocks");    push_int(total_sectors); -  push_text("bfree"); +  push_static_text("bfree");    push_int(free_sectors); -  push_text("bavail"); +  push_static_text("bavail");    push_int(free_sectors);    f_aggregate_mapping( 8 );   }      #else /* !__NT__ */    - #if !defined(HAVE_STRUCT_STATFS) && !defined(HAVE_STRUCT_FS_DATA) + #if !defined(HAVE_STRUCT_STATFS) && !defined(HAVE_STRUCT_FS_DATA)   #undef HAVE_STATFS   #endif    -  + #if defined(HAVE_STATFS) && defined(HAVE_STATVFS) && !defined(HAVE_STATVFS_F_BASETYPE) + /* Linux libc doesn't provide fs type info in statvfs(2), +  * so use statfs(2) instead. +  */ + #undef HAVE_STATVFS + #endif +    #if defined(HAVE_STATVFS) || defined(HAVE_STATFS) || defined(HAVE_USTAT)   #ifdef HAVE_SYS_STATVFS_H   /* Kludge for broken SCO headerfiles */   #ifdef _SVID3   #include <sys/statvfs.h>   #else   #define _SVID3   #include <sys/statvfs.h>   #undef _SVID3   #endif /* _SVID3 */   #endif /* HAVE_SYS_STATVFS_H */   #ifdef HAVE_SYS_VFS_H   #include <sys/vfs.h>   #endif /* HAVE_SYS_VFS_H */   #ifdef HAVE_SYS_STATFS_H   #include <sys/statfs.h> -  + #ifdef HAVE_LINUX_MAGIC_H + #include <linux/magic.h> + #endif /* HAVE_LINUX_MAGIC_H */   #endif /* HAVE_SYS_STATFS_H */   #ifdef HAVE_SYS_PARAM_H   #include <sys/param.h>   #endif /* HAVE_SYS_PARAM_H */   #ifdef HAVE_SYS_MOUNT_H   #include <sys/mount.h>   #endif /* HAVE_SYS_MOUNT_H */   #if !defined(HAVE_STATVFS) && !defined(HAVE_STATFS)   #ifdef HAVE_USTAT_H   #include <ustat.h>
pike.git/src/modules/_Stdio/efuns.c:704:    struct statvfs st;   #else /* !HAVE_STATVFS */   #ifdef HAVE_STATFS   #ifdef HAVE_STRUCT_STATFS    struct statfs st;   #else /* !HAVE_STRUCT_STATFS */   #ifdef HAVE_STRUCT_FS_DATA    /* Probably only ULTRIX has this name for the struct */    struct fs_data st;   #else /* !HAVE_STRUCT_FS_DATA */ -  /* Should not be reached */ +    #error No struct to hold statfs() data.   #endif /* HAVE_STRUCT_FS_DATA */   #endif /* HAVE_STRUCT_STATFS */   #else /* !HAVE_STATFS */   #ifdef HAVE_USTAT    PIKE_STAT_T statbuf;    struct ustat st;   #else /* !HAVE_USTAT */ -  /* Should not be reached */ +    #error No stat function for filesystems.   #endif /* HAVE_USTAT */   #endif /* HAVE_STATFS */   #endif /* HAVE_STATVFS */    int i;    struct pike_string *str;    -  if(args<1) -  SIMPLE_TOO_FEW_ARGS_ERROR("filesystem_stat", 1); +  if(args!=1) +  SIMPLE_WRONG_NUM_ARGS_ERROR("filesystem_stat", 1);    if(TYPEOF(sp[-args]) != T_STRING) -  SIMPLE_BAD_ARG_ERROR("filesystem_stat", 1, "string"); +  SIMPLE_ARG_TYPE_ERROR("filesystem_stat", 1, "string");       str = sp[-args].u.string;       if (string_has_null(str)) {    /* Filenames with NUL are not supported. */    errno = ENOENT;    pop_n_elems(args);    push_int(0);    return;    }
pike.git/src/modules/_Stdio/efuns.c:752: Inside #if defined(HAVE_STATFS)
   i = statfs(str->str, &st, sizeof(st), 0);   #else    i = statfs(str->str, &st);   #endif /* HAVE_SYSV_STATFS */   #else /* !HAVE_STATFS */   #ifdef HAVE_USTAT    if (!(i = fd_stat(str->str, &statbuf))) {    i = ustat(statbuf.st_rdev, &st);    }   #else -  /* Should not be reached */ +    #error No stat function for filesystems.   #endif /* HAVE_USTAT */   #endif /* HAVE_STATFS */   #endif /* HAVE_STATVFS */    THREADS_DISALLOW();    pop_n_elems(args);    if(i==-1)    {    push_int(0);    }else{    int num_fields = 0; -  char *fsname = NULL; +    #ifdef HAVE_STATVFS   #if 0 -  push_text("id"); push_int(st.f_fsid); +  push_static_text("id"); push_int(st.f_fsid);    num_fields++;   #endif -  push_text("blocksize"); push_int(st.f_frsize); -  push_text("blocks"); push_int(st.f_blocks); -  push_text("bfree"); push_int(st.f_bfree); -  push_text("bavail"); push_int(st.f_bavail); -  push_text("files"); push_int(st.f_files); -  push_text("ffree"); push_int(st.f_ffree); -  push_text("favail"); push_int(st.f_favail); +  push_static_text("blocksize"); push_int(st.f_frsize); +  push_static_text("blocks"); push_int(st.f_blocks); +  push_static_text("bfree"); push_int(st.f_bfree); +  push_static_text("bavail"); push_int(st.f_bavail); +  push_static_text("files"); push_int(st.f_files); +  push_static_text("ffree"); push_int(st.f_ffree); +  push_static_text("favail"); push_int(st.f_favail);    num_fields += 7;   #ifdef HAVE_STATVFS_F_FSTR -  push_text("fsname"); push_text(fsname = st.f_fstr); +  push_static_text("fsname"); push_text(st.f_fstr);    num_fields++;   #endif /* HAVE_STATVFS_F_FSTR */   #ifdef HAVE_STATVFS_F_BASETYPE -  push_text("fstype"); push_text(st.f_basetype); +  push_static_text("fstype"); push_text(st.f_basetype);    num_fields++;   #endif /* HAVE_STATVFS_F_BASETYPE */   #else /* !HAVE_STATVFS */   #ifdef HAVE_STATFS   #ifdef HAVE_STRUCT_STATFS   #if 0 && HAVE_STATFS_F_FSID -  push_text("id"); push_int(st.f_fsid); +  push_static_text("id"); push_int(st.f_fsid);    num_fields++;   #endif -  push_text("blocksize"); push_int(st.f_bsize); -  push_text("blocks"); push_int(st.f_blocks); -  push_text("bfree"); push_int(st.f_bfree); -  push_text("files"); push_int(st.f_files); -  push_text("ffree"); push_int(st.f_ffree); -  push_text("favail"); push_int(st.f_ffree); +  push_static_text("blocksize"); push_int(st.f_bsize); +  push_static_text("blocks"); push_int(st.f_blocks); +  push_static_text("bfree"); push_int(st.f_bfree); +  push_static_text("files"); push_int(st.f_files); +  push_static_text("ffree"); push_int(st.f_ffree); +  push_static_text("favail"); push_int(st.f_ffree);    num_fields += 6;   #ifdef HAVE_STATFS_F_BAVAIL -  push_text("bavail"); push_int(st.f_bavail); +  push_static_text("bavail"); push_int(st.f_bavail);    num_fields++;   #endif /* HAVE_STATFS_F_BAVAIL */ -  +  push_static_text("fstype"); + #ifdef HAVE_STATFS_F_FSTYPENAME +  push_text(st.f_fstypename); + #else +  switch(st.f_type) { + #ifdef BTRFS_SUPER_MAGIC +  case BTRFS_SUPER_MAGIC: push_static_text("btrfs"); break; + #endif /* BTRFS_SUPER_MAGIC */ + #ifdef EXT2_SUPER_MAGIC +  case EXT2_SUPER_MAGIC: push_static_text("ext"); break; + #endif /* EXT2_SUPER_MAGIC */ + #ifdef ISOFS_SUPER_MAGIC +  case ISOFS_SUPER_MAGIC: push_static_text("isofs"); break; + #endif /* ISOFS_SUPER_MAGIC */ + #ifdef JFFS2_SUPER_MAGIC +  case JFFS2_SUPER_MAGIC: push_static_text("jffs2"); break; + #endif /* JFFS2_SUPER_MAGIC */ + #ifdef MSDOS_SUPER_MAGIC +  case MSDOS_SUPER_MAGIC: push_static_text("msdos"); break; + #endif /* MSDOS_SUPER_MAGIC */ + #ifdef NFS_SUPER_MAGIC +  case NFS_SUPER_MAGIC: push_static_text("nfs"); break; + #endif /* NFS_SUPER_MAGIC */ + #ifndef NTFS_SB_MAGIC + #define NTFS_SB_MAGIC 0x5346544e + #endif +  case NTFS_SB_MAGIC: push_static_text("ntfs"); break; + #ifdef PROC_SUPER_MAGIC +  case PROC_SUPER_MAGIC: push_static_text("procfs"); break; + #endif /* PROC_SUPER_MAGIC */ + #ifdef RAMFS_MAGIC +  case RAMFS_MAGIC: push_static_text("ramfs"); break; + #endif /* RAMFS_MAGIC */ + #ifdef REISERFS_SUPER_MAGIC +  case REISERFS_SUPER_MAGIC: push_static_text("reiserfs"); break; + #endif /* REISERFS_SUPER_MAGIC */ + #ifdef SMB_SUPER_MAGIC +  case SMB_SUPER_MAGIC: push_static_text("smb"); break; + #endif /* SMB_SUPER_MAGIC */ + #ifdef SYSFS_MAGIC +  case SYSFS_MAGIC: push_static_text("sysfs"); break; + #endif /* SYSFS_MAGIC */ + #ifdef TMPFS_MAGIC +  case TMPFS_MAGIC: push_static_text("tmpfs"); break; + #endif /* TMPFS_MAGIC */ + #ifdef XENFS_SUPER_MAGIC +  case XENFS_SUPER_MAGIC: push_static_text("xenfs"); break; + #endif /* XENFS_SUPER_MAGIC */ +  default: +  push_int(st.f_type); +  break; +  } + #endif /* HAVE_STATFS_F_FSTYPENAME */ +  num_fields++;   #else /* !HAVE_STRUCT_STATFS */   #ifdef HAVE_STRUCT_FS_DATA    /* ULTRIX */ -  push_text("blocksize"); push_int(st.fd_bsize); -  push_text("blocks"); push_int(st.fd_btot); -  push_text("bfree"); push_int(st.fd_bfree); -  push_text("bavail"); push_int(st.fd_bfreen); +  push_static_text("blocksize"); push_int(st.fd_bsize); +  push_static_text("blocks"); push_int(st.fd_btot); +  push_static_text("bfree"); push_int(st.fd_bfree); +  push_static_text("bavail"); push_int(st.fd_bfreen);    num_fields += 4;   #else /* !HAVE_STRUCT_FS_DATA */ -  /* Should not be reached */ +    #error No struct to hold statfs() data.   #endif /* HAVE_STRUCT_FS_DATA */   #endif /* HAVE_STRUCT_STATFS */   #else /* !HAVE_STATFS */   #ifdef HAVE_USTAT -  push_text("bfree"); push_int(st.f_tfree); -  push_text("ffree"); push_int(st.f_tinode); -  push_text("fsname"); push_text(fsname = st.f_fname); +  push_static_text("bfree"); push_int(st.f_tfree); +  push_static_text("ffree"); push_int(st.f_tinode); +  push_static_text("fsname"); push_text(st.f_fname);    num_fields += 3;   #else -  /* Should not be reached */ +    #error No stat function for filesystems.   #endif /* HAVE_USTAT */   #endif /* HAVE_STATFS */   #endif /* HAVE_STATVFS */ - #if 0 - #if defined(HAVE_LIBZFS_INIT) && defined(HAVE_ZFS_PATH_TO_ZHANDLE) -  /* zfs_path_to_zhandle() has an unfortunate tendency to output stuff -  * to stderr when it fails... -  */ -  if (fsname && !strcmp(fsname, "zfs")) { -  zfs_handle_t *zfs_handle; -  if ((str->len == 1) && (str->str[0] == '.')) { -  /* Workaround for bug in zfs_path_to_zhandle(). */ -  zfs_handle = zfs_path_to_zhandle(libzfs_handle, "./", -  ZFS_TYPE_FILESYSTEM); -  } else { -  zfs_handle = zfs_path_to_zhandle(libzfs_handle, str->str, -  ZFS_TYPE_FILESYSTEM); -  } -  if (zfs_handle) { - #ifndef HAVE_ZFS_PROP_UTF8ONLY -  /* NOTE: ZFS_PROP_UTF8ONLY is not present in Solaris 10 127112-05. -  * Attempt to be forward compatible. -  */ - #define ZFS_PROP_UTF8ONLY (ZFS_PROP_XATTR + 4) - #endif /* !HAVE_ZFS_PROP_UTF8ONLY */ -  if (zfs_prop_get_int(zfs_handle, ZFS_PROP_UTF8ONLY)) { -  push_text("filename_encoding"); -  push_text("utf8"); -  num_fields++; -  } -  } -  } - #endif /* HAVE_LIBZFS_INIT && HAVE_ZFS_PATH_TO_ZHANDLE */ - #endif /* 0 */ -  +     f_aggregate_mapping(num_fields*2);    }   }      #endif /* HAVE_STATVFS || HAVE_STATFS || HAVE_USTAT */   #endif /* __NT__ */      /*! @decl int rm(string f)    *!    *! Remove a file or directory.    *!    *! @returns    *! Returns @expr{0@} (zero) on failure, @expr{1@} otherwise.    *! -  +  *! @note +  *! May fail with @[errno()] set to @[EISDIR] or @[ENOTDIR] +  *! if the file has changed to a directory during the call +  *! or the reverse. +  *!    *! @seealso -  *! @[mkdir()], @[Stdio.recursive_rm()] +  *! @[Stdio.File()->unlinkat()], @[mkdir()], @[Stdio.recursive_rm()]    */   void f_rm(INT32 args)   {    PIKE_STAT_T st;    INT32 i;    struct pike_string *str;       destruct_objects_to_destruct();    -  VALID_FILE_IO("rm","write"); +  if(args!=1) +  SIMPLE_WRONG_NUM_ARGS_ERROR("rm", 1);    -  if(!args) -  SIMPLE_TOO_FEW_ARGS_ERROR("rm", 1); -  +     if(TYPEOF(sp[-args]) != T_STRING) -  SIMPLE_BAD_ARG_ERROR("rm", 1, "string"); +  SIMPLE_ARG_TYPE_ERROR("rm", 1, "string");       str = sp[-args].u.string;       if (string_has_null(str)) {    /* Filenames with NUL are not supported. */    errno = ENOENT;    pop_n_elems(args);    push_int(0);    return;    }
pike.git/src/modules/_Stdio/efuns.c:914: Inside #if defined(HAVE_LSTAT)
   THREADS_ALLOW_UID();   #ifdef HAVE_LSTAT    i=fd_lstat(str->str, &st) != -1;   #else    i=fd_stat(str->str, &st) != -1;   #endif    if(i)    {    if(S_IFDIR == (S_IFMT & st.st_mode))    { -  while (!(i = rmdir(str->str) != -1) && (errno == EINTR)) +  while (!(i = fd_rmdir(str->str) != -1) && (errno == EINTR))    ;    }else{ -  while (!(i = unlink(str->str) != -1) && (errno == EINTR)) +  while (!(i = fd_unlink(str->str) != -1) && (errno == EINTR))    ;    } - #ifdef __NT__ -  /* NT looks at the permissions on the file itself and refuses to -  * remove files we don't have write access to. Thus we chmod it -  * and try again, to make rm() more unix-like. */ -  if (!i && errno == EACCES && !(st.st_mode & _S_IWRITE)) { -  if (chmod(str->str, st.st_mode | _S_IWRITE) == -1) -  errno = EACCES; -  else { -  if(S_IFDIR == (S_IFMT & st.st_mode)) -  { -  while (!(i = rmdir(str->str) != -1) && (errno == EINTR)) -  ; -  }else{ -  while (!(i = unlink(str->str) != -1) && (errno == EINTR)) -  ; +     } -  if (!i) { /* Failed anyway; try to restore the old mode. */ -  int olderrno = errno; -  chmod(str->str, st.st_mode); -  errno = olderrno; -  } -  } -  } - #endif -  } +     THREADS_DISALLOW_UID();       pop_n_elems(args);    push_int(i);   }      /*! @decl int mkdir(string dirname, void|int mode)    *!    *! Create a directory.    *!
pike.git/src/modules/_Stdio/efuns.c:971:    *! @seealso    *! @[rm()], @[cd()], @[Stdio.mkdirhier()]    */   void f_mkdir(INT32 args)   {    struct pike_string *str;    int mode;    int i;    char *s, *s_dup;    -  VALID_FILE_IO("mkdir","write"); -  +     if(!args) -  SIMPLE_TOO_FEW_ARGS_ERROR("mkdir", 1); +  SIMPLE_WRONG_NUM_ARGS_ERROR("mkdir", 1);       if(TYPEOF(sp[-args]) != T_STRING) -  SIMPLE_BAD_ARG_ERROR("mkdir", 1, "string"); +  SIMPLE_ARG_TYPE_ERROR("mkdir", 1, "string");       mode = 0777; /* &'ed with ~umask anyway. */       if(args > 1)    {    if(TYPEOF(sp[1-args]) != T_INT)    Pike_error("Bad argument 2 to mkdir.\n");       mode = sp[1-args].u.integer;    }
pike.git/src/modules/_Stdio/efuns.c:1010:    implementations (e.g. Mac OS X and Windows) */    s = str->str;    s_dup = NULL;    if (str->len && (s[str->len - 1] == '/' || s[str->len - 1] == '\\')) {    if ((s_dup = strdup(s))) {    s = s_dup;    s[str->len - 1] = '\0';    }    }    - #if MKDIR_ARGS == 2 +     THREADS_ALLOW_UID(); -  i = mkdir(s, mode) != -1; +  i = fd_mkdir(s, mode) != -1;    THREADS_DISALLOW_UID(); - #else +     - #ifdef HAVE_LSTAT - #define LSTAT lstat - #else - #define LSTAT stat - #endif -  -  { -  /* Most OS's should have MKDIR_ARGS == 2 nowadays fortunately. */ -  int mask = umask(0); -  /* The following is basically the normal THREADS_ALLOW_UID/ -  * THREADS_DISALLOW_UID macros expanded. They cannot be used -  * directly due to the nested disallow/allow block below. */ -  struct thread_state *cur_ts_ext = Pike_interpreter.thread_state; -  pike_threads_allow_ext (cur_ts_ext COMMA_DLOC); -  i = mkdir(s) != -1; -  umask(mask); -  if (i) { -  /* Attempt to set the mode. -  * -  * This code needs to be as paranoid as possible. -  */ -  struct stat statbuf1; -  struct stat statbuf2; -  i = LSTAT(s, &statbuf1) != -1; -  if (i) { -  i = ((statbuf1.st_mode & S_IFMT) == S_IFDIR); -  } -  if (i) { -  mode = ((mode & 0777) | (statbuf1.st_mode & ~0777)) & ~mask; -  do { -  i = chmod(s, mode) != -1; -  if (i || errno != EINTR) break; -  pike_threads_disallow_ext (cur_ts_ext COMMA_DLOC); -  check_threads_etc(); -  pike_threads_allow_ext (cur_ts_ext COMMA_DLOC); -  } while (1); -  } -  if (i) { -  i = LSTAT(s, &statbuf2) != -1; -  } -  if (i) { -  i = (statbuf2.st_mode == mode) && (statbuf1.st_ino == statbuf2.st_ino); -  if (!i) { -  errno = EPERM; -  } -  } -  if (!i) { -  rmdir(s); -  } -  } -  pike_threads_disallow_ext (cur_ts_ext COMMA_DLOC); -  } - #endif -  +     if (s_dup)    free(s_dup);       pop_n_elems(args);    push_int(i);   }      #undef HAVE_READDIR_R   #if defined(HAVE_SOLARIS_READDIR_R) || defined(HAVE_HPUX_READDIR_R) || \    defined(HAVE_POSIX_READDIR_R)
pike.git/src/modules/_Stdio/efuns.c:1113:      /*! @decl array(string) get_dir(void|string dirname)    *!    *! Returns an array of all filenames in the directory @[dirname], or    *! @expr{0@} (zero) if the directory does not exist. When no    *! @[dirname] is given, current work directory is used.    *!    *! @seealso    *! @[mkdir()], @[cd()]    */ + #ifdef __NT__   void f_get_dir(INT32 args)   { - #ifdef __NT__ +     HANDLE dir;    WIN32_FIND_DATAW d; -  struct string_builder sb; - #else /* !__NT__ */ - #ifdef USE_FDOPENDIR -  int dir_fd; - #endif -  DIR *dir = NULL; - #ifdef HAVE_READDIR_R -  ptrdiff_t name_max = -1; - #endif - #endif /* __NT__ */ +     struct pike_string *str=0; -  +  p_wchar1 *pattern; +  size_t plen;    -  VALID_FILE_IO("get_dir","read"); +  get_all_args("get_dir", args, ".%S", &str);    - #ifdef __NT__ -  get_all_args("get_dir",args,".%T",&str); - #else /* !__NT__ */ -  get_all_args("get_dir",args,".%N",&str); - #endif /* __NT__ */ -  -  if(!str) { - #if defined(__amigaos4__) -  push_empty_string(); - #else -  push_constant_text("."); - #endif +  /* NB: The empty string is also an alias for the current directory. +  * This is a convenience eg when recursing with dirname(). +  */ +  if(!str || !str->len) { +  push_static_text(".");    str = Pike_sp[-1].u.string;    args++; -  } -  - #ifdef __NT__ -  -  if (str->size_shift == 2) { -  /* Filenames that are too wide are not supported. */ +  } else if (string_has_null(str)) { +  /* Filenames with NUL are not supported. */    errno = ENOENT;    pop_n_elems(args);    push_int(0);    return;    }    -  init_string_builder_alloc(&sb, str->len+2, 1); +  pattern = pike_dwim_utf8_to_utf16(str->str);    -  string_builder_shared_strcat(&sb, str); -  -  /* Append "/" "*". */ -  if (sb.s->len && (STR1(sb.s)[sb.s->len-1] != '/') && -  (STR1(sb.s)[sb.s->len-1] != '\\')) { -  STR1(sb.s)[sb.s->len++] = '/'; +  if (!pattern) { +  SIMPLE_OUT_OF_MEMORY_ERROR("get_dir", (str->len + 4) * sizeof(p_wchar1));    } -  STR1(sb.s)[sb.s->len++] = '*'; -  STR1(sb.s)[sb.s->len] = '\0'; +     -  if (wcslen(STR1(sb.s)) != (size_t)sb.s->len) { -  /* Filenames with NUL are not supported. */ -  free_string_builder(&sb); -  errno = ENOENT; -  pop_n_elems(args); -  push_int(0); -  return; +  plen = wcslen(pattern); +  +  /* Append "/" "*". +  * +  * NB: pike_dwim_utf8_to_utf16() allocates space for at +  * least 3 extra characters. +  */ +  if (plen && (pattern[plen-1] != '/') && (pattern[plen-1] != '\\')) { +  pattern[plen++] = '/';    } -  +  pattern[plen++] = '*'; +  pattern[plen] = 0;    - #ifdef READDIR_DEBUG -  fprintf(stderr, "FindFirstFile(\"%S\")...\n", STR1(sb.s)); - #endif /* READDIR_DEBUG */ +  RDWERR("FindFirstFile(\"%S\")...\n", STR1(sb.s));    -  dir = FindFirstFileW(STR1(sb.s), &d); +  dir = FindFirstFileW(pattern, &d);    -  free_string_builder(&sb); +  free(pattern);    -  if (dir == DO_NOT_WARN(INVALID_HANDLE_VALUE)) { +  if (dir == INVALID_HANDLE_VALUE) {    int err = GetLastError(); - #ifdef READDIR_DEBUG -  fprintf(stderr, " INVALID_HANDLE_VALUE, error %d\n", err); - #endif /* READDIR_DEBUG */ +  RDWERR(" INVALID_HANDLE_VALUE, error %d\n", err);       pop_n_elems(args);    if (err == ERROR_FILE_NOT_FOUND) {    /* Normally there should at least be a "." entry, so this seldom    * happens. But it seems unwise to count on it, considering this    * being Windows and all..    *    * Note: The error is ERROR_PATH_NOT_FOUND if the directory    * doesn't exist.    */
pike.git/src/modules/_Stdio/efuns.c:1217: Inside #if defined(__NT__)
   }    return;    }       {    int err;       BEGIN_AGGREGATE_ARRAY(10);       do { - #ifdef READDIR_DEBUG -  fprintf(stderr, " \"%S\"\n", d.cFileName); - #endif /* READDIR_DEBUG */ +  ONERROR uwp; +  p_wchar0 *utf8_fname; +  +  RDWERR(" \"%S\"\n", d.cFileName);    /* Filter "." and ".." from the list. */    if(d.cFileName[0]=='.')    {    if(!d.cFileName[1]) continue;    if(d.cFileName[1]=='.' && !d.cFileName[2]) continue;    } -  push_string(make_shared_binary_string1(d.cFileName, wcslen(d.cFileName))); +  +  utf8_fname = pike_utf16_to_utf8(d.cFileName); +  if (!utf8_fname) { +  SIMPLE_OUT_OF_MEMORY_ERROR("get_dir", +  (wcslen(d.cFileName) + 4) * sizeof(p_wchar1)); +  } +  +  SET_ONERROR(uwp, free, utf8_fname); +  push_text(utf8_fname); +  CALL_AND_UNSET_ONERROR(uwp); +     DO_AGGREGATE_ARRAY(120);    } while(FindNextFileW(dir, &d));    err = GetLastError();    - #ifdef READDIR_DEBUG -  fprintf(stderr, " DONE, error %d\n", err); - #endif /* READDIR_DEBUG */ +  RDWERR(" DONE, error %d\n", err);       FindClose(dir);       END_AGGREGATE_ARRAY;       stack_pop_n_elems_keep_top(args);       if (err != ERROR_SUCCESS && err != ERROR_NO_MORE_FILES) {    set_errno_from_win32_error (err);    pop_stack();    push_int (0);    return;    }    } -  + }      #else /* !__NT__ */    -  if (string_has_null(str)) { -  /* Filenames with NUL are not supported. */ -  errno = ENOENT; -  pop_n_elems(args); -  push_int(0); -  return; -  } -  -  THREADS_ALLOW_UID(); - #ifdef USE_FDOPENDIR -  dir_fd = open(str->str, O_RDONLY); -  if (dir_fd != -1) { - #ifdef USE_FPATHCONF -  name_max = fpathconf(dir_fd, _PC_NAME_MAX); - #endif /* USE_FPATHCONF */ -  dir = fdopendir(dir_fd); -  if (!dir) close(dir_fd); -  } - #else -  dir = opendir(str->str); - #ifdef USE_FPATHCONF -  if (dir) { -  name_max = fpathconf(dirfd(dir), _PC_NAME_MAX); -  } - #endif - #endif /* !HAVE_FDOPENDIR */ - #ifdef USE_PATHCONF -  name_max = pathconf(str->str, _PC_NAME_MAX); - #endif -  THREADS_DISALLOW_UID(); -  if(dir) + /* Note: Also used from file_get_dir(). */ + void low_get_dir(DIR *dir, ptrdiff_t UNUSED(name_max))   { -  +  if(dir) {    struct dirent *d; -  struct dirent *tmp = NULL; - #if defined(_REENTRANT) && defined(HAVE_READDIR_R) + #if defined(_REENTRANT)   #define FPR 1024    char buffer[MAXPATHLEN * 4];    char *ptrs[FPR];    ptrdiff_t lens[FPR]; -  + #endif /* _REENTRANT */    - #ifndef NAME_MAX - #define NAME_MAX 1024 - #endif -  if (name_max < NAME_MAX) -  name_max = NAME_MAX; -  if (name_max < 1024) name_max = 1024; -  -  if (!(tmp = malloc(sizeof(struct dirent) + name_max + 1))) { -  closedir(dir); -  Pike_error("get_dir(): Out of memory\n"); -  } - #endif /* _REENTRANT && HAVE_READDIR_R */ -  +     BEGIN_AGGREGATE_ARRAY(10);    - #if defined(_REENTRANT) && defined(HAVE_READDIR_R) + #if defined(_REENTRANT)    while(1)    {    int e;    int num_files=0;    char *bufptr=buffer;    int err = 0;       THREADS_ALLOW();       while(1)    { - #if defined(HAVE_SOLARIS_READDIR_R) -  /* Solaris readdir_r returns the second arg on success, -  * and returns NULL on error or at end of dir. +  /* Modern impementations of readdir(3C) are thread-safe with +  * respect to unique DIRs. +  * +  * Linux Glibc has deprecated readdir_r(3C).    */ -  errno=0; -  do { -  d=readdir_r(dir, tmp); -  } while ((!d) && ((errno == EAGAIN)||(errno == EINTR))); +  errno = 0; +  while (!(d = readdir(dir)) && (errno == EINTR)) +  ;    if (!d) { -  +  RDWERR("readdir(), d= %p\n", d); +  RDWERR("readdir() => errno %d\n", errno);    /* Solaris readdir_r seems to set errno to ENOENT sometimes. -  */ -  if (errno == ENOENT) { -  err = 0; -  } else { -  err = errno; -  } -  break; -  } - #elif defined(HAVE_HPUX_READDIR_R) -  /* HPUX's readdir_r returns an int instead: +     * -  * 0 - Successfull operation. -  * -1 - End of directory or encountered an error (sets errno). +  * AIX readdir seems to set errno to EBADF at end of dir.    */ -  errno=0; -  if (readdir_r(dir, tmp)) { -  d = NULL; -  err = errno; -  break; -  } else { -  d = tmp; -  } - #elif defined(HAVE_POSIX_READDIR_R) -  /* POSIX readdir_r returns 0 on success, and ERRNO on failure. -  * at end of dir it sets the third arg to NULL. -  */ -  d = NULL; +  if ((errno == ENOENT) || (errno == EBADF)) {    errno = 0; -  if ((err = readdir_r(dir, tmp, &d)) || !d) { - #ifdef READDIR_DEBUG -  fprintf(stderr, "POSIX readdir_r(\"%s\") => err %d\n", -  str->str, err); -  fprintf(stderr, "POSIX readdir_r(), d= 0x%08x\n", -  (unsigned int)d); - #endif /* READDIR_DEBUG */ -  if (err == -1) { -  /* Solaris readdir_r returns -1, and sets errno. */ -  err = errno; +     } - #ifdef READDIR_DEBUG -  fprintf(stderr, "POSIX readdir_r(\"%s\") => errno %d\n", -  str->str, err); - #endif /* READDIR_DEBUG */ -  /* Solaris readdir_r seems to set errno to ENOENT sometimes. -  * -  * AIX readdir_r seems to set errno to EBADF at end of dir. -  */ -  if ((err == ENOENT) || (err == EBADF)) { -  err = 0; -  } +     break;    } - #ifdef READDIR_DEBUG -  fprintf(stderr, "POSIX readdir_r(\"%s\") => \"%s\"\n", -  str->str, d->d_name); - #endif /* READDIR_DEBUG */ - #else - #error Unknown readdir_r variant - #endif +  RDWERR("POSIX readdir_r() => \"%s\"\n", d->d_name);    /* Filter "." and ".." from the list. */    if(d->d_name[0]=='.')    {    if(NAMLEN(d)==1) continue;    if(d->d_name[1]=='.' && NAMLEN(d)==2) continue;    }    if(num_files >= FPR) break;    lens[num_files]=NAMLEN(d);    if(bufptr+lens[num_files] >= buffer+sizeof(buffer)) break; -  MEMCPY(bufptr, d->d_name, lens[num_files]); +  memcpy(bufptr, d->d_name, lens[num_files]);    ptrs[num_files]=bufptr;    bufptr+=lens[num_files];    num_files++;    }    THREADS_DISALLOW();    if ((!d) && err) { -  free(tmp); -  Pike_error("get_dir(): readdir_r(\"%S\") failed: %d\n", str, err); +  Pike_error("get_dir(): readdir_r() failed: %d\n", err);    } - #ifdef READDIR_DEBUG -  fprintf(stderr, "Pushing %d filenames...\n", num_files); - #endif /* READDIR_DEBUG */ +  RDWERR("Pushing %d filenames...\n", num_files);    for(e=0;e<num_files;e++)    {    push_string(make_shared_binary_string(ptrs[e],lens[e]));    }    if(d)    push_string(make_shared_binary_string(d->d_name,NAMLEN(d)));    else    break;    DO_AGGREGATE_ARRAY(120);    } -  -  free(tmp); +    #else    for(d=readdir(dir); d; d=readdir(dir))    { -  +  RDWERR("readdir(): %s\n", d->d_name);    /* Filter "." and ".." from the list. */    if(d->d_name[0]=='.')    {    if(NAMLEN(d)==1) continue;    if(d->d_name[1]=='.' && NAMLEN(d)==2) continue;    }    push_string(make_shared_binary_string(d->d_name, NAMLEN(d)));       DO_AGGREGATE_ARRAY(120);    }   #endif    closedir(dir);       END_AGGREGATE_ARRAY; -  stack_pop_n_elems_keep_top(args); +     } else { -  +  push_int(0); +  } + } +  + void f_get_dir(INT32 args) + { + #ifdef USE_FDOPENDIR +  int dir_fd; + #endif +  DIR *dir = NULL; +  ptrdiff_t name_max = -1; +  struct pike_string *str=0; +  +  get_all_args("get_dir",args,".%N",&str); +  +  /* NB: The empty string is also an alias for the current directory. +  * This is a convenience eg when recursing with dirname(). +  */ +  if(!str || !str->len) { + #if defined(__amigaos4__) +  push_empty_string(); + #else +  push_static_text("."); + #endif +  str = Pike_sp[-1].u.string; +  args++; +  } +  +  if (string_has_null(str)) { +  /* Filenames with NUL are not supported. */ +  errno = ENOENT;    pop_n_elems(args);    push_int(0); -  +  return;    } - #endif /* __NT__ */ +  +  THREADS_ALLOW_UID(); + #ifdef USE_FDOPENDIR +  dir_fd = open(str->str, O_RDONLY); +  if (dir_fd != -1) { + #ifdef USE_FPATHCONF +  name_max = fpathconf(dir_fd, _PC_NAME_MAX); + #endif /* USE_FPATHCONF */ +  dir = fdopendir(dir_fd); +  if (!dir) close(dir_fd);    } -  + #else +  dir = opendir(str->str); + #ifdef USE_FPATHCONF +  if (dir) { +  name_max = fpathconf(dirfd(dir), _PC_NAME_MAX); +  } + #endif + #endif /* !HAVE_FDOPENDIR */ + #ifdef USE_PATHCONF +  name_max = pathconf(str->str, _PC_NAME_MAX); + #endif    -  +  THREADS_DISALLOW_UID(); +  +  low_get_dir(dir, name_max); +  stack_pop_n_elems_keep_top(args); + } + #endif /* __NT__ */ +    /*! @decl int cd(string s)    *!    *! Change the current directory for the whole Pike process.    *!    *! @returns    *! Returns @expr{1@} for success, @expr{0@} (zero) otherwise.    *!    *! @seealso    *! @[getcwd()]    */   void f_cd(INT32 args)   {    INT32 i;    struct pike_string *str;    -  VALID_FILE_IO("cd","status"); +  if(args!=1) +  SIMPLE_WRONG_NUM_ARGS_ERROR("cd", 1);    -  if(!args) -  SIMPLE_TOO_FEW_ARGS_ERROR("cd", 1); -  +     if(TYPEOF(sp[-args]) != T_STRING) -  SIMPLE_BAD_ARG_ERROR("cd", 1, "string"); +  SIMPLE_ARG_TYPE_ERROR("cd", 1, "string");       str = sp[-args].u.string;       if (string_has_null(str)) {    /* Filenames with NUL are not supported. */    errno = ENOENT;    pop_n_elems(args);    push_int(0);    return;    }    -  i = chdir(str->str) != -1; +  i = fd_chdir(str->str) != -1;    pop_n_elems(args);    push_int(i);   }      /*! @decl string getcwd()    *!    *! Returns the current working directory.    *!    *! @seealso    *! @[cd()]    */   void f_getcwd(INT32 args)   { -  char *e; -  char *tmp; - #if defined(HAVE_WORKING_GETCWD) || !defined(HAVE_GETWD) -  INT32 size; -  -  size=1000; -  do { -  tmp=(char *)xalloc(size); -  e = getcwd(tmp,size); -  if (e || errno!=ERANGE) break; -  free(tmp); -  tmp=0; -  size*=2; -  } while (size < 10000); - #else - #ifndef MAXPATHLEN - #define MAXPATHLEN 32768 - #endif -  tmp=xalloc(MAXPATHLEN+1); -  THREADS_ALLOW_UID(); -  e = getwd(tmp); -  THREADS_DISALLOW_UID(); - #endif -  if(!e) { -  if (tmp) -  free(tmp); +  char *e = fd_get_current_dir_name(); +  if (!e) {    Pike_error("Failed to fetch current path.\n");    }       pop_n_elems(args);    push_text(e); -  free(tmp); +  free(e);   }      #ifdef HAVE_EXECVE   /*! @decl int exece(string file, array(string) args)    *! @decl int exece(string file, array(string) args, @    *! mapping(string:string) env)    *!    *! This function transforms the Pike process into a process running    *! the program specified in the argument @[file] with the arguments @[args].    *!
pike.git/src/modules/_Stdio/efuns.c:1565: Inside #if defined(HAVE_EXECVE)
   char **argv, **env;    struct svalue *save_sp;    struct mapping *en;   #ifdef DECLARE_ENVIRON    extern char **environ;   #endif       save_sp=sp-args;       if(args < 2) -  SIMPLE_TOO_FEW_ARGS_ERROR("exece", 2); +  SIMPLE_WRONG_NUM_ARGS_ERROR("exece", 2);    - #ifdef PIKE_SECURITY -  if(!CHECK_SECURITY(SECURITY_BIT_SECURITY)) -  Pike_error("exece: permission denied.\n"); - #endif -  -  +     e=0;    en=0;    switch(args)    {    default:    if(TYPEOF(sp[2-args]) != T_MAPPING) -  SIMPLE_BAD_ARG_ERROR("exece", 3, "mapping(string:string)"); +  SIMPLE_ARG_TYPE_ERROR("exece", 3, "mapping(string:string)");    en=sp[2-args].u.mapping;    mapping_fix_type_field(en);       if(m_ind_types(en) & ~BIT_STRING) -  SIMPLE_BAD_ARG_ERROR("exece", 3, "mapping(string:string)"); +  SIMPLE_ARG_TYPE_ERROR("exece", 3, "mapping(string:string)");    if(m_val_types(en) & ~BIT_STRING) -  SIMPLE_BAD_ARG_ERROR("exece", 3, "mapping(string:string)"); +  SIMPLE_ARG_TYPE_ERROR("exece", 3, "mapping(string:string)");    -  +  /* FALLTHRU */ +     case 2:    if(TYPEOF(sp[1-args]) != T_ARRAY) -  SIMPLE_BAD_ARG_ERROR("exece", 2, "array(string)"); +  SIMPLE_ARG_TYPE_ERROR("exece", 2, "array(string)");          if(array_fix_type_field(sp[1-args].u.array) & ~BIT_STRING) -  SIMPLE_BAD_ARG_ERROR("exece", 2, "array(string)"); +  SIMPLE_ARG_TYPE_ERROR("exece", 2, "array(string)");    -  +  /* FALLTHRU */ +     case 1:    if(TYPEOF(sp[0-args]) != T_STRING) -  SIMPLE_BAD_ARG_ERROR("exece", 1, "string"); +  SIMPLE_ARG_TYPE_ERROR("exece", 1, "string"); +  break;    }    -  argv=(char **)xalloc((2+sp[1-args].u.array->size) * sizeof(char *)); +  argv=xalloc((2+sp[1-args].u.array->size) * sizeof(char *));       argv[0]=sp[0-args].u.string->str;       for(e=0;e<sp[1-args].u.array->size;e++)    {    union anything *a;    a=low_array_get_item_ptr(sp[1-args].u.array,e,T_STRING);    argv[e+1]=a->string->str;    }    argv[e+1]=0;       if(en)    {    INT32 e, i = 0;    struct keypair *k;    -  env=(char **)malloc((1+m_sizeof(en)) * sizeof(char *)); +  env=calloc(1+m_sizeof(en), sizeof(char *));    if(!env) {    free(argv);    SIMPLE_OUT_OF_MEMORY_ERROR("exece", (1+m_sizeof(en)*sizeof(char *)));    }       NEW_MAPPING_LOOP(en->data) { -  push_string(k->ind.u.string); -  push_constant_text("="); -  push_string(k->val.u.string); +  ref_push_string(k->ind.u.string); +  push_static_text("="); +  ref_push_string(k->val.u.string);    f_add(3);    env[i++]=sp[-1].u.string->str;    dmalloc_touch_svalue(sp-1);    }       env[i]=0;    }else{    env=environ;    }   
pike.git/src/modules/_Stdio/efuns.c:1688:    *! @[errno()] to get more error info on failure.    *!    *! @seealso    *! @[rm()]    */   void f_mv(INT32 args)   {    INT32 i;    struct pike_string *str1;    struct pike_string *str2; - #ifdef __NT__ -  int orig_errno = errno; -  int err; -  PIKE_STAT_T st; - #endif +     -  VALID_FILE_IO("mv","write"); +  if(args!=2) +  SIMPLE_WRONG_NUM_ARGS_ERROR("mv", 2);    -  if(args<2) -  SIMPLE_TOO_FEW_ARGS_ERROR("mv", 2); -  +     if(TYPEOF(sp[-args]) != T_STRING) -  SIMPLE_BAD_ARG_ERROR("mv", 1, "string"); +  SIMPLE_ARG_TYPE_ERROR("mv", 1, "string");       if(TYPEOF(sp[-args+1]) != T_STRING) -  SIMPLE_BAD_ARG_ERROR("mv", 2, "string"); +  SIMPLE_ARG_TYPE_ERROR("mv", 2, "string");       str1 = sp[-args].u.string;    str2 = sp[1-args].u.string;       if (string_has_null(str1) || string_has_null(str2)) {    /* Filenames with NUL are not supported. */    if (string_has_null(str1)) {    errno = ENOENT;    } else {    errno = EINVAL;    }    pop_n_elems(args);    push_int(0);    return;    }    - #ifndef __NT__ -  i=rename(str1->str, str2->str); - #else +  i = fd_rename(str1->str, str2->str);    -  /* Emulate the behavior of unix rename(2) when the destination exists. */ -  -  if (movefileex) { -  if (MoveFileEx (str1->str, str2->str, 0)) { -  i = 0; -  goto no_nt_rename_kludge; -  } -  if ((i = GetLastError()) != ERROR_ALREADY_EXISTS) -  goto no_nt_rename_kludge; -  } -  else { -  /* Fall back to rename() for W98 and earlier. Unlike MoveFileEx, -  * it can't move directories between directories. */ -  if (!rename (str1->str, str2->str)) { -  i = 0; -  goto no_nt_rename_kludge; -  } -  if ((i = errno) != EEXIST) -  goto no_nt_rename_kludge; -  } -  - #ifdef HAVE_LSTAT -  if (fd_lstat (str2->str, &st)) goto no_nt_rename_kludge; - #else -  if (fd_stat (str2->str, &st)) goto no_nt_rename_kludge; - #endif -  -  if ((st.st_mode & S_IFMT) != S_IFDIR && movefileex) { -  /* MoveFileEx can overwrite a file but not a dir. */ -  if (!(st.st_mode & _S_IWRITE)) -  /* Like in f_rm, we got to handle the case that NT looks on the -  * permissions on the file itself before removing it. */ -  if (chmod (str2->str, st.st_mode | _S_IWRITE)) -  goto no_nt_rename_kludge; -  if (movefileex (str1->str, str2->str, MOVEFILE_REPLACE_EXISTING)) -  i = 0; /* Success. */ -  else -  chmod (str2->str, st.st_mode); -  } -  -  else { -  char *s = malloc (str2->len + 2), *p; -  if (!s) { -  i = movefileex ? ERROR_NOT_ENOUGH_MEMORY : ENOMEM; -  goto no_nt_rename_kludge; -  } -  memcpy (s, str2->str, str2->len); -  p = s + str2->len; -  p[2] = 0; -  -  if ((st.st_mode & S_IFMT) == S_IFDIR) { -  /* Check first that the target is empty if it's a directory, so -  * that we won't even bother trying with the stunt below. */ -  WIN32_FIND_DATA *dir = malloc (sizeof (WIN32_FIND_DATA)); -  HANDLE h; -  if (!dir) { -  i = movefileex ? ERROR_NOT_ENOUGH_MEMORY : ENOMEM; -  goto nt_rename_kludge_end; -  } -  p[0] = '/', p[1] = '*'; -  h = FindFirstFile (s, dir); -  if (h != INVALID_HANDLE_VALUE) { -  do { -  if (dir->cFileName[0] != '.' || -  (dir->cFileName[1] && -  (dir->cFileName[1] != '.' || dir->cFileName[2]))) { -  /* Target dir not empty. */ -  FindClose (h); -  free (dir); -  goto nt_rename_kludge_end; -  } -  } while (FindNextFile (h, dir)); -  FindClose (h); -  } -  free (dir); -  } -  -  /* Move away the target temporarily to do the move, then cleanup -  * or undo depending on how it went. */ -  for (p[0] = 'A'; p[0] != 'Z'; p[0]++) -  for (p[1] = 'A'; p[1] != 'Z'; p[1]++) { -  if (movefileex) { -  if (!movefileex (str2->str, s, 0)) { -  if (GetLastError() == ERROR_ALREADY_EXISTS) continue; -  else goto nt_rename_kludge_end; -  } -  } -  else { -  if (rename (str2->str, s)) { -  if (errno == EEXIST) continue; -  else goto nt_rename_kludge_end; -  } -  } -  if (movefileex ? -  movefileex (str1->str, str2->str, MOVEFILE_REPLACE_EXISTING) : -  !rename (str1->str, str2->str)) { -  if (!(st.st_mode & _S_IWRITE)) -  if (chmod (s, st.st_mode | _S_IWRITE)) -  goto nt_rename_kludge_fail; -  if ((st.st_mode & S_IFMT) == S_IFDIR) { -  while ((err = rmdir (s)) && (errno == EINTR)) -  ; -  } else { -  while ((err = unlink (s)) && (errno == EINTR)) -  ; -  } -  if (!err) { /* Success. */ -  i = 0; -  goto nt_rename_kludge_end; -  } -  -  nt_rename_kludge_fail: -  /* Couldn't remove the old target, perhaps the directory -  * grew files. */ -  if (!(st.st_mode & _S_IWRITE)) -  chmod (s, st.st_mode); -  if (movefileex ? -  !movefileex (str2->str, str1->str, MOVEFILE_REPLACE_EXISTING) : -  rename (str2->str, str1->str)) { -  /* Old target left behind but the rename is still -  * successful, so we claim success anyway in lack of -  * better error reporting capabilities. */ -  i = 0; -  goto nt_rename_kludge_end; -  } -  } -  -  rename (s, str2->str); -  goto nt_rename_kludge_end; -  } -  -  nt_rename_kludge_end: -  free (s); -  } -  - no_nt_rename_kludge: -  if (i) { -  if (movefileex) -  switch (i) { -  /* Try to translate NT errors to errno codes that NT's rename() -  * would return. */ -  case ERROR_INVALID_NAME: -  errno = EINVAL; -  break; -  case ERROR_NOT_ENOUGH_MEMORY: -  errno = ENOMEM; -  break; -  case ERROR_FILE_NOT_FOUND: -  case ERROR_PATH_NOT_FOUND: -  errno = ENOENT; -  break; -  case ERROR_ALREADY_EXISTS: -  errno = EEXIST; -  break; -  default: -  errno = EACCES; -  } -  } -  else errno = orig_errno; - #endif /* __NT__ */ -  +     pop_n_elems(args);    push_int(!i);   }      /*! @decl string strerror(int errno)    *!    *! This function returns a description of an error code. The error    *! code is usually obtained from eg @[Stdio.File->errno()].    *!    *! @note    *! On some platforms the string returned can be somewhat nondescriptive.    */   void f_strerror(INT32 args)   {    char *s;    int err;    -  if(!args) -  SIMPLE_TOO_FEW_ARGS_ERROR("strerror", 1); +  if(args!=1) +  SIMPLE_WRONG_NUM_ARGS_ERROR("strerror", 1);    if(TYPEOF(sp[-args]) != T_INT) -  SIMPLE_BAD_ARG_ERROR("strerror", 1, "int"); +  SIMPLE_ARG_TYPE_ERROR("strerror", 1, "int");       err = sp[-args].u.integer;    pop_n_elems(args);    if(err < 0 || err > 256 )    s=0;    else {   #ifdef HAVE_STRERROR    s=strerror(err);   #else    s=0;   #endif    }    if(s)    push_text(s);    else { -  push_constant_text("Error "); +  push_static_text("Error ");    push_int(err);    f_add(2);    }   }      /*! @decl int errno()    *!    *! This function returns the system error from the last file operation.    *!    *! @note
pike.git/src/modules/_Stdio/efuns.c:1943:    *!    *! @seealso    *! @[Stdio.File->errno()], @[strerror()]    */   static void f_errno(INT32 args)   {    pop_n_elems(args);    push_int(errno);   }    + #ifdef HAVE__ACCESS + #define access(PATH, FLAGS) _access(PATH, FLAGS) + #define HAVE_ACCESS + #endif    - #if defined(HAVE_ACCESS) + #ifdef HAVE_ACCESS +  + #ifndef R_OK + #define R_OK 4 + #define W_OK 2 + #define X_OK 1 + #define F_OK 0 + #endif +    /*! @decl int access( string path, string|void mode )    *!    *! access() checks if the calling process can access the file    *! @[path]. Symbolic links are dereferenced.    *!    *! @param mode    *! The @[mode] specifies the accessibility checks to be performed, and    *! is either not specified or empty, in which case access() just tests    *! if the file exists, or one or more of the characters @expr{"rwx"@}.    *!
pike.git/src/modules/_Stdio/efuns.c:2040: Inside #if defined(HAVE_ACCESS)
      THREADS_ALLOW_UID();    do {    res = access( path, flags );    } while( (res == -1) && (errno == EINTR) )    THREADS_DISALLOW_UID();       pop_n_elems(args);    push_int( !res );   } - #endif + #endif /* HAVE_ACCESS */      void init_stdio_efuns(void)   {    set_close_on_exec(0,1);    set_close_on_exec(1,1);    set_close_on_exec(2,1);      #if 0   #ifdef HAVE_LIBZFS_INIT    libzfs_handle = libzfs_init();