e576bb2002-10-11Martin Nilsson /* || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. */
f9bec92000-08-27Henrik Grubbström (Grubba) 
61a4242000-08-27Mirar (Pontus Hagland) #include "global.h" #include "fdlib.h" #include "interpret.h" #include "svalue.h" #include "bignum.h" #include "mapping.h" #include "object.h" #include "builtin_functions.h"
aaea902000-08-28Henrik Grubbström (Grubba) #include "operators.h"
29e4fc2000-08-29Martin Stjernholm #include "program_id.h"
e60b072005-04-30Per Hedbor #include "file_machine.h"
61a4242000-08-27Mirar (Pontus Hagland) 
f9bec92000-08-27Henrik Grubbström (Grubba) #include <sys/stat.h> #ifdef HAVE_SYS_PARAM_H #include <sys/param.h> #endif /* HAVE_SYS_PARAM_H */
d569182002-05-11Martin Nilsson #define sp Pike_sp #define fp Pike_fp
54fe392002-03-05Martin Stjernholm /*! @module Stdio */ /*! @class Stat *! *! This object is used to represent file status information *! from e.g. @[file_stat()]. *! *! It contains the following items usually found in a C @tt{struct *! stat@}: *! @dl *! @item mode *! File mode (see @tt{mknod(2)@}). *! @item size *! File size in bytes. *! @item uid *! User ID of the file's owner. *! @item gid *! Group ID of the file's owner. *! @item atime *! Time of last access in seconds since 00:00:00 UTC, 1970-01-01. *! @item mtime *! Time of last data modification. *! @item ctime *! Time of last file status change. *! @item ino *! Inode number. *! @item nlink *! Number of links. *! @item dev *! ID of the device containing a directory entry for this file. *! @item rdev *! ID of the device. *! @enddl *! *! It also contains some items that correspond to the C @tt{IS*@} macros: *! @dl *! @item isreg *! Set if the file is a regular file. *! @item isdir *! Set if the file is a directory. *! @item islnk *! Set if the file is a symbolic link. Note that symbolic links *! are normally followed by the stat functions, so this might *! only be set if you turn that off, e.g. by giving a nonzero *! second argument to @[file_stat()]. *! @item isfifo *! Set if the file is a FIFO (aka named pipe). *! @item issock *! Set if the file is a socket. *! @item ischr *! Set if the file is a character device. *! @item isblk *! Set if the file is a block device. *! @enddl *! *! There are also some items that provide alternative representations *! of the above: *! @dl *! @item type
cbe8c92003-04-07Martin Nilsson  *! The type as a string, can be any of @expr{"reg"@}, *! @expr{"dir"@}, @expr{"lnk"@}, @expr{"fifo"@}, @expr{"sock"@}, *! @expr{"chr"@}, @expr{"blk"@}, and @expr{"unknown"@}.
54fe392002-03-05Martin Stjernholm  *! @item mode_string *! The file mode encoded as a string in @tt{ls -l@} style, e.g.
cbe8c92003-04-07Martin Nilsson  *! @expr{"drwxr-xr-x"@}.
54fe392002-03-05Martin Stjernholm  *! @enddl *! *! Note that some items might not exist or have meaningful values *! on some platforms. *! *! Additionally, the object may be initialized from or casted to an
cbe8c92003-04-07Martin Nilsson  *! @expr{array@} on the form of a 'traditional' LPC stat-array, and
54fe392002-03-05Martin Stjernholm  *! it's also possible to index the object directly with integers as *! if it were such an array. The stat-array has this format: *! *! @array *! @elem int 0 *! File mode, same as @tt{mode@}. *! @elem int 1 *! If zero or greater, the file is a regular file and this is *! its size in bytes. If less than zero it gives the type: *! -2=directory, -3=symlink and -4=device. *! @elem int 2 *! Time of last access, same as @tt{atime@}. *! @elem int 3 *! Time of last data modification, same as @tt{mtime@}. *! @elem int 4 *! Time of last file status change, same as @tt{ctime@}. *! @elem int 5 *! User ID of the file's owner, same as @tt{uid@}. *! @elem int 6 *! Group ID of the file's owner, same as @tt{gid@}. *! @endarray *! *! It's possible to modify the stat struct by assigning values to *! the items. They essentially work as variables, although some of
cbe8c92003-04-07Martin Nilsson  *! them affect others, e.g. setting @expr{isdir@} clears @expr{isreg@} *! and setting @expr{mode_string@} changes many of the other items.
54fe392002-03-05Martin Stjernholm  */
29e4fc2000-08-29Martin Stjernholm /* Let's define these mode flags if they don't exist, so reading and * writing the Stat structure will behave identically regardless of * OS. */
0c2bfe2000-08-28Henrik Grubbström (Grubba)  #ifndef S_IFMT #define S_IFMT 0xf000 #endif /* !S_IFMT */ #ifndef S_IFREG #define S_IFREG 0x8000 #endif /* !S_IFREG */
29e4fc2000-08-29Martin Stjernholm #ifndef S_IFLNK #define S_IFLNK 0xA000 #endif /* !S_IFLNK */ #ifndef S_IFDIR #define S_IFDIR 0x4000 #endif /* !S_IFDIR */ #ifndef S_IFCHR #define S_IFCHR 0x2000 #endif /* !S_IFCHR */ #ifndef S_IFBLK #define S_IFBLK 0x6000 #endif /* !S_IFBLK */ #ifndef S_IFIFO #define S_IFIFO 0x1000 #endif /* !S_IFIFO */ #ifndef S_IFSOCK #define S_IFSOCK 0xC000 #endif /* !S_IFSOCK */
0c2bfe2000-08-28Henrik Grubbström (Grubba)  #ifndef S_IRUSR #define S_IRUSR 0400 #endif /* !S_IRUSR */ #ifndef S_IWUSR #define S_IWUSR 0200 #endif /* !S_IWUSR */ #ifndef S_IXUSR #define S_IXUSR 0100 #endif /* !S_IXUSR */ #ifndef S_IRGRP #define S_IRGRP 040 #endif /* !S_IRGRP */ #ifndef S_IWGRP #define S_IWGRP 020 #endif /* !S_IWGRP */
e3b77f2000-08-28Henrik Grubbström (Grubba) #ifndef S_IXGRP #define S_IXGRP 010 #endif /* !S_IXGRP */
0c2bfe2000-08-28Henrik Grubbström (Grubba) #ifndef S_IROTH #define S_IROTH 04 #endif /* !S_IROTH */ #ifndef S_IWOTH #define S_IWOTH 02 #endif /* !S_IWOTH */ #ifndef S_IXOTH #define S_IXOTH 01 #endif /* !S_IXOTH */
29e4fc2000-08-29Martin Stjernholm #ifndef S_ISUID #define S_ISUID 0x800 #endif /* !S_ISUID */ #ifndef S_ISGID #define S_ISGID 0x400 #endif /* !S_ISGID */ #ifndef S_ISVTX #define S_ISVTX 0x200 #endif /* !S_ISVTX */
f38fdd2011-10-29Henrik Grubbström (Grubba) PMOD_EXPORT struct program *stat_program=NULL;
29e4fc2000-08-29Martin Stjernholm  struct stat_storage { /* Note: stat_create assumes there are no refs in here. */
40962a2003-03-27Martin Stjernholm  PIKE_STAT_T s;
29e4fc2000-08-29Martin Stjernholm }; static struct mapping *stat_map=NULL; enum stat_query {STAT_DEV=1, STAT_INO, STAT_MODE, STAT_NLINK, STAT_UID, STAT_GID, STAT_RDEV,
b00ea02000-08-30Martin Stjernholm  STAT_SIZE,
e60b072005-04-30Per Hedbor #ifdef HAVE_STRUCT_STAT_BLOCKS
b00ea02000-08-30Martin Stjernholm  STAT_BLKSIZE, STAT_BLOCKS, #endif STAT_ATIME, STAT_MTIME, STAT_CTIME,
29e4fc2000-08-29Martin Stjernholm /* is... */ STAT_ISLNK, STAT_ISREG, STAT_ISDIR, STAT_ISCHR, STAT_ISBLK, STAT_ISFIFO, STAT_ISSOCK, /* special */ STAT_TYPE, STAT_MODE_STRING, /* end marker */ STAT_ENUM_END}; static struct pike_string *stat_index_strs[STAT_ENUM_END]; static struct pike_string *str_type_reg, *str_type_dir, *str_type_lnk, *str_type_chr, *str_type_blk, *str_type_fifo, *str_type_sock, *str_type_unknown;
d569182002-05-11Martin Nilsson #define THIS_STAT ((struct stat_storage*)(Pike_fp->current_storage))
29e4fc2000-08-29Martin Stjernholm  static void stat_index_set (INT32 args);
0a5eae2001-07-02Martin Stjernholm static int stat_compat_set (INT_TYPE pos, INT64 val)
29e4fc2000-08-29Martin Stjernholm {
0a5eae2001-07-02Martin Stjernholm  if (pos < 0) pos += 7;
29e4fc2000-08-29Martin Stjernholm  switch (pos) {
097de92006-07-05Martin Stjernholm  case 0: DO_NOT_WARN(THIS_STAT->s.st_mode = (int) val); break;
29e4fc2000-08-29Martin Stjernholm  case 1: if (val >= 0) { THIS_STAT->s.st_mode = (THIS_STAT->s.st_mode & ~S_IFMT) | S_IFREG;
097de92006-07-05Martin Stjernholm  THIS_STAT->s.st_size = DO_NOT_WARN ((off_t) val);
29e4fc2000-08-29Martin Stjernholm  } else { THIS_STAT->s.st_size = 0; if (val == -2) THIS_STAT->s.st_mode = (THIS_STAT->s.st_mode & ~S_IFMT) | S_IFDIR; else if (val == -3) THIS_STAT->s.st_mode = (THIS_STAT->s.st_mode & ~S_IFMT) | S_IFLNK; else THIS_STAT->s.st_mode = THIS_STAT->s.st_mode & ~S_IFMT; } break;
097de92006-07-05Martin Stjernholm  case 2: THIS_STAT->s.st_atime = DO_NOT_WARN ((time_t) val); break; case 3: THIS_STAT->s.st_mtime = DO_NOT_WARN ((time_t) val); break; case 4: THIS_STAT->s.st_ctime = DO_NOT_WARN ((time_t) val); break; case 5: DO_NOT_WARN(THIS_STAT->s.st_uid = (int) val); break; case 6: DO_NOT_WARN(THIS_STAT->s.st_gid = (int) val); break;
29e4fc2000-08-29Martin Stjernholm  default: return 0; } return 1; }
61a4242000-08-27Mirar (Pontus Hagland)  static void stat_push_compat(INT_TYPE n) {
0a5eae2001-07-02Martin Stjernholm  if (n < 0) n += 7;
61a4242000-08-27Mirar (Pontus Hagland)  switch (n) {
0c2bfe2000-08-28Henrik Grubbström (Grubba)  case 0: push_int(THIS_STAT->s.st_mode); break;
61a4242000-08-27Mirar (Pontus Hagland)  case 1:
0c2bfe2000-08-28Henrik Grubbström (Grubba)  switch(S_IFMT & THIS_STAT->s.st_mode)
61a4242000-08-27Mirar (Pontus Hagland)  { case S_IFREG:
0c2bfe2000-08-28Henrik Grubbström (Grubba)  push_int64(THIS_STAT->s.st_size);
61a4242000-08-27Mirar (Pontus Hagland)  break; case S_IFDIR: push_int(-2); break; case S_IFLNK: push_int(-3); break; default: #ifdef DEBUG_FILE fprintf(stderr, "encode_stat(): mode:%ld\n",
0c2bfe2000-08-28Henrik Grubbström (Grubba)  (long)S_IFMT & THIS_STAT->s.st_mode);
61a4242000-08-27Mirar (Pontus Hagland) #endif /* DEBUG_FILE */ push_int(-4); break; } break;
0c2bfe2000-08-28Henrik Grubbström (Grubba)  case 2: push_int64(THIS_STAT->s.st_atime); break; case 3: push_int64(THIS_STAT->s.st_mtime); break; case 4: push_int64(THIS_STAT->s.st_ctime); break;
29e4fc2000-08-29Martin Stjernholm  case 5: push_int(THIS_STAT->s.st_uid); break; case 6: push_int(THIS_STAT->s.st_gid); break;
61a4242000-08-27Mirar (Pontus Hagland)  default: { INT32 args=1; SIMPLE_BAD_ARG_ERROR("Stat `[]",1,"int(0..6)"); } } }
74dfe82012-12-30Jonas Walldén static void stat_init (struct object *UNUSED(o))
278a512011-03-21Martin Stjernholm {
ab98542014-04-27Martin Nilsson  MEMSET (&THIS_STAT->s, 0, sizeof (THIS_STAT->s));
278a512011-03-21Martin Stjernholm }
54fe392002-03-05Martin Stjernholm /*! @decl void create (void|object|array stat); *! *! A new @[Stdio.Stat] object can be initialized in two ways: *! *! @ul *! @item *! @[stat] is an object, typically another @[Stdio.Stat]. The *! stat info is copied from the object by getting the values of
cbe8c92003-04-07Martin Nilsson  *! @expr{mode@}, @expr{size@}, @expr{atime@}, @expr{mtime@}, *! @expr{ctime@}, @expr{uid@}, @expr{gid@}, @expr{dev@}, @expr{ino@}, *! @expr{nlink@}, and @expr{rdev@}.
54fe392002-03-05Martin Stjernholm  *! @item *! @[stat] is a seven element array on the 'traditional' LPC *! stat-array form (see the class doc). *! @endul */
29e4fc2000-08-29Martin Stjernholm static void stat_create (INT32 args) {
dbefdb2011-02-15Martin Stjernholm  if (args >= 1 && !UNSAFE_IS_ZERO (Pike_sp - 1)) {
29e4fc2000-08-29Martin Stjernholm  pop_n_elems (args - 1); args = 1;
017b572011-10-28Henrik Grubbström (Grubba)  if (TYPEOF(sp[-1]) == T_OBJECT)
29e4fc2000-08-29Martin Stjernholm  if (sp[-1].u.object->prog == stat_program) { *THIS_STAT = *(struct stat_storage *) sp[-1].u.object->storage; pop_stack(); return; }
017b572011-10-28Henrik Grubbström (Grubba)  if ((1 << TYPEOF(sp[-1])) & (BIT_PROGRAM|BIT_OBJECT|BIT_MAPPING)) {
3396ea2000-08-29Martin Stjernholm 
29e4fc2000-08-29Martin Stjernholm #define ASSIGN_INDEX(ENUM) \ do { \ stack_dup(); \ ref_push_string (stat_index_strs[ENUM]); \
017b572011-10-28Henrik Grubbström (Grubba)  SET_SVAL_SUBTYPE(sp[-1], 1); \
29e4fc2000-08-29Martin Stjernholm  o_index(); \ if (!IS_UNDEFINED (sp-1)) { \ ref_push_string (stat_index_strs[ENUM]); \ stack_swap(); \ stat_index_set (2); \ } \ pop_stack(); \ } while (0) ASSIGN_INDEX (STAT_MODE); ASSIGN_INDEX (STAT_SIZE); ASSIGN_INDEX (STAT_ATIME); ASSIGN_INDEX (STAT_MTIME); ASSIGN_INDEX (STAT_CTIME); ASSIGN_INDEX (STAT_UID); ASSIGN_INDEX (STAT_GID); ASSIGN_INDEX (STAT_DEV); ASSIGN_INDEX (STAT_INO); ASSIGN_INDEX (STAT_NLINK); ASSIGN_INDEX (STAT_RDEV);
e60b072005-04-30Per Hedbor #ifdef HAVE_STRUCT_STAT_BLOCKS
29e4fc2000-08-29Martin Stjernholm  ASSIGN_INDEX (STAT_BLKSIZE); ASSIGN_INDEX (STAT_BLOCKS);
b00ea02000-08-30Martin Stjernholm #endif
29e4fc2000-08-29Martin Stjernholm  }
017b572011-10-28Henrik Grubbström (Grubba)  else if (TYPEOF(sp[-1]) == T_ARRAY) {
29e4fc2000-08-29Martin Stjernholm  struct array *a = sp[-1].u.array;
0a5eae2001-07-02Martin Stjernholm  int i;
29e4fc2000-08-29Martin Stjernholm  if (a->size != 7) SIMPLE_BAD_ARG_ERROR ("Stat create", 1, "stat array with 7 elements"); for (i = 0; i < 7; i++) { INT64 val;
017b572011-10-28Henrik Grubbström (Grubba)  if (TYPEOF(ITEM(a)[i]) == T_INT)
a580e12000-09-27Fredrik Hübinette (Hubbe)  val = ITEM(a)[i].u.integer;
017b572011-10-28Henrik Grubbström (Grubba)  else if (TYPEOF(ITEM(a)[i]) == T_OBJECT &&
29e4fc2000-08-29Martin Stjernholm  is_bignum_object (ITEM(a)[i].u.object)) { if (!int64_from_bignum (&val, ITEM(a)[i].u.object))
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error ("Stat create: Too big integer in stat array.\n");
29e4fc2000-08-29Martin Stjernholm  } else SIMPLE_BAD_ARG_ERROR ("Stat create", 1, "array(int)"); stat_compat_set (i, val); } } else SIMPLE_BAD_ARG_ERROR ("Stat create", 1, "void|Stdio.Stat|array(int)"); } pop_n_elems (args); }
61a4242000-08-27Mirar (Pontus Hagland) void f_min(INT32 args); void f_max(INT32 args);
8caa912014-05-20Per Hedbor static void _stat_index(INT_TYPE code)
61a4242000-08-27Mirar (Pontus Hagland) {
8caa912014-05-20Per Hedbor  if (!code) { /* Fall back to a normal index on this object, in case * someone inherited us. */ struct svalue res; object_index_no_free2 (&res, fp->current_object, 0, sp-1); pop_stack(); *sp++ = res; return; } switch (code) { case STAT_DEV: push_int(THIS_STAT->s.st_dev); break; case STAT_INO: push_int(THIS_STAT->s.st_ino); break; case STAT_MODE: push_int(THIS_STAT->s.st_mode); break; case STAT_NLINK: push_int(THIS_STAT->s.st_nlink); break; case STAT_UID: push_int(THIS_STAT->s.st_uid); break; case STAT_GID: push_int(THIS_STAT->s.st_gid); break; case STAT_RDEV: push_int(THIS_STAT->s.st_rdev); break; case STAT_SIZE: push_int64(THIS_STAT->s.st_size); break; #ifdef HAVE_STRUCT_STAT_BLOCKS case STAT_BLKSIZE: push_int(THIS_STAT->s.st_blksize); break; case STAT_BLOCKS: push_int(THIS_STAT->s.st_blocks); break; #endif case STAT_ATIME: push_int64(THIS_STAT->s.st_atime); break; case STAT_MTIME: push_int64(THIS_STAT->s.st_mtime); break; case STAT_CTIME: push_int64(THIS_STAT->s.st_ctime); break; case STAT_ISREG: push_int((THIS_STAT->s.st_mode & S_IFMT) == S_IFREG); break; case STAT_ISLNK: push_int((THIS_STAT->s.st_mode & S_IFMT) == S_IFLNK); break; case STAT_ISDIR: push_int((THIS_STAT->s.st_mode & S_IFMT) == S_IFDIR); break; case STAT_ISCHR: push_int((THIS_STAT->s.st_mode & S_IFMT) == S_IFCHR); break; case STAT_ISBLK: push_int((THIS_STAT->s.st_mode & S_IFMT) == S_IFBLK); break; case STAT_ISFIFO: push_int((THIS_STAT->s.st_mode & S_IFMT) == S_IFIFO); break; case STAT_ISSOCK: push_int((THIS_STAT->s.st_mode & S_IFMT) == S_IFSOCK); break; case STAT_TYPE: switch (THIS_STAT->s.st_mode & S_IFMT)
61a4242000-08-27Mirar (Pontus Hagland)  {
8caa912014-05-20Per Hedbor  case S_IFREG: ref_push_string(str_type_reg); break; case S_IFDIR: ref_push_string(str_type_dir); break; case S_IFLNK: ref_push_string(str_type_lnk); break; case S_IFCHR: ref_push_string(str_type_chr); break; case S_IFBLK: ref_push_string(str_type_blk); break; case S_IFIFO: ref_push_string(str_type_fifo); break; case S_IFSOCK: ref_push_string(str_type_sock); break; default: ref_push_string(str_type_unknown); break;
61a4242000-08-27Mirar (Pontus Hagland)  }
8caa912014-05-20Per Hedbor  break; case STAT_MODE_STRING: switch (THIS_STAT->s.st_mode & S_IFMT)
61a4242000-08-27Mirar (Pontus Hagland)  {
8caa912014-05-20Per Hedbor  case S_IFREG: push_constant_text("-"); break; case S_IFDIR: push_constant_text("d"); break; case S_IFLNK: push_constant_text("l"); break; case S_IFCHR: push_constant_text("c"); break; case S_IFBLK: push_constant_text("b"); break; case S_IFIFO: push_constant_text("f"); break; case S_IFSOCK: push_constant_text("s"); break; default: push_constant_text("?"); break; }
61a4242000-08-27Mirar (Pontus Hagland) 
8caa912014-05-20Per Hedbor  if ( (THIS_STAT->s.st_mode & S_IRUSR) ) push_constant_text("r"); else push_constant_text("-");
29e4fc2000-08-29Martin Stjernholm 
8caa912014-05-20Per Hedbor  if ( (THIS_STAT->s.st_mode & S_IWUSR) ) push_constant_text("w");
61a4242000-08-27Mirar (Pontus Hagland)  else
8caa912014-05-20Per Hedbor  push_constant_text("-");
61a4242000-08-27Mirar (Pontus Hagland) 
8caa912014-05-20Per Hedbor  if ( (THIS_STAT->s.st_mode & S_ISUID) ) if ( (THIS_STAT->s.st_mode & S_IXUSR) ) push_constant_text("s"); else push_constant_text("S"); else if ( (THIS_STAT->s.st_mode & S_IXUSR) ) push_constant_text("x"); else push_constant_text("-");
6c638f2000-08-28Henrik Grubbström (Grubba) 
8caa912014-05-20Per Hedbor  if ( (THIS_STAT->s.st_mode & S_IRGRP) ) push_constant_text("r"); else push_constant_text("-");
a580e12000-09-27Fredrik Hübinette (Hubbe) 
8caa912014-05-20Per Hedbor  if ( (THIS_STAT->s.st_mode & S_IWGRP) ) push_constant_text("w"); else push_constant_text("-");
3396ea2000-08-29Martin Stjernholm 
8caa912014-05-20Per Hedbor  if ( (THIS_STAT->s.st_mode & S_ISGID) ) if ( (THIS_STAT->s.st_mode & S_IXGRP) ) push_constant_text("s"); else push_constant_text("S"); else if ( (THIS_STAT->s.st_mode & S_IXGRP) ) push_constant_text("x"); else push_constant_text("-");
61a4242000-08-27Mirar (Pontus Hagland) 
8caa912014-05-20Per Hedbor  if ( (THIS_STAT->s.st_mode & S_IROTH) ) push_constant_text("r"); else push_constant_text("-");
6c638f2000-08-28Henrik Grubbström (Grubba) 
8caa912014-05-20Per Hedbor  if ( (THIS_STAT->s.st_mode & S_IWOTH) ) push_constant_text("w"); else push_constant_text("-"); if ( (THIS_STAT->s.st_mode & S_ISVTX) ) if ( (THIS_STAT->s.st_mode & S_IXOTH) ) push_constant_text("t"); else push_constant_text("T"); else if ( (THIS_STAT->s.st_mode & S_IXOTH) ) push_constant_text("x"); else push_constant_text("-"); f_add(10); break; #ifdef PIKE_DEBUG default: Pike_fatal ("stat_index is not kept up-to-date with stat_map.\n"); #endif } } static void stat_index(INT32 args) { if( !args ) SIMPLE_TOO_FEW_ARGS_ERROR("Stat `[]",1); else if( args == 1 ) { if (TYPEOF(sp[-1]) == T_INT) { int index = sp[-1].u.integer; pop_stack(); stat_push_compat(index); } else if( TYPEOF(sp[-1]) == T_STRING ) { struct svalue *tmp; tmp = low_mapping_string_lookup( stat_map, sp[-1].u.string ); _stat_index( tmp ? tmp->u.integer : 0 ); } else SIMPLE_BAD_ARG_ERROR("Stat `[]",1,"int(0..6)|string"); } else if (args>=2) /* range */ { INT_TYPE from, to, n=0; if (args > 2) { pop_n_elems(args - 2); args = 2; } if (TYPEOF(sp[-2]) != T_INT && !(TYPEOF(sp[-2]) == T_OBJECT && is_bignum_object (sp[-2].u.object))) SIMPLE_BAD_ARG_ERROR("Stat `[..]",1,"int"); if (TYPEOF(sp[-1]) != T_INT && !(TYPEOF(sp[-1]) == T_OBJECT && is_bignum_object (sp[-1].u.object))) SIMPLE_BAD_ARG_ERROR("Stat `[..]",2,"int"); /* make in range 0..6 */ push_int(6); f_min(2); stack_swap(); push_int(0); f_max(2); stack_swap(); from = sp[-2].u.integer; to = sp[-1].u.integer; pop_n_elems(args); while (from<=to) { stat_push_compat(from++); n++; } f_aggregate(n); }
61a4242000-08-27Mirar (Pontus Hagland) }
8caa912014-05-20Per Hedbor 
29e4fc2000-08-29Martin Stjernholm static void stat_index_set (INT32 args) { int got_int_val = 0; INT64 int_val; if (args < 2) SIMPLE_TOO_FEW_ARGS_ERROR ("Stat `[]=", 2);
3396ea2000-08-29Martin Stjernholm  if (args > 2) { pop_n_elems (args - 2); args = 2; }
29e4fc2000-08-29Martin Stjernholm 
017b572011-10-28Henrik Grubbström (Grubba)  if (TYPEOF(sp[-1]) == T_INT)
a580e12000-09-27Fredrik Hübinette (Hubbe)  int_val = sp[-1].u.integer, got_int_val = 1;
0311712013-06-17Martin Nilsson  else if (TYPEOF(sp[-1]) == T_OBJECT && is_bignum_object (sp[-1].u.object)) {
29e4fc2000-08-29Martin Stjernholm  if (!int64_from_bignum (&int_val, sp[-1].u.object))
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error ("Stat `[]=: Too big integer as value.\n");
29e4fc2000-08-29Martin Stjernholm  else got_int_val = 1; }
0311712013-06-17Martin Nilsson 
40962a2003-03-27Martin Stjernholm  /* shouldn't there be an else clause here ? */ /* No, the second argument is checked further below depending on * what the first is. /mast */
29e4fc2000-08-29Martin Stjernholm 
017b572011-10-28Henrik Grubbström (Grubba)  if (TYPEOF(sp[-2]) == T_INT) {
29e4fc2000-08-29Martin Stjernholm  if (!got_int_val) SIMPLE_BAD_ARG_ERROR ("Stat `[]=", 2, "integer when the first argument is an integer"); if (!stat_compat_set (sp[-2].u.integer, int_val)) SIMPLE_BAD_ARG_ERROR ("Stat `[]=", 1, "int(0..6)|string"); }
017b572011-10-28Henrik Grubbström (Grubba)  else if (TYPEOF(sp[-2]) == T_STRING) {
29e4fc2000-08-29Martin Stjernholm  INT_TYPE code; ref_push_mapping (stat_map);
3396ea2000-08-29Martin Stjernholm  push_svalue (sp-3);
29e4fc2000-08-29Martin Stjernholm  f_index (2); code = sp[-1].u.integer; pop_stack();
b00ea02000-08-30Martin Stjernholm  if (!code) { /* Fall back to a normal index set on this object, in case * someone inherited us. */
9273742008-05-29Henrik Grubbström (Grubba)  object_set_index2 (fp->current_object, 0, sp-2, sp-1);
b00ea02000-08-30Martin Stjernholm  stack_swap(); pop_stack(); return; }
29e4fc2000-08-29Martin Stjernholm  switch (code) {
3396ea2000-08-29Martin Stjernholm  case 0: SIMPLE_BAD_ARG_ERROR ("Stat `[]=", 1, "a valid index");
29e4fc2000-08-29Martin Stjernholm  case STAT_MODE_STRING:
017b572011-10-28Henrik Grubbström (Grubba)  if (TYPEOF(sp[-1]) != T_STRING)
29e4fc2000-08-29Martin Stjernholm  SIMPLE_BAD_ARG_ERROR ("Stat `[]=", 2, "string"); /* FIXME: Handle modes on the form u+rw, perhaps? */ if (sp[-1].u.string->len != 10) SIMPLE_BAD_ARG_ERROR ("Stat `[]=", 2, "mode string with 10 chars"); { PCHARP str = MKPCHARP_STR (sp[-1].u.string); int mode = THIS_STAT->s.st_mode; switch (INDEX_PCHARP (str, 0)) { case '-': mode = (mode & ~S_IFMT) | S_IFREG; break; case 'd': mode = (mode & ~S_IFMT) | S_IFDIR; break; case 'l': mode = (mode & ~S_IFMT) | S_IFLNK; break; case 'c': mode = (mode & ~S_IFMT) | S_IFCHR; break; case 'b': mode = (mode & ~S_IFMT) | S_IFBLK; break; case 'f': mode = (mode & ~S_IFMT) | S_IFIFO; break; case 's': mode = (mode & ~S_IFMT) | S_IFSOCK; break; } switch (INDEX_PCHARP (str, 1)) { case '-': mode &= ~S_IRUSR; break; case 'r': mode |= S_IRUSR; break; } switch (INDEX_PCHARP (str, 2)) { case '-': mode &= ~S_IWUSR; break; case 'w': mode |= S_IWUSR; break; } switch (INDEX_PCHARP (str, 3)) { case '-': mode &= ~(S_IXUSR | S_ISUID); break; case 'x': mode = (mode & ~S_ISUID) | S_IXUSR; break; case 'S': mode = (mode & ~S_IXUSR) | S_ISUID; break; case 's': mode |= S_IXUSR | S_ISUID; break; } switch (INDEX_PCHARP (str, 4)) { case '-': mode &= ~S_IRGRP; break; case 'r': mode |= S_IRGRP; break; } switch (INDEX_PCHARP (str, 5)) { case '-': mode &= ~S_IWGRP; break; case 'w': mode |= S_IWGRP; break; } switch (INDEX_PCHARP (str, 6)) { case '-': mode &= ~(S_IXGRP | S_ISGID); break; case 'x': mode = (mode & ~S_ISGID) | S_IXGRP; break; case 'S': mode = (mode & ~S_IXGRP) | S_ISGID; break; case 's': mode |= S_IXGRP | S_ISGID; break; } switch (INDEX_PCHARP (str, 7)) { case '-': mode &= ~S_IROTH; break; case 'r': mode |= S_IROTH; break; } switch (INDEX_PCHARP (str, 8)) { case '-': mode &= ~S_IWOTH; break; case 'w': mode |= S_IWOTH; break; } switch (INDEX_PCHARP (str, 9)) { case '-': mode &= ~(S_IXOTH | S_ISVTX); break; case 'x': mode = (mode & ~S_ISVTX) | S_IXOTH; break; case 'T': mode = (mode & ~S_IXOTH) | S_ISVTX; break; case 't': mode |= S_IXOTH | S_ISVTX; break; } THIS_STAT->s.st_mode = mode; } break; case STAT_TYPE:
017b572011-10-28Henrik Grubbström (Grubba)  if (TYPEOF(sp[-1]) != T_STRING)
29e4fc2000-08-29Martin Stjernholm  SIMPLE_BAD_ARG_ERROR ("Stat `[]=", 2, "string"); if (sp[-1].u.string == str_type_reg) THIS_STAT->s.st_mode = (THIS_STAT->s.st_mode & ~S_IFMT) | S_IFREG; else if (sp[-1].u.string == str_type_dir) THIS_STAT->s.st_mode = (THIS_STAT->s.st_mode & ~S_IFMT) | S_IFDIR; else if (sp[-1].u.string == str_type_lnk) THIS_STAT->s.st_mode = (THIS_STAT->s.st_mode & ~S_IFMT) | S_IFLNK; else if (sp[-1].u.string == str_type_chr) THIS_STAT->s.st_mode = (THIS_STAT->s.st_mode & ~S_IFMT) | S_IFCHR; else if (sp[-1].u.string == str_type_blk) THIS_STAT->s.st_mode = (THIS_STAT->s.st_mode & ~S_IFMT) | S_IFBLK; else if (sp[-1].u.string == str_type_fifo) THIS_STAT->s.st_mode = (THIS_STAT->s.st_mode & ~S_IFMT) | S_IFIFO; else if (sp[-1].u.string == str_type_sock) THIS_STAT->s.st_mode = (THIS_STAT->s.st_mode & ~S_IFMT) | S_IFSOCK; else if (sp[-1].u.string == str_type_unknown) THIS_STAT->s.st_mode = THIS_STAT->s.st_mode & ~S_IFMT; else SIMPLE_BAD_ARG_ERROR ("Stat `[]=", 2, "valid type string"); break; case STAT_ISREG: THIS_STAT->s.st_mode &= ~S_IFMT;
9f516a2001-12-16Martin Stjernholm  if (!UNSAFE_IS_ZERO (sp-1)) THIS_STAT->s.st_mode |= S_IFREG;
29e4fc2000-08-29Martin Stjernholm  break; case STAT_ISDIR: THIS_STAT->s.st_mode &= ~S_IFMT;
9f516a2001-12-16Martin Stjernholm  if (!UNSAFE_IS_ZERO (sp-1)) THIS_STAT->s.st_mode |= S_IFDIR;
29e4fc2000-08-29Martin Stjernholm  break; case STAT_ISLNK: THIS_STAT->s.st_mode &= ~S_IFMT;
9f516a2001-12-16Martin Stjernholm  if (!UNSAFE_IS_ZERO (sp-1)) THIS_STAT->s.st_mode |= S_IFLNK;
29e4fc2000-08-29Martin Stjernholm  break; case STAT_ISCHR: THIS_STAT->s.st_mode &= ~S_IFMT;
9f516a2001-12-16Martin Stjernholm  if (!UNSAFE_IS_ZERO (sp-1)) THIS_STAT->s.st_mode |= S_IFCHR;
29e4fc2000-08-29Martin Stjernholm  break; case STAT_ISBLK: THIS_STAT->s.st_mode &= ~S_IFMT;
9f516a2001-12-16Martin Stjernholm  if (!UNSAFE_IS_ZERO (sp-1)) THIS_STAT->s.st_mode |= S_IFBLK;
29e4fc2000-08-29Martin Stjernholm  break; case STAT_ISFIFO: THIS_STAT->s.st_mode &= ~S_IFMT;
9f516a2001-12-16Martin Stjernholm  if (!UNSAFE_IS_ZERO (sp-1)) THIS_STAT->s.st_mode |= S_IFIFO;
29e4fc2000-08-29Martin Stjernholm  break; case STAT_ISSOCK: THIS_STAT->s.st_mode &= ~S_IFMT;
9f516a2001-12-16Martin Stjernholm  if (!UNSAFE_IS_ZERO (sp-1)) THIS_STAT->s.st_mode |= S_IFSOCK;
29e4fc2000-08-29Martin Stjernholm  break; default: if (!got_int_val) SIMPLE_BAD_ARG_ERROR ("Stat `[]=", 2, "integer"); switch (code) {
097de92006-07-05Martin Stjernholm  case STAT_DEV: DO_NOT_WARN(THIS_STAT->s.st_dev = (int) int_val); break; case STAT_INO: DO_NOT_WARN(THIS_STAT->s.st_ino = (int) int_val); break; case STAT_MODE: DO_NOT_WARN(THIS_STAT->s.st_mode = (int) int_val); break; case STAT_NLINK: DO_NOT_WARN(THIS_STAT->s.st_nlink = (int) int_val); break; case STAT_UID: DO_NOT_WARN(THIS_STAT->s.st_uid = (int) int_val); break; case STAT_GID: DO_NOT_WARN(THIS_STAT->s.st_gid = (int) int_val); break; case STAT_RDEV: DO_NOT_WARN(THIS_STAT->s.st_rdev = (int) int_val); break; case STAT_SIZE: THIS_STAT->s.st_size = DO_NOT_WARN ((off_t) int_val); break;
e60b072005-04-30Per Hedbor #ifdef HAVE_STRUCT_STAT_BLOCKS
0e8c502000-08-31Henrik Grubbström (Grubba)  case STAT_BLKSIZE: DO_NOT_WARN(THIS_STAT->s.st_blksize = int_val); break; case STAT_BLOCKS: DO_NOT_WARN(THIS_STAT->s.st_blocks = int_val); break;
e60b072005-04-30Per Hedbor #endif
097de92006-07-05Martin Stjernholm  case STAT_ATIME: THIS_STAT->s.st_atime = DO_NOT_WARN ((time_t) int_val); break; case STAT_MTIME: THIS_STAT->s.st_mtime = DO_NOT_WARN ((time_t) int_val); break; case STAT_CTIME: THIS_STAT->s.st_ctime = DO_NOT_WARN ((time_t) int_val); break;
29e4fc2000-08-29Martin Stjernholm  default:
5aad932002-08-15Marcus Comstedt  Pike_fatal ("stat_index_set is not kept up-to-date with stat_map.\n");
29e4fc2000-08-29Martin Stjernholm  } } } else SIMPLE_BAD_ARG_ERROR ("Stat `[]=", 1, "int(0..6)|string"); stack_swap(); pop_stack(); }
61a4242000-08-27Mirar (Pontus Hagland) static void stat_cast(INT32 args) { if (!args)
c010e32000-08-28Martin Stjernholm  SIMPLE_TOO_FEW_ARGS_ERROR("Stat cast",1);
017b572011-10-28Henrik Grubbström (Grubba)  if (TYPEOF(sp[-args]) == T_STRING && !sp[-args].u.string->size_shift)
61a4242000-08-27Mirar (Pontus Hagland)  { if (strncmp(sp[-args].u.string->str,"array",5)==0) { pop_n_elems(args); push_int(0); push_int(6); stat_index(2); return; } } SIMPLE_BAD_ARG_ERROR("Stat cast",1, "string(\"array\")"); } static void stat__sprintf(INT32 args) {
6c638f2000-08-28Henrik Grubbström (Grubba)  int n=0, x;
61a4242000-08-27Mirar (Pontus Hagland)  if (args<1) SIMPLE_TOO_FEW_ARGS_ERROR("_sprintf",2);
017b572011-10-28Henrik Grubbström (Grubba)  if (TYPEOF(sp[-args]) != T_INT)
61a4242000-08-27Mirar (Pontus Hagland)  SIMPLE_BAD_ARG_ERROR("_sprintf",0,"integer"); x=sp[-args].u.integer; pop_n_elems(args); switch (x) { case 'O': n++; push_constant_text("Stat(");
8caa912014-05-20Per Hedbor  n++; _stat_index(STAT_MODE_STRING);
61a4242000-08-27Mirar (Pontus Hagland)  n++; push_constant_text(" ");
8caa912014-05-20Per Hedbor  n++; _stat_index(STAT_SIZE);
61a4242000-08-27Mirar (Pontus Hagland)  n++; push_constant_text("b)"); f_add(n); return; default: push_int(0); return; } } static void stat_indices(INT32 args) { pop_n_elems(args); ref_push_mapping(stat_map); f_indices(1); } static void stat_values(INT32 args) { int i,z; struct array *a; pop_n_elems(args); ref_push_mapping(stat_map); f_indices(1); z=(a=sp[-1].u.array)->size; for (i=0; i<z; i++) { ref_push_object(fp->current_object); push_svalue(a->item+i); f_index(2); } f_aggregate(z);
0d0bab2003-04-27Martin Stjernholm  stack_pop_keep_top();
61a4242000-08-27Mirar (Pontus Hagland) }
0c2bfe2000-08-28Henrik Grubbström (Grubba) #undef THIS_STAT
61a4242000-08-27Mirar (Pontus Hagland) 
40962a2003-03-27Martin Stjernholm void push_stat(PIKE_STAT_T *s)
61a4242000-08-27Mirar (Pontus Hagland) { struct object *o; struct stat_storage *stor; o=clone_object(stat_program,0); stor=(struct stat_storage*)get_storage(o,stat_program); stor->s=*s; push_object(o); }
54fe392002-03-05Martin Stjernholm /*! @endclass */ /*! @endmodule */
61a4242000-08-27Mirar (Pontus Hagland) /* ---------------------------------------------------------------- */
29f9a92013-06-11Martin Nilsson void init_stdio_stat()
61a4242000-08-27Mirar (Pontus Hagland) { INT_TYPE n=0;
29e4fc2000-08-29Martin Stjernholm  MAKE_CONSTANT_SHARED_STRING (str_type_reg, "reg"); MAKE_CONSTANT_SHARED_STRING (str_type_dir, "dir"); MAKE_CONSTANT_SHARED_STRING (str_type_lnk, "lnk"); MAKE_CONSTANT_SHARED_STRING (str_type_chr, "chr"); MAKE_CONSTANT_SHARED_STRING (str_type_blk, "blk"); MAKE_CONSTANT_SHARED_STRING (str_type_fifo, "fifo"); MAKE_CONSTANT_SHARED_STRING (str_type_sock, "sock"); MAKE_CONSTANT_SHARED_STRING (str_type_unknown, "unknown"); #define INIT_INDEX(ENUM, TXT) do { \ MAKE_CONSTANT_SHARED_STRING (stat_index_strs[ENUM], TXT); \ n++; ref_push_string (stat_index_strs[ENUM]); push_int (ENUM); \ } while (0) INIT_INDEX (STAT_DEV, "dev"); INIT_INDEX (STAT_INO, "ino"); INIT_INDEX (STAT_MODE, "mode"); INIT_INDEX (STAT_NLINK, "nlink"); INIT_INDEX (STAT_UID, "uid"); INIT_INDEX (STAT_GID, "gid"); INIT_INDEX (STAT_RDEV, "rdev"); INIT_INDEX (STAT_SIZE, "size");
e60b072005-04-30Per Hedbor #ifdef HAVE_STRUCT_STAT_BLOCKS
29e4fc2000-08-29Martin Stjernholm  INIT_INDEX (STAT_BLKSIZE, "blksize"); INIT_INDEX (STAT_BLOCKS, "blocks");
b00ea02000-08-30Martin Stjernholm #endif
29e4fc2000-08-29Martin Stjernholm  INIT_INDEX (STAT_ATIME, "atime"); INIT_INDEX (STAT_MTIME, "mtime"); INIT_INDEX (STAT_CTIME, "ctime"); INIT_INDEX (STAT_ISLNK, "islnk"); INIT_INDEX (STAT_ISREG, "isreg"); INIT_INDEX (STAT_ISDIR, "isdir"); INIT_INDEX (STAT_ISCHR, "ischr"); INIT_INDEX (STAT_ISBLK, "isblk"); INIT_INDEX (STAT_ISFIFO, "isfifo"); INIT_INDEX (STAT_ISSOCK, "issock"); INIT_INDEX (STAT_TYPE, "type"); INIT_INDEX (STAT_MODE_STRING, "mode_string");
61a4242000-08-27Mirar (Pontus Hagland)  f_aggregate_mapping(n*2); stat_map=sp[-1].u.mapping; sp--;
6c638f2000-08-28Henrik Grubbström (Grubba)  dmalloc_touch_svalue(sp);
61a4242000-08-27Mirar (Pontus Hagland) 
29e4fc2000-08-29Martin Stjernholm  START_NEW_PROGRAM_ID(STDIO_STAT);
61a4242000-08-27Mirar (Pontus Hagland)  ADD_STORAGE(struct stat_storage);
29e4fc2000-08-29Martin Stjernholm  ADD_FUNCTION ("create", stat_create,
8c953a2001-03-28Henrik Grubbström (Grubba)  tFunc(tOr5(tVoid,tObjImpl_STDIO_STAT,tPrg(tObj),tMapping,tArr(tInt)),
ecc9382008-06-29Martin Nilsson  tVoid), ID_PROTECTED);
29e4fc2000-08-29Martin Stjernholm 
61a4242000-08-27Mirar (Pontus Hagland)  ADD_FUNCTION("`[]",stat_index,
29e4fc2000-08-29Martin Stjernholm  tOr(tFunc(tOr(tStr,tInt06),tOr3(tStr,tInt,tFunction)),
61a4242000-08-27Mirar (Pontus Hagland)  tFunc(tInt tInt,tArr(tInt))),0); ADD_FUNCTION("`->",stat_index,
29e4fc2000-08-29Martin Stjernholm  tOr(tFunc(tOr(tStr,tInt06),tOr3(tStr,tInt,tFunction)),
61a4242000-08-27Mirar (Pontus Hagland)  tFunc(tInt tInt,tArr(tInt))),0);
29e4fc2000-08-29Martin Stjernholm  ADD_FUNCTION ("`[]=", stat_index_set, tOr(tFunc(tInt06 tSetvar(0,tInt),tVar(0)), tFunc(tString tSetvar(1,tOr(tInt,tString)),tVar(1))), 0); ADD_FUNCTION ("`->=", stat_index_set, tOr(tFunc(tInt06 tSetvar(0,tInt),tVar(0)), tFunc(tString tSetvar(1,tOr(tInt,tString)),tVar(1))), 0);
61a4242000-08-27Mirar (Pontus Hagland)  ADD_FUNCTION("cast",stat_cast,tFunc(tStr,tArray),0); ADD_FUNCTION("_sprintf",stat__sprintf, tFunc(tInt tOr(tVoid,tMapping),tString),0); ADD_FUNCTION("_indices",stat_indices, tFunc(tNone,tArr(tOr(tString,tInt))),0); ADD_FUNCTION("_values",stat_values, tFunc(tNone,tArr(tOr(tString,tInt))),0);
278a512011-03-21Martin Stjernholm  set_init_callback (stat_init);
61a4242000-08-27Mirar (Pontus Hagland)  stat_program=end_program(); add_program_constant("Stat",stat_program,0); }
29f9a92013-06-11Martin Nilsson void exit_stdio_stat()
61a4242000-08-27Mirar (Pontus Hagland) {
29e4fc2000-08-29Martin Stjernholm  size_t i;
61a4242000-08-27Mirar (Pontus Hagland)  free_program(stat_program);
6c638f2000-08-28Henrik Grubbström (Grubba)  free_mapping(stat_map);
29e4fc2000-08-29Martin Stjernholm  for (i = 1; i < STAT_ENUM_END; i++) free_string (stat_index_strs[i]); free_string (str_type_reg); free_string (str_type_dir); free_string (str_type_lnk); free_string (str_type_chr); free_string (str_type_blk); free_string (str_type_fifo); free_string (str_type_sock); free_string (str_type_unknown);
61a4242000-08-27Mirar (Pontus Hagland) }