|
|
|
|
|
|
#include "global.h" |
#include "fdlib.h" |
#include "interpret.h" |
#include "svalue.h" |
#include "stralloc.h" |
#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 "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 */ |
|
#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 |
|
|
|
|
#ifdef __NT__ |
|
#include <winbase.h> |
#include <io.h> |
|
|
#ifndef INVALID_SET_FILE_POINTER |
#define INVALID_SET_FILE_POINTER ((DWORD)-1) |
#endif |
|
|
|
static HINSTANCE kernel32lib; |
|
#define LINKFUNC(RET,NAME,TYPE) \ |
typedef RET (WINAPI * PIKE_CONCAT(NAME,type)) TYPE ; \ |
static PIKE_CONCAT(NAME,type) NAME |
|
LINKFUNC(BOOL, movefileex, ( |
LPCTSTR lpExistingFileName, |
LPCTSTR lpNewFileName, |
DWORD dwFlags |
)); |
|
#endif /* __NT__ */ |
|
struct array *encode_stat(PIKE_STAT_T *s) |
{ |
struct array *a; |
a=allocate_array(7); |
a->type_field = BIT_INT; |
ITEM(a)[0].u.integer=s->st_mode; |
switch(S_IFMT & s->st_mode) |
{ |
case S_IFREG: |
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)[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) |
|
*! |
*! Return an array of all extended attributes set on the file |
*/ |
|
#ifdef HAVE_DARWIN_XATTR |
#define LISTXATTR(PATH, BUF, SZ) listxattr(PATH, BUF, SZ, 0) |
#define LLISTXATTR(PATH, BUF, SZ) listxattr(PATH, BUF, SZ, XATTR_NOFOLLOW) |
#else |
#define LISTXATTR(PATH, BUF, SZ) listxattr(PATH, BUF, SZ) |
#define LLISTXATTR(PATH, BUF, SZ) llistxattr(PATH, BUF, SZ) |
#endif /* !HAVE_DARWIN_XATTR */ |
|
static void f_listxattr(INT32 args) |
{ |
char buffer[1024]; |
char *ptr = buffer; |
char *name; |
int do_free = 0; |
int nofollow = 0; |
ssize_t res; |
get_all_args( "listxattr", args, "%s.%d", &name, &nofollow ); |
|
THREADS_ALLOW(); |
do { |
|
if (nofollow) |
res = LLISTXATTR(name, buffer, sizeof(buffer)); |
else |
res = LISTXATTR( name, buffer, sizeof(buffer)); |
} while( res < 0 && errno == EINTR ); |
THREADS_DISALLOW(); |
|
if( res<0 && errno==ERANGE ) |
{ |
|
size_t blen = 65536; |
ptr = NULL; |
do_free = 1; |
do { |
if (!ptr) { |
ptr = xalloc(blen); |
} else { |
char *tmp = realloc( ptr, blen ); |
if( !tmp ) |
break; |
ptr = tmp; |
} |
THREADS_ALLOW(); |
do { |
if (nofollow) |
res = LLISTXATTR(name, ptr, sizeof(blen)); |
else |
res = LISTXATTR(name, ptr, blen); |
} while( res < 0 && errno == EINTR ); |
THREADS_DISALLOW(); |
blen *= 2; |
} while( (res < 0) && (errno == ERANGE) ); |
} |
|
pop_n_elems( args ); |
if (res < 0) |
{ |
if (do_free) |
free(ptr); |
push_int(0); |
return; |
} |
|
push_string( make_shared_binary_string( ptr, res ) ); |
ptr[0]=0; |
push_string( make_shared_binary_string( ptr, 1 ) ); |
o_divide(); |
push_empty_string(); |
f_aggregate(1); |
o_subtract(); |
|
if (do_free) |
free(ptr); |
} |
|
#ifdef HAVE_DARWIN_XATTR |
#define GETXATTR(PATH, NAME, BUF, SZ) getxattr(PATH, NAME, BUF, SZ, 0, 0) |
#define LGETXATTR(PATH, NAME, BUF, SZ) getxattr(PATH, NAME, BUF, SZ, 0, XATTR_NOFOLLOW) |
#else |
#define GETXATTR(PATH, NAME, BUF, SZ) getxattr(PATH, NAME, BUF, SZ) |
#define LGETXATTR(PATH, NAME, BUF, SZ) lgetxattr(PATH, NAME, BUF, SZ) |
#endif /* !HAVE_DARWIN_XATTR */ |
|
|
|
|
|
static void f_getxattr(INT32 args) |
{ |
char buffer[1024]; |
char *ptr = buffer; |
int do_free = 0; |
ssize_t res; |
char *name, *file; |
int nofollow=0; |
get_all_args( "getxattr", args, "%s%s.%d", &file, &name, &nofollow ); |
|
THREADS_ALLOW(); |
do { |
|
if (nofollow) |
res = LGETXATTR(file, name, buffer, sizeof(buffer)); |
else |
res = GETXATTR(file, name, buffer, sizeof(buffer)); |
} while( res < 0 && errno == EINTR ); |
THREADS_DISALLOW(); |
|
if( res<0 && errno==ERANGE ) |
{ |
|
size_t blen = 65536; |
do_free = 1; |
ptr = NULL; |
do { |
if (!ptr) { |
ptr = xalloc(blen); |
} else { |
char *tmp = realloc( ptr, blen ); |
if( !tmp ) |
break; |
ptr = tmp; |
} |
THREADS_ALLOW(); |
do { |
if (nofollow) |
res = LGETXATTR(file, name, ptr, blen); |
else |
res = GETXATTR(file, name, ptr, blen); |
} while( res < 0 && errno == EINTR ); |
THREADS_DISALLOW(); |
blen *= 2; |
} while( (res < 0) && (errno == ERANGE) ); |
} |
|
if( res < 0 ) |
{ |
if( do_free && ptr ) |
free(ptr); |
push_int(0); |
return; |
} |
|
push_string( make_shared_binary_string( ptr, res ) ); |
if( do_free && ptr ) |
free( ptr ); |
} |
|
|
#ifdef HAVE_DARWIN_XATTR |
#define REMOVEXATTR(PATH, NAME) removexattr(PATH, NAME, 0) |
#define LREMOVEXATTR(PATH, NAME) removexattr(PATH, NAME, XATTR_NOFOLLOW) |
#else |
#define REMOVEXATTR(PATH, NAME) removexattr(PATH, NAME) |
#define LREMOVEXATTR(PATH, NAME) lremovexattr(PATH, NAME) |
#endif /* !HAVE_DARWIN_XATTR */ |
|
|
|
|
static void f_removexattr( INT32 args ) |
{ |
char *name, *file; |
int nofollow=0, rv; |
|
get_all_args( "removexattr", args, "%s%s.%d", &file, &name, &nofollow ); |
|
THREADS_ALLOW(); |
if (nofollow) { |
while(((rv=LREMOVEXATTR(file, name)) < 0) && (errno == EINTR)) |
; |
} else { |
while(((rv=REMOVEXATTR(file, name)) < 0) && (errno == EINTR)) |
; |
} |
THREADS_DISALLOW(); |
|
pop_n_elems(args); |
if( rv < 0 ) |
{ |
push_int(0); |
} |
else |
{ |
push_int(1); |
} |
} |
|
#ifdef HAVE_DARWIN_XATTR |
#define SETXATTR(PATH, NAME, BUF, SZ, FL) setxattr(PATH, NAME, BUF, SZ, 0, FL) |
#define LSETXATTR(PATH, NAME, BUF, SZ, FL) setxattr(PATH, NAME, BUF, SZ, 0, (FL)|XATTR_NOFOLLOW) |
#else |
#define SETXATTR(PATH, NAME, BUF, SZ, FL) setxattr(PATH, NAME, BUF, SZ, FL) |
#define LSETXATTR(PATH, NAME, BUF, SZ, FL) lsetxattr(PATH, NAME, BUF, SZ, FL) |
#endif /* !HAVE_DARWIN_XATTR */ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void f_setxattr( INT32 args ) |
{ |
char *ind, *file; |
struct pike_string *val; |
int flags; |
int rv; |
int nofollow=0; |
get_all_args( "setxattr", args, "%s%s%S%d.%d", &file, &ind, &val, &flags, &nofollow ); |
|
THREADS_ALLOW(); |
if (nofollow) { |
while(((rv=LSETXATTR(file, ind, val->str, |
(val->len<<val->size_shift), flags )) < 0) && |
(errno == EINTR)) |
; |
} else { |
while(((rv=SETXATTR(file, ind, val->str, |
(val->len<<val->size_shift), flags )) < 0) && |
(errno == EINTR)) |
; |
} |
THREADS_DISALLOW(); |
pop_n_elems(args); |
if( rv < 0 ) |
{ |
push_int(0); |
} |
else |
push_int(1); |
} |
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void f_file_stat(INT32 args) |
{ |
PIKE_STAT_T st; |
int i, l; |
struct pike_string *str; |
|
if(args<1) |
SIMPLE_TOO_FEW_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)"); |
|
str = sp[-args].u.string; |
l = (args>1 && !UNSAFE_IS_ZERO(sp+1-args))?1:0; |
|
if (string_has_null(str)) { |
|
errno = ENOENT; |
pop_n_elems(args); |
push_int(0); |
return; |
} |
|
THREADS_ALLOW_UID(); |
do { |
#ifdef HAVE_LSTAT |
if(l) |
i=fd_lstat(str->str, &st); |
else |
#endif |
i=fd_stat(str->str, &st); |
} while ((i == -1) && (errno == EINTR)); |
|
THREADS_DISALLOW_UID(); |
pop_n_elems(args); |
if(i==-1) |
{ |
push_int(0); |
}else{ |
push_stat(&st); |
} |
} |
|
|
|
|
|
|
|
|
void f_file_truncate(INT32 args) |
{ |
#if defined(INT64) |
INT64 len = 0; |
#else |
off_t len = 0; |
#endif |
struct pike_string *str; |
int res; |
|
if(args < 2) |
SIMPLE_TOO_FEW_ARGS_ERROR("file_truncate", 2); |
if(TYPEOF(sp[-args]) != T_STRING) |
SIMPLE_BAD_ARG_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"); |
else |
len = sp[1-args].u.integer; |
|
str = sp[-args].u.string; |
|
if (string_has_null(str)) { |
|
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__ */ |
|
pop_n_elems(args); |
|
push_int(!res); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#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; |
char _p[4]; |
char *p = _p; |
unsigned int free_sectors; |
unsigned int total_sectors; |
|
get_all_args( "filesystem_stat", args, "%s", &path ); |
|
if(sp[-1].u.string->len < 2 || path[1] != ':') |
{ |
p = 0; |
} else { |
p[0] = path[0]; |
p[1] = ':'; |
p[2] = '\\'; |
p[3] = 0; |
} |
|
if(!GetDiskFreeSpace( p, §ors_per_cluster, |
&bytes_per_sector, |
&free_clusters, |
&total_clusters )) |
{ |
pop_n_elems(args); |
push_int( 0 ); |
return; |
} |
|
free_sectors = sectors_per_cluster * free_clusters; |
total_sectors = sectors_per_cluster * total_clusters; |
|
pop_n_elems( args ); |
push_text("blocksize"); |
push_int(bytes_per_sector); |
push_text("blocks"); |
push_int(total_sectors); |
push_text("bfree"); |
push_int(free_sectors); |
push_text("bavail"); |
push_int(free_sectors); |
f_aggregate_mapping( 8 ); |
} |
|
#else /* !__NT__ */ |
|
#if !defined(HAVE_STRUCT_STATFS) && !defined(HAVE_STRUCT_FS_DATA) |
#undef HAVE_STATFS |
#endif |
|
#if defined(HAVE_STATVFS) || defined(HAVE_STATFS) || defined(HAVE_USTAT) |
#ifdef HAVE_SYS_STATVFS_H |
|
#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> |
#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> |
#endif /* HAVE_USTAT_H */ |
#endif /* !HAVE_STATVFS && !HAVE_STATFS */ |
void f_filesystem_stat(INT32 args) |
{ |
#ifdef HAVE_STATVFS |
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 |
|
struct fs_data st; |
#else /* !HAVE_STRUCT_FS_DATA */ |
|
#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 */ |
|
#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(TYPEOF(sp[-args]) != T_STRING) |
SIMPLE_BAD_ARG_ERROR("filesystem_stat", 1, "string"); |
|
str = sp[-args].u.string; |
|
if (string_has_null(str)) { |
|
errno = ENOENT; |
pop_n_elems(args); |
push_int(0); |
return; |
} |
|
THREADS_ALLOW(); |
#ifdef HAVE_STATVFS |
i = statvfs(str->str, &st); |
#else /* !HAVE_STATVFS */ |
#ifdef HAVE_STATFS |
#ifdef HAVE_SYSV_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 |
|
#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; |
#ifdef HAVE_STATVFS |
#if 0 |
push_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); |
num_fields += 7; |
#ifdef HAVE_STATVFS_F_FSTR |
push_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); |
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); |
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); |
num_fields += 6; |
#ifdef HAVE_STATFS_F_BAVAIL |
push_text("bavail"); push_int(st.f_bavail); |
num_fields++; |
#endif /* HAVE_STATFS_F_BAVAIL */ |
#else /* !HAVE_STRUCT_STATFS */ |
#ifdef HAVE_STRUCT_FS_DATA |
|
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); |
num_fields += 4; |
#else /* !HAVE_STRUCT_FS_DATA */ |
|
#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(st.f_fname); |
num_fields += 3; |
#else |
|
#error No stat function for filesystems. |
#endif /* HAVE_USTAT */ |
#endif /* HAVE_STATFS */ |
#endif /* HAVE_STATVFS */ |
f_aggregate_mapping(num_fields*2); |
} |
} |
|
#endif /* HAVE_STATVFS || HAVE_STATFS || HAVE_USTAT */ |
#endif /* __NT__ */ |
|
|
|
|
|
|
|
|
|
|
|
void f_rm(INT32 args) |
{ |
PIKE_STAT_T st; |
INT32 i; |
struct pike_string *str; |
|
destruct_objects_to_destruct(); |
|
if(!args) |
SIMPLE_TOO_FEW_ARGS_ERROR("rm", 1); |
|
if(TYPEOF(sp[-args]) != T_STRING) |
SIMPLE_BAD_ARG_ERROR("rm", 1, "string"); |
|
str = sp[-args].u.string; |
|
if (string_has_null(str)) { |
|
errno = ENOENT; |
pop_n_elems(args); |
push_int(0); |
return; |
} |
|
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)) |
; |
}else{ |
while (!(i = unlink(str->str) != -1) && (errno == EINTR)) |
; |
} |
#ifdef __NT__ |
|
* 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) { |
int olderrno = errno; |
chmod(str->str, st.st_mode); |
errno = olderrno; |
} |
} |
} |
#endif |
} |
THREADS_DISALLOW_UID(); |
|
pop_n_elems(args); |
push_int(i); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void f_mkdir(INT32 args) |
{ |
struct pike_string *str; |
int mode; |
int i; |
char *s, *s_dup; |
|
if(!args) |
SIMPLE_TOO_FEW_ARGS_ERROR("mkdir", 1); |
|
if(TYPEOF(sp[-args]) != T_STRING) |
SIMPLE_BAD_ARG_ERROR("mkdir", 1, "string"); |
|
mode = 0777; |
|
if(args > 1) |
{ |
if(TYPEOF(sp[1-args]) != T_INT) |
Pike_error("Bad argument 2 to mkdir.\n"); |
|
mode = sp[1-args].u.integer; |
} |
|
str = sp[-args].u.string; |
|
if (string_has_null(str)) { |
|
errno = EINVAL; |
pop_n_elems(args); |
push_int(0); |
return; |
} |
|
|
|
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; |
THREADS_DISALLOW_UID(); |
#else |
|
#ifdef HAVE_LSTAT |
#define LSTAT lstat |
#else |
#define LSTAT stat |
#endif |
|
{ |
|
int mask = umask(0); |
|
|
|
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) { |
|
|
|
|
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) |
#define HAVE_READDIR_R |
#endif |
|
#if defined(_REENTRANT) && defined(HAVE_READDIR_R) |
|
#ifdef _PC_NAME_MAX |
#ifdef HAVE_FPATHCONF |
|
#ifdef HAVE_FDOPENDIR |
#define USE_FDOPENDIR |
#define USE_FPATHCONF |
#elif defined(HAVE_DIRFD) |
#define USE_FPATHCONF |
#endif |
|
#endif /* HAVE_FPATHCONF */ |
|
#if defined(HAVE_PATHCONF) && !defined(USE_FPATHCONF) |
#define USE_PATHCONF |
#endif |
#endif /* _PC_NAME_MAX */ |
|
#endif /* _REENTRANT && HAVE_READDIR_R */ |
|
|
|
|
|
|
|
|
|
|
#ifdef __NT__ |
void f_get_dir(INT32 args) |
{ |
HANDLE dir; |
WIN32_FIND_DATAW d; |
struct string_builder sb; |
struct pike_string *str=0; |
|
get_all_args("get_dir",args,".%T",&str); |
|
if(!str) { |
push_text("."); |
str = Pike_sp[-1].u.string; |
args++; |
} |
|
if (str->size_shift == 2) { |
|
errno = ENOENT; |
pop_n_elems(args); |
push_int(0); |
return; |
} |
|
init_string_builder_alloc(&sb, str->len+2, 1); |
|
string_builder_shared_strcat(&sb, str); |
|
|
if (sb.s->len && (STR1(sb.s)[sb.s->len-1] != '/') && |
(STR1(sb.s)[sb.s->len-1] != '\\')) { |
STR1(sb.s)[sb.s->len++] = '/'; |
} |
STR1(sb.s)[sb.s->len++] = '*'; |
STR1(sb.s)[sb.s->len] = '\0'; |
|
if (wcslen(STR1(sb.s)) != (size_t)sb.s->len) { |
|
free_string_builder(&sb); |
errno = ENOENT; |
pop_n_elems(args); |
push_int(0); |
return; |
} |
|
#ifdef READDIR_DEBUG |
fprintf(stderr, "FindFirstFile(\"%S\")...\n", STR1(sb.s)); |
#endif /* READDIR_DEBUG */ |
|
dir = FindFirstFileW(STR1(sb.s), &d); |
|
free_string_builder(&sb); |
|
if (dir == DO_NOT_WARN(INVALID_HANDLE_VALUE)) { |
int err = GetLastError(); |
#ifdef READDIR_DEBUG |
fprintf(stderr, " INVALID_HANDLE_VALUE, error %d\n", err); |
#endif /* READDIR_DEBUG */ |
|
pop_n_elems(args); |
if (err == ERROR_FILE_NOT_FOUND) { |
|
|
|
|
|
|
|
push_empty_array(); |
} |
else { |
set_errno_from_win32_error (err); |
push_int(0); |
} |
return; |
} |
|
{ |
int err; |
|
BEGIN_AGGREGATE_ARRAY(10); |
|
do { |
#ifdef READDIR_DEBUG |
fprintf(stderr, " \"%S\"\n", d.cFileName); |
#endif /* READDIR_DEBUG */ |
|
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))); |
DO_AGGREGATE_ARRAY(120); |
} while(FindNextFileW(dir, &d)); |
err = GetLastError(); |
|
#ifdef READDIR_DEBUG |
fprintf(stderr, " DONE, error %d\n", err); |
#endif /* READDIR_DEBUG */ |
|
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__ */ |
|
|
void low_get_dir(DIR *dir, ptrdiff_t name_max) |
{ |
if(dir) { |
struct dirent *d; |
struct dirent *tmp = NULL; |
#if defined(_REENTRANT) && defined(HAVE_READDIR_R) |
#define FPR 1024 |
char buffer[MAXPATHLEN * 4]; |
char *ptrs[FPR]; |
ptrdiff_t lens[FPR]; |
|
#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) |
while(1) |
{ |
int e; |
int num_files=0; |
char *bufptr=buffer; |
int err = 0; |
|
THREADS_ALLOW(); |
|
while(1) |
{ |
#if defined(HAVE_SOLARIS_READDIR_R) |
|
* and returns NULL on error or at end of dir. |
*/ |
errno=0; |
do { |
d=readdir_r(dir, tmp); |
} while ((!d) && ((errno == EAGAIN)||(errno == EINTR))); |
if (!d) { |
|
|
if (errno == ENOENT) { |
err = 0; |
} else { |
err = errno; |
} |
break; |
} |
#elif defined(HAVE_HPUX_READDIR_R) |
|
* |
* 0 - Successfull operation. |
* -1 - End of directory or encountered an error (sets errno). |
*/ |
errno=0; |
if (readdir_r(dir, tmp)) { |
d = NULL; |
err = errno; |
break; |
} else { |
d = tmp; |
} |
#elif defined(HAVE_POSIX_READDIR_R) |
|
* at end of dir it sets the third arg to NULL. |
*/ |
d = NULL; |
errno = 0; |
if ((err = readdir_r(dir, tmp, &d)) || !d) { |
#ifdef READDIR_DEBUG |
fprintf(stderr, "POSIX readdir_r() => err %d\n", err); |
fprintf(stderr, "POSIX readdir_r(), d= 0x%08x\n", (unsigned int)d); |
#endif /* READDIR_DEBUG */ |
if (err == -1) { |
|
err = errno; |
} |
#ifdef READDIR_DEBUG |
fprintf(stderr, "POSIX readdir_r() => errno %d\n", err); |
#endif /* READDIR_DEBUG */ |
|
* |
* 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\"\n", d->d_name); |
#endif /* READDIR_DEBUG */ |
#else |
#error Unknown readdir_r variant |
#endif |
|
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]); |
ptrs[num_files]=bufptr; |
bufptr+=lens[num_files]; |
num_files++; |
} |
THREADS_DISALLOW(); |
if ((!d) && err) { |
free(tmp); |
Pike_error("get_dir(): readdir_r() failed: %d\n", err); |
} |
#ifdef READDIR_DEBUG |
fprintf(stderr, "Pushing %d filenames...\n", num_files); |
#endif /* READDIR_DEBUG */ |
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)) |
{ |
#ifdef READDIR_DEBUG |
fprintf(stderr, "readdir(): %s\n", d->d_name); |
#endif /* READDIR_DEBUG */ |
|
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; |
} else { |
push_int(0); |
} |
} |
|
void f_get_dir(INT32 args) |
{ |
#ifdef USE_FDOPENDIR |
int dir_fd; |
#endif |
DIR *dir = NULL; |
#ifdef HAVE_READDIR_R |
ptrdiff_t name_max = -1; |
#endif |
struct pike_string *str=0; |
|
get_all_args("get_dir",args,".%N",&str); |
|
if(!str) { |
#if defined(__amigaos4__) |
push_empty_string(); |
#else |
push_text("."); |
#endif |
str = Pike_sp[-1].u.string; |
args++; |
} |
|
if (string_has_null(str)) { |
|
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(); |
|
low_get_dir(dir, name_max); |
stack_pop_n_elems_keep_top(args); |
} |
#endif /* __NT__ */ |
|
|
|
|
|
|
|
|
|
|
|
void f_cd(INT32 args) |
{ |
INT32 i; |
struct pike_string *str; |
|
if(!args) |
SIMPLE_TOO_FEW_ARGS_ERROR("cd", 1); |
|
if(TYPEOF(sp[-args]) != T_STRING) |
SIMPLE_BAD_ARG_ERROR("cd", 1, "string"); |
|
str = sp[-args].u.string; |
|
if (string_has_null(str)) { |
|
errno = ENOENT; |
pop_n_elems(args); |
push_int(0); |
return; |
} |
|
i = chdir(str->str) != -1; |
pop_n_elems(args); |
push_int(i); |
} |
|
|
|
|
|
|
|
|
void f_getcwd(INT32 args) |
{ |
char *e; |
char *tmp; |
#if defined(HAVE_WORKING_GETCWD) || !defined(HAVE_GETWD) |
INT32 size; |
|
size=1000; |
do { |
tmp=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); |
Pike_error("Failed to fetch current path.\n"); |
} |
|
pop_n_elems(args); |
push_text(e); |
free(tmp); |
} |
|
#ifdef HAVE_EXECVE |
|
*! @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]. |
*! |
*! If the mapping @[env] is present, it will completely replace all |
*! environment variables before the new program is executed. |
*! |
*! @returns |
*! This function only returns if something went wrong during @tt{exece(2)@}, |
*! and in that case it returns @expr{0@} (zero). |
*! |
*! @note |
*! The Pike driver _dies_ when this function is called. You must either |
*! use @[fork()] or @[Process.create_process()] if you wish to execute a |
*! program and still run the Pike runtime. |
*! |
*! This function is not available on all platforms. |
*! |
*! @seealso |
*! @[Process.create_process()], @[fork()], @[Stdio.File->pipe()] |
*/ |
void f_exece(INT32 args) |
{ |
INT32 e; |
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); |
|
e=0; |
en=0; |
switch(args) |
{ |
default: |
if(TYPEOF(sp[2-args]) != T_MAPPING) |
SIMPLE_BAD_ARG_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)"); |
if(m_val_types(en) & ~BIT_STRING) |
SIMPLE_BAD_ARG_ERROR("exece", 3, "mapping(string:string)"); |
|
case 2: |
if(TYPEOF(sp[1-args]) != T_ARRAY) |
SIMPLE_BAD_ARG_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)"); |
|
case 1: |
if(TYPEOF(sp[0-args]) != T_STRING) |
SIMPLE_BAD_ARG_ERROR("exece", 1, "string"); |
} |
|
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=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) { |
ref_push_string(k->ind.u.string); |
push_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; |
} |
|
my_set_close_on_exec(0,0); |
my_set_close_on_exec(1,0); |
my_set_close_on_exec(2,0); |
|
do_set_close_on_exec(); |
|
#ifdef __NT__ |
#define DOCAST(X) ((const char * const *)(X)) |
#else |
#define DOCAST(X) (X) |
#endif |
|
#ifdef HAVE_BROKEN_F_SETFD |
do_close_on_exec(); |
#endif /* HAVE_BROKEN_F_SETFD */ |
|
execve(argv[0],DOCAST(argv),DOCAST(env)); |
|
free((char *)argv); |
if(env != environ) free((char *)env); |
pop_n_elems(sp-save_sp); |
push_int(0); |
} |
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
|
if(args<2) |
SIMPLE_TOO_FEW_ARGS_ERROR("mv", 2); |
|
if(TYPEOF(sp[-args]) != T_STRING) |
SIMPLE_BAD_ARG_ERROR("mv", 1, "string"); |
|
if(TYPEOF(sp[-args+1]) != T_STRING) |
SIMPLE_BAD_ARG_ERROR("mv", 2, "string"); |
|
str1 = sp[-args].u.string; |
str2 = sp[1-args].u.string; |
|
if (string_has_null(str1) || string_has_null(str2)) { |
|
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 |
|
|
|
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 { |
|
|
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) { |
|
if (!(st.st_mode & _S_IWRITE)) |
|
|
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; |
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) { |
|
|
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]))) { |
|
FindClose (h); |
free (dir); |
goto nt_rename_kludge_end; |
} |
} while (FindNextFile (h, dir)); |
FindClose (h); |
} |
free (dir); |
} |
|
|
|
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) { |
i = 0; |
goto nt_rename_kludge_end; |
} |
|
nt_rename_kludge_fail: |
|
|
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)) { |
|
|
|
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) { |
|
|
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); |
} |
|
|
|
|
|
|
|
|
|
void f_strerror(INT32 args) |
{ |
char *s; |
int err; |
|
if(!args) |
SIMPLE_TOO_FEW_ARGS_ERROR("strerror", 1); |
if(TYPEOF(sp[-args]) != T_INT) |
SIMPLE_BAD_ARG_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_text("Error "); |
push_int(err); |
f_add(2); |
} |
} |
|
|
|
|
|
|
|
|
|
|
|
static void f_errno(INT32 args) |
{ |
pop_n_elems(args); |
push_int(errno); |
} |
|
|
#if defined(HAVE_ACCESS) |
|
*! |
*! 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"@}. |
*! |
*! r, w, and x test whether the file exists and grants read, write, |
*! and execute permissions, respectively. |
*! |
*! The check is done using the calling process's real UID and GID, |
*! rather than the effective IDs as is done when actually attempting |
*! an operation (e.g., open(2)) on the file. This allows set-user-ID |
*! programs to easily determine the invoking user's authority. |
*! |
*! If the calling process is privileged (i.e., its real UID is zero), |
*! then an X_OK check is successful for a regular file if execute |
*! permission is enabled for any of the file owner, group, or other. |
*! |
*! @returns |
*! @int |
*! @value 1 |
*! When the file is accessible using the given permissions. |
*! |
*! @value 0 |
*! When the file is not accessible, in which case @[errno] is set |
*! to one of the following values: |
*! |
*! @int |
*! @value EACCESS |
*! Access denied. |
*! |
*! @value ELOOP |
*! Too many symbolic links. |
*! |
*! @value ENAMETOOLONG |
*! The path is too long. |
*! |
*! @value ENOENT |
*! The file does not exist. |
*! |
*! @value ENOTDIR |
*! One of the directories used in @[path] is not, in fact, a directory. |
*! |
*! @value EROFS |
*! The filesystem is read only and write access was requested. |
*! @endint |
*! |
*! Other errors can occur, but are not directly related to the |
*! requested path, such as @expr{ENOMEM@}, etc. |
*! @endint |
*! |
*! @seealso |
*! @[errno()], @[Stdio.File] |
*/ |
static void f_access( INT32 args ) |
{ |
const char *path; |
int flags, res; |
if( args == 2 ) |
{ |
char *how; |
int i; |
get_all_args( "access", args, "%s%s", &path, &how ); |
flags = 0; |
for( i=0; how[i]; i++ ) |
{ |
switch( how[i] ) |
{ |
case 'r': flags |= R_OK; break; |
case 'w': flags |= W_OK; break; |
case 'x': flags |= X_OK; break; |
} |
} |
if( !flags ) |
flags = F_OK; |
} |
else |
{ |
get_all_args( "access", args, "%s", &path ); |
flags = F_OK; |
} |
|
THREADS_ALLOW_UID(); |
do { |
res = access( path, flags ); |
} while( (res == -1) && (errno == EINTR) ) |
THREADS_DISALLOW_UID(); |
|
pop_n_elems(args); |
push_int( !res ); |
} |
#endif |
|
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(); |
#endif |
#endif /* 0 */ |
|
#ifdef __NT__ |
{ |
|
|
|
OSVERSIONINFO osversion; |
osversion.dwOSVersionInfoSize=sizeof(osversion); |
if(GetVersionEx(&osversion)) |
{ |
switch(osversion.dwPlatformId) |
{ |
case VER_PLATFORM_WIN32s: |
case VER_PLATFORM_WIN32_WINDOWS: |
break; |
default: |
if ((kernel32lib = LoadLibrary ("kernel32"))) |
movefileex = (movefileextype) GetProcAddress (kernel32lib, "MoveFileExA"); |
} |
} |
} |
#endif |
|
|
ADD_EFUN("file_stat",f_file_stat,tFunc(tStr tOr(tInt,tVoid),tObjIs_STDIO_STAT), OPT_EXTERNAL_DEPEND|OPT_SIDE_EFFECT); |
|
|
ADD_EFUN("file_truncate",f_file_truncate,tFunc(tStr tInt,tInt),OPT_EXTERNAL_DEPEND|OPT_SIDE_EFFECT); |
#if defined(HAVE_ACCESS) |
ADD_EFUN("access", f_access, tFunc(tStr tOr(tVoid,tStr),tInt),OPT_EXTERNAL_DEPEND); |
#endif |
#if defined(HAVE_FSETXATTR) && defined(HAVE_FGETXATTR) && defined(HAVE_FLISTXATTR) |
ADD_EFUN( "listxattr", f_listxattr, tFunc(tStr tOr(tVoid,tInt),tArr(tStr)), OPT_EXTERNAL_DEPEND|OPT_SIDE_EFFECT); |
ADD_EFUN( "setxattr", f_setxattr, tFunc(tStr tStr tStr tInt tOr(tVoid,tInt),tInt), OPT_EXTERNAL_DEPEND|OPT_SIDE_EFFECT); |
ADD_EFUN( "getxattr", f_getxattr, tFunc(tStr tStr tOr(tVoid,tInt),tStr), OPT_EXTERNAL_DEPEND|OPT_SIDE_EFFECT); |
ADD_EFUN( "removexattr", f_removexattr, tFunc(tStr tStr tOr(tVoid,tInt),tInt), OPT_EXTERNAL_DEPEND|OPT_SIDE_EFFECT); |
#endif |
|
#if defined(HAVE_STATVFS) || defined(HAVE_STATFS) || defined(HAVE_USTAT) || defined(__NT__) |
|
|
ADD_EFUN("filesystem_stat", f_filesystem_stat,tFunc(tStr,tMap(tStr,tOr(tStr,tInt))), OPT_EXTERNAL_DEPEND|OPT_SIDE_EFFECT); |
#endif /* HAVE_STATVFS || HAVE_STATFS */ |
|
|
ADD_EFUN("errno",f_errno,tFunc(tNone,tInt),OPT_EXTERNAL_DEPEND); |
|
|
ADD_EFUN("rm",f_rm,tFunc(tStr,tInt),OPT_SIDE_EFFECT); |
|
|
ADD_EFUN("mkdir",f_mkdir,tFunc(tStr tOr(tVoid,tInt),tInt),OPT_SIDE_EFFECT); |
|
|
ADD_EFUN("mv", f_mv,tFunc(tStr tStr,tInt), OPT_SIDE_EFFECT); |
|
|
ADD_EFUN("get_dir",f_get_dir,tFunc(tOr(tVoid,tStr),tArr(tStr)),OPT_EXTERNAL_DEPEND|OPT_SIDE_EFFECT); |
|
|
ADD_EFUN("cd",f_cd,tFunc(tStr,tInt),OPT_SIDE_EFFECT); |
|
|
ADD_EFUN("getcwd",f_getcwd,tFunc(tNone,tStr),OPT_EXTERNAL_DEPEND|OPT_SIDE_EFFECT); |
|
#ifdef HAVE_EXECVE |
|
ADD_EFUN("exece",f_exece,tFunc(tStr tArr(tMix) tOr(tVoid,tMap(tStr,tStr)),tInt),OPT_SIDE_EFFECT); |
#endif |
|
|
ADD_EFUN("strerror",f_strerror,tFunc(tInt,tStr),0); |
} |
|
void exit_stdio_efuns(void) |
{ |
#ifdef __NT__ |
if (kernel32lib) { |
if (FreeLibrary (kernel32lib)) |
movefileex = 0; |
kernel32lib = 0; |
} |
#endif |
#if 0 |
#ifdef HAVE_LIBZFS_INIT |
libzfs_fini(libzfs_handle); |
#endif |
#endif /* 0 */ |
} |
|
|