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

version» Context lines:

pike.git/src/modules/_Stdio/stat.c:8:   #include "fdlib.h"   #include "interpret.h"   #include "svalue.h"   #include "bignum.h"   #include "mapping.h"   #include "object.h"   #include "builtin_functions.h"   #include "operators.h"   #include "program_id.h"   #include "file_machine.h" + #include "pike_types.h" + #include "sprintf.h"      #include <sys/stat.h>   #ifdef HAVE_SYS_PARAM_H   #include <sys/param.h>   #endif /* HAVE_SYS_PARAM_H */      #define sp Pike_sp   #define fp Pike_fp      /*! @module Stdio
pike.git/src/modules/_Stdio/stat.c:41:    *! @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 atime_nsec +  *! Time of last access in nanoseconds, added to atime to get +  *! sub-second time +  *! @item mtime_nsec +  *! Time of last modification in nanoseconds, added to mtime to get +  *! sub-second time +  *! @item ctime_nsec +  *! Time of last file status change in nanoseconds, added to ctime to +  *! get sub-second time    *! @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    *!
pike.git/src/modules/_Stdio/stat.c:201:      static struct mapping *stat_map=NULL;      enum stat_query   {STAT_DEV=1, STAT_INO, STAT_MODE, STAT_NLINK, STAT_UID, STAT_GID, STAT_RDEV,    STAT_SIZE,   #ifdef HAVE_STRUCT_STAT_BLOCKS    STAT_BLKSIZE, STAT_BLOCKS,   #endif    STAT_ATIME, STAT_MTIME, STAT_CTIME, +  STAT_ATIME_NSEC,STAT_MTIME_NSEC, STAT_CTIME_NSEC,   /* 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;      #define THIS_STAT ((struct stat_storage*)(Pike_fp->current_storage))      static void stat_index_set (INT32 args); -  + static void _stat_index_set (INT_TYPE pos, struct svalue *val, int is_int, INT64 intval);      static int stat_compat_set (INT_TYPE pos, INT64 val)   {    if (pos < 0) pos += 7;    switch (pos) { -  case 0: DO_NOT_WARN(THIS_STAT->s.st_mode = (int) val); break; +  case 0: THIS_STAT->s.st_mode = (int) val; break;    case 1:    if (val >= 0) {    THIS_STAT->s.st_mode = (THIS_STAT->s.st_mode & ~S_IFMT) | S_IFREG; -  THIS_STAT->s.st_size = DO_NOT_WARN ((off_t) val); +  THIS_STAT->s.st_size = (off_t) val;    }    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; -  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; +  case 2: THIS_STAT->s.st_atime = (time_t) val; break; +  case 3: THIS_STAT->s.st_mtime = (time_t) val; break; +  case 4: THIS_STAT->s.st_ctime = (time_t) val; break; +  case 5: THIS_STAT->s.st_uid = (int) val; break; +  case 6: THIS_STAT->s.st_gid = (int) val; break;    default: return 0;    }    return 1;   }      static void stat_push_compat(INT_TYPE n)   {    if (n < 0) n += 7;    switch (n)    {
pike.git/src/modules/_Stdio/stat.c:264:    case 1:    switch(S_IFMT & THIS_STAT->s.st_mode)    {    case S_IFREG:    push_int64(THIS_STAT->s.st_size);    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", -  (long)S_IFMT & THIS_STAT->s.st_mode); - #endif /* DEBUG_FILE */ +     push_int(-4);    break;    }    break;    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;    case 5: push_int(THIS_STAT->s.st_uid); break;    case 6: push_int(THIS_STAT->s.st_gid); break;    default:    {    INT32 args=1; -  SIMPLE_BAD_ARG_ERROR("Stat `[]",1,"int(0..6)"); +  SIMPLE_ARG_TYPE_ERROR("`[]",1,"int(0..6)");    }    }   }      static void stat_init (struct object *UNUSED(o))   { -  MEMSET ((char *) &THIS_STAT->s, 0, sizeof (THIS_STAT->s)); +  memset (&THIS_STAT->s, 0, sizeof (THIS_STAT->s));   }      /*! @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    *! @expr{mode@}, @expr{size@}, @expr{atime@}, @expr{mtime@},    *! @expr{ctime@}, @expr{uid@}, @expr{gid@}, @expr{dev@}, @expr{ino@},    *! @expr{nlink@}, and @expr{rdev@}.    *! @item    *! @[stat] is a seven element array on the 'traditional' LPC    *! stat-array form (see the class doc).    *! @endul    */ - static void stat_create (INT32 args) - { -  if (args >= 1 && !UNSAFE_IS_ZERO (Pike_sp - 1)) { -  pop_n_elems (args - 1); -  args = 1; -  -  if (TYPEOF(sp[-1]) == T_OBJECT) -  if (sp[-1].u.object->prog == stat_program) { -  *THIS_STAT = *(struct stat_storage *) sp[-1].u.object->storage; -  pop_stack(); -  return; -  } -  -  if ((1 << TYPEOF(sp[-1])) & (BIT_PROGRAM|BIT_OBJECT|BIT_MAPPING)) { -  - #define ASSIGN_INDEX(ENUM) \ -  do { \ -  stack_dup(); \ -  ref_push_string (stat_index_strs[ENUM]); \ -  SET_SVAL_SUBTYPE(sp[-1], 1); \ -  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); - #ifdef HAVE_STRUCT_STAT_BLOCKS -  ASSIGN_INDEX (STAT_BLKSIZE); -  ASSIGN_INDEX (STAT_BLOCKS); - #endif -  } -  -  else if (TYPEOF(sp[-1]) == T_ARRAY) { -  struct array *a = sp[-1].u.array; -  int i; -  if (a->size != 7) -  SIMPLE_BAD_ARG_ERROR ("Stat create", 1, "stat array with 7 elements"); -  for (i = 0; i < 7; i++) { -  INT64 val; -  if (TYPEOF(ITEM(a)[i]) == T_INT) -  val = ITEM(a)[i].u.integer; -  else if (TYPEOF(ITEM(a)[i]) == T_OBJECT && -  is_bignum_object (ITEM(a)[i].u.object)) { -  if (!int64_from_bignum (&val, ITEM(a)[i].u.object)) -  Pike_error ("Stat create: Too big integer in stat array.\n"); -  } -  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); - } -  +    void f_min(INT32 args);   void f_max(INT32 args);    - static void stat_index(INT32 args) + static void _stat_index(INT_TYPE code)   { -  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) -  { -  INT_TYPE code; -  -  ref_push_mapping(stat_map); -  push_svalue (sp-2); -  f_index(2); -  code = sp[-1].u.integer; /* always integer there now */ -  pop_stack(); -  +     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;    } -  pop_stack(); +        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; -  + #ifdef HAVE_STRUCT_STAT_NSEC +  case STAT_ATIME_NSEC: push_int64(THIS_STAT->s.st_atim.tv_nsec); break; +  case STAT_MTIME_NSEC: push_int64(THIS_STAT->s.st_mtim.tv_nsec); break; +  case STAT_CTIME_NSEC: push_int64(THIS_STAT->s.st_ctim.tv_nsec); break; + #else +  case STAT_ATIME_NSEC: case STAT_MTIME_NSEC: case STAT_CTIME_NSEC: +  push_int(0); +  break; + #endif    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;
pike.git/src/modules/_Stdio/stat.c:466:    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;    }    break;       case STAT_MODE_STRING:    switch (THIS_STAT->s.st_mode & S_IFMT)    {    case S_IFREG: -  push_constant_text("-"); +  push_static_text("-");    break;    case S_IFDIR: -  push_constant_text("d"); +  push_static_text("d");    break;    case S_IFLNK: -  push_constant_text("l"); +  push_static_text("l");    break;    case S_IFCHR: -  push_constant_text("c"); +  push_static_text("c");    break;    case S_IFBLK: -  push_constant_text("b"); +  push_static_text("b");    break;    case S_IFIFO: -  push_constant_text("f"); +  push_static_text("f");    break;    case S_IFSOCK: -  push_constant_text("s"); +  push_static_text("s");    break;    default: -  push_constant_text("?"); +  push_static_text("?");    break;    }       if ( (THIS_STAT->s.st_mode & S_IRUSR) ) -  push_constant_text("r"); +  push_static_text("r");    else -  push_constant_text("-"); +  push_static_text("-");       if ( (THIS_STAT->s.st_mode & S_IWUSR) ) -  push_constant_text("w"); +  push_static_text("w");    else -  push_constant_text("-"); +  push_static_text("-");       if ( (THIS_STAT->s.st_mode & S_ISUID) )    if ( (THIS_STAT->s.st_mode & S_IXUSR) ) -  push_constant_text("s"); +  push_static_text("s");    else -  push_constant_text("S"); +  push_static_text("S");    else    if ( (THIS_STAT->s.st_mode & S_IXUSR) ) -  push_constant_text("x"); +  push_static_text("x");    else -  push_constant_text("-"); +  push_static_text("-");       if ( (THIS_STAT->s.st_mode & S_IRGRP) ) -  push_constant_text("r"); +  push_static_text("r");    else -  push_constant_text("-"); +  push_static_text("-");       if ( (THIS_STAT->s.st_mode & S_IWGRP) ) -  push_constant_text("w"); +  push_static_text("w");    else -  push_constant_text("-"); +  push_static_text("-");       if ( (THIS_STAT->s.st_mode & S_ISGID) )    if ( (THIS_STAT->s.st_mode & S_IXGRP) ) -  push_constant_text("s"); +  push_static_text("s");    else -  push_constant_text("S"); +  push_static_text("S");    else    if ( (THIS_STAT->s.st_mode & S_IXGRP) ) -  push_constant_text("x"); +  push_static_text("x");    else -  push_constant_text("-"); +  push_static_text("-");       if ( (THIS_STAT->s.st_mode & S_IROTH) ) -  push_constant_text("r"); +  push_static_text("r");    else -  push_constant_text("-"); +  push_static_text("-");       if ( (THIS_STAT->s.st_mode & S_IWOTH) ) -  push_constant_text("w"); +  push_static_text("w");    else -  push_constant_text("-"); +  push_static_text("-");       if ( (THIS_STAT->s.st_mode & S_ISVTX) )    if ( (THIS_STAT->s.st_mode & S_IXOTH) ) -  push_constant_text("t"); +  push_static_text("t");    else -  push_constant_text("T"); +  push_static_text("T");    else    if ( (THIS_STAT->s.st_mode & S_IXOTH) ) -  push_constant_text("x"); +  push_static_text("x");    else -  push_constant_text("-"); +  push_static_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_WRONG_NUM_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"); +  SIMPLE_ARG_TYPE_ERROR("`[]",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"); +  SIMPLE_ARG_TYPE_ERROR("`[..]",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"); +  SIMPLE_ARG_TYPE_ERROR("`[..]",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;
pike.git/src/modules/_Stdio/stat.c:604:       while (from<=to)    {    stat_push_compat(from++);    n++;    }    f_aggregate(n);    }   }    - static void stat_index_set (INT32 args) +  + static void _stat_index_set (INT_TYPE code, struct svalue *val, int got_int_val, INT64 int_val )   { -  int got_int_val = 0; -  INT64 int_val; + #define BAD_ARG_2(X) bad_arg_error("`[]=", 2,2,X,val,msg_bad_arg,2,"`[]=",X)    -  if (args < 2) -  SIMPLE_TOO_FEW_ARGS_ERROR ("Stat `[]=", 2); -  -  if (args > 2) { -  pop_n_elems (args - 2); -  args = 2; -  } -  -  if (TYPEOF(sp[-1]) == T_INT) -  int_val = sp[-1].u.integer, got_int_val = 1; -  else if (TYPEOF(sp[-1]) == T_OBJECT && is_bignum_object (sp[-1].u.object)) +  if( got_int_val == -1 )    { -  if (!int64_from_bignum (&int_val, sp[-1].u.object)) -  Pike_error ("Stat `[]=: Too big integer as value.\n"); +  if (TYPEOF(*val) == T_INT) +  int_val = val->u.integer, got_int_val = 1; +  else if (TYPEOF(*val) == T_OBJECT && is_bignum_object (val->u.object)) +  { +  if (!int64_from_bignum (&int_val, val->u.object)) +  Pike_error ("`[]=: Too big integer as value.\n");    else    got_int_val = 1;    } -  -  /* shouldn't there be an else clause here ? */ -  /* No, the second argument is checked further below depending on -  * what the first is. /mast */ -  -  if (TYPEOF(sp[-2]) == T_INT) { -  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"); +     }    -  else if (TYPEOF(sp[-2]) == T_STRING) { -  INT_TYPE code; -  -  ref_push_mapping (stat_map); -  push_svalue (sp-3); -  f_index (2); -  code = sp[-1].u.integer; -  pop_stack(); -  -  if (!code) { -  /* Fall back to a normal index set on this object, in case -  * someone inherited us. */ -  object_set_index2 (fp->current_object, 0, sp-2, sp-1); -  stack_swap(); -  pop_stack(); -  return; -  } -  +     switch (code) { -  case 0: -  SIMPLE_BAD_ARG_ERROR ("Stat `[]=", 1, "a valid index"); -  +     case STAT_MODE_STRING: -  if (TYPEOF(sp[-1]) != T_STRING) -  SIMPLE_BAD_ARG_ERROR ("Stat `[]=", 2, "string"); +  if (TYPEOF(*val) != T_STRING) +  BAD_ARG_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"); +  if (val->u.string->len != 10) +  BAD_ARG_2("mode string with 10 chars");       { -  PCHARP str = MKPCHARP_STR (sp[-1].u.string); +  PCHARP str = MKPCHARP_STR (val->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;
pike.git/src/modules/_Stdio/stat.c:734:    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: -  if (TYPEOF(sp[-1]) != T_STRING) -  SIMPLE_BAD_ARG_ERROR ("Stat `[]=", 2, "string"); +  if (TYPEOF(*val) != T_STRING) +  BAD_ARG_2("string");    -  if (sp[-1].u.string == str_type_reg) +  if (val->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) +  else if (val->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) +  else if (val->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) +  else if (val->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) +  else if (val->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) +  else if (val->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) +  else if (val->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) +  else if (val->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"); +  BAD_ARG_2("valid type string");    break;       case STAT_ISREG:    THIS_STAT->s.st_mode &= ~S_IFMT; -  if (!UNSAFE_IS_ZERO (sp-1)) THIS_STAT->s.st_mode |= S_IFREG; +  if (!UNSAFE_IS_ZERO (val)) THIS_STAT->s.st_mode |= S_IFREG;    break;    case STAT_ISDIR:    THIS_STAT->s.st_mode &= ~S_IFMT; -  if (!UNSAFE_IS_ZERO (sp-1)) THIS_STAT->s.st_mode |= S_IFDIR; +  if (!UNSAFE_IS_ZERO (val)) THIS_STAT->s.st_mode |= S_IFDIR;    break;    case STAT_ISLNK:    THIS_STAT->s.st_mode &= ~S_IFMT; -  if (!UNSAFE_IS_ZERO (sp-1)) THIS_STAT->s.st_mode |= S_IFLNK; +  if (!UNSAFE_IS_ZERO (val)) THIS_STAT->s.st_mode |= S_IFLNK;    break;    case STAT_ISCHR:    THIS_STAT->s.st_mode &= ~S_IFMT; -  if (!UNSAFE_IS_ZERO (sp-1)) THIS_STAT->s.st_mode |= S_IFCHR; +  if (!UNSAFE_IS_ZERO (val)) THIS_STAT->s.st_mode |= S_IFCHR;    break;    case STAT_ISBLK:    THIS_STAT->s.st_mode &= ~S_IFMT; -  if (!UNSAFE_IS_ZERO (sp-1)) THIS_STAT->s.st_mode |= S_IFBLK; +  if (!UNSAFE_IS_ZERO (val)) THIS_STAT->s.st_mode |= S_IFBLK;    break;    case STAT_ISFIFO:    THIS_STAT->s.st_mode &= ~S_IFMT; -  if (!UNSAFE_IS_ZERO (sp-1)) THIS_STAT->s.st_mode |= S_IFIFO; +  if (!UNSAFE_IS_ZERO (val)) THIS_STAT->s.st_mode |= S_IFIFO;    break;    case STAT_ISSOCK:    THIS_STAT->s.st_mode &= ~S_IFMT; -  if (!UNSAFE_IS_ZERO (sp-1)) THIS_STAT->s.st_mode |= S_IFSOCK; +  if (!UNSAFE_IS_ZERO (val)) THIS_STAT->s.st_mode |= S_IFSOCK;    break;       default:    if (!got_int_val) -  SIMPLE_BAD_ARG_ERROR ("Stat `[]=", 2, "integer"); +  BAD_ARG_2("integer");       switch (code) { -  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; +  case STAT_DEV: THIS_STAT->s.st_dev = (int) int_val; break; +  case STAT_INO: THIS_STAT->s.st_ino = (int) int_val; break; +  case STAT_MODE: THIS_STAT->s.st_mode = (int) int_val; break; +  case STAT_NLINK: THIS_STAT->s.st_nlink = (int) int_val; break; +  case STAT_UID: THIS_STAT->s.st_uid = (int) int_val; break; +  case STAT_GID: THIS_STAT->s.st_gid = (int) int_val; break; +  case STAT_RDEV: THIS_STAT->s.st_rdev = (int) int_val; break; +  case STAT_SIZE: THIS_STAT->s.st_size = (off_t) int_val; break;   #ifdef HAVE_STRUCT_STAT_BLOCKS -  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; +  case STAT_BLKSIZE: THIS_STAT->s.st_blksize = int_val; break; +  case STAT_BLOCKS: THIS_STAT->s.st_blocks = int_val; break;   #endif -  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; +  case STAT_ATIME: THIS_STAT->s.st_atime = (time_t) int_val; break; +  case STAT_MTIME: THIS_STAT->s.st_mtime = (time_t) int_val; break; +  case STAT_CTIME: THIS_STAT->s.st_ctime = (time_t) int_val; break;    -  default: -  Pike_fatal ("stat_index_set is not kept up-to-date with stat_map.\n"); + #ifdef HAVE_STRUCT_STAT_NSEC +  case STAT_ATIME_NSEC: THIS_STAT->s.st_atim.tv_nsec = (time_t) int_val; break; +  case STAT_MTIME_NSEC: THIS_STAT->s.st_mtim.tv_nsec = (time_t) int_val; break; +  case STAT_CTIME_NSEC: THIS_STAT->s.st_ctim.tv_nsec = (time_t) int_val; break; + #endif    }    }   }    -  else SIMPLE_BAD_ARG_ERROR ("Stat `[]=", 1, "int(0..6)|string"); + static void stat_index_set (INT32 args) + { +  int got_int_val = 0; +  INT64 int_val = 0;    -  +  if (args < 2) +  SIMPLE_WRONG_NUM_ARGS_ERROR ("Stat `[]=", 2); +  +  if (args > 2) { +  pop_n_elems (args - 2); +  args = 2; +  } +  +  if (TYPEOF(sp[-1]) == T_INT) +  int_val = sp[-1].u.integer, got_int_val = 1; +  else if (TYPEOF(sp[-1]) == T_OBJECT && is_bignum_object (sp[-1].u.object)) +  { +  if (!int64_from_bignum (&int_val, sp[-1].u.object)) +  Pike_error ("Stat `[]=: Too big integer as value.\n"); +  else +  got_int_val = 1; +  } +  +  /* shouldn't there be an else clause here ? */ +  /* No, the second argument is checked further below depending on +  * what the first is. /mast */ +  +  if (TYPEOF(sp[-2]) == T_INT) { +  if (!got_int_val) +  SIMPLE_ARG_TYPE_ERROR ("`[]=", 2, +  "integer when the first argument is an integer"); +  if (!stat_compat_set (sp[-2].u.integer, int_val)) +  SIMPLE_ARG_TYPE_ERROR ("`[]=", 1, "int(0..6)|string"); +  } +  else if (TYPEOF(sp[-2]) == T_STRING) { +  INT_TYPE code; +  struct svalue *tmp; +  tmp = low_mapping_string_lookup( stat_map, sp[-2].u.string ); +  if (!tmp) +  { +  /* Fall back to a normal index set on this object, in case +  * someone inherited us. */ +  object_set_index2 (fp->current_object, 0, sp-2, sp-1);    stack_swap();    pop_stack(); -  +  return;    } -  +  _stat_index_set( tmp->u.integer, sp-1, got_int_val, int_val); +  }    -  +  else SIMPLE_ARG_TYPE_ERROR ("`[]=", 1, "int(0..6)|string"); +  +  stack_swap(); +  pop_stack(); + } +  + static void stat_indices(INT32 args); + static void stat_values(INT32 args); +  + /*! @decl mapping(string:int)|array cast (string to); +  *! +  *! Convert the stat object to a mapping or array. +  */   static void stat_cast(INT32 args)   { -  if (!args) -  SIMPLE_TOO_FEW_ARGS_ERROR("Stat cast",1); -  if (TYPEOF(sp[-args]) == T_STRING && !sp[-args].u.string->size_shift) +  struct pike_string *type; +  +  if (args!=1) +  SIMPLE_WRONG_NUM_ARGS_ERROR("Stat cast",1); +  if (TYPEOF(sp[-args]) != T_STRING) +  SIMPLE_ARG_TYPE_ERROR("cast",1,"string"); +  +  type = Pike_sp[-args].u.string; +  pop_stack(); /* type have at least one more reference. */ +  +  if (type == literal_array_string)    { -  if (strncmp(sp[-args].u.string->str,"array",5)==0) -  { -  pop_n_elems(args); +     push_int(0);    push_int(6);    stat_index(2); -  +  } +  else if (type == literal_mapping_string) +  { +  stat_indices(0); +  stat_values(0); +  push_mapping(mkmapping(Pike_sp[-2].u.array, Pike_sp[-1].u.array)); +  stack_pop_n_elems_keep_top(2); +  } +  else +  push_undefined(); + } +  + /*! @decl int(0..1) _equal(mixed other) +  *! +  *! Compare this object with another @[Stat] object. +  *! +  *! @returns +  *! Returns @expr{1@} if @[other] is a @[Stat] object with the +  *! same content, and @expr{0@} (zero) otherwise. +  */ + static void stat__equal(INT32 args) + { +  struct stat_storage *this_st = THIS_STAT; +  struct stat_storage *other_st; +  +  if (args != 1) +  SIMPLE_WRONG_NUM_ARGS_ERROR("_equal", 1); +  +  if ((TYPEOF(Pike_sp[-args]) != T_OBJECT) || +  !(other_st = get_storage(Pike_sp[-1].u.object, stat_program))) { +  push_int(0);    return;    } -  +  +  if (this_st == other_st) { +  push_int(1); +  return;    } -  SIMPLE_BAD_ARG_ERROR("Stat cast",1, -  "string(\"array\")"); +  +  push_int(!memcmp(this_st, other_st, sizeof(struct stat_storage)));   }      static void stat__sprintf(INT32 args)   { -  int n=0, x; +  int x;       if (args<1) -  SIMPLE_TOO_FEW_ARGS_ERROR("_sprintf",2); +  SIMPLE_WRONG_NUM_ARGS_ERROR("_sprintf",2);       if (TYPEOF(sp[-args]) != T_INT) -  SIMPLE_BAD_ARG_ERROR("_sprintf",0,"integer"); +  SIMPLE_ARG_TYPE_ERROR("_sprintf",0,"integer");       x=sp[-args].u.integer;    pop_n_elems(args);    switch (x)    {    case 'O': -  n++; push_constant_text("Stat("); -  -  ref_push_string(stat_index_strs[STAT_MODE_STRING]); -  n++; stat_index(1); -  -  n++; push_constant_text(" "); -  -  ref_push_string(stat_index_strs[STAT_SIZE]); -  n++; stat_index(1); -  n++; push_constant_text("b)"); -  f_add(n); +  push_static_text("Stat(%s %db)"); +  _stat_index(STAT_MODE_STRING); +  _stat_index(STAT_SIZE); +  f_sprintf(3);    return;    default:    push_int(0);    return;    }   }      static void stat_indices(INT32 args)   {    pop_n_elems(args);
pike.git/src/modules/_Stdio/stat.c:897:    for (i=0; i<z; i++)    {    ref_push_object(fp->current_object);    push_svalue(a->item+i);    f_index(2);    }    f_aggregate(z);    stack_pop_keep_top();   }    + #ifdef __GNUC__ + /* Without this gcc inlines all the function calls to _index_set etc below. +  +  It's really rather pointless. And we really need a better way to +  avoid this than adding a lot of -Os around the code. :) + */ + #pragma GCC optimize "-Os" + #endif +  + static void stat_create (INT32 args) + { +  if (args >= 1 && !UNSAFE_IS_ZERO (Pike_sp - 1)) { +  pop_n_elems (args - 1); +  args = 1; +  +  if (TYPEOF(sp[-1]) == T_OBJECT) +  if (sp[-1].u.object->prog == stat_program) { +  *THIS_STAT = *(struct stat_storage *) sp[-1].u.object->storage; +  pop_stack(); +  return; +  } +  +  if ((1 << TYPEOF(sp[-1])) & (BIT_PROGRAM|BIT_OBJECT|BIT_MAPPING)) +  { +  struct keypair *k; +  int e; +  NEW_MAPPING_LOOP( stat_map->data ) +  { +  push_svalue(&k->ind); +  SET_SVAL_SUBTYPE(sp[-1],1); +  o_index(); +  if(!IS_UNDEFINED(sp-1)) { +  _stat_index_set( k->val.u.integer, sp-1, -1,0 ); +  } +  pop_stack(); +  } +  } +  else if (TYPEOF(sp[-1]) == T_ARRAY) +  { +  struct array *a = sp[-1].u.array; +  int i; +  if (a->size != 7) +  SIMPLE_ARG_TYPE_ERROR ("create", 1, "stat array with 7 elements"); +  for (i = 0; i < 7; i++) { +  INT64 val; +  if (TYPEOF(ITEM(a)[i]) == T_INT) +  val = ITEM(a)[i].u.integer; +  else if (TYPEOF(ITEM(a)[i]) == T_OBJECT && +  is_bignum_object (ITEM(a)[i].u.object)) { +  if (!int64_from_bignum (&val, ITEM(a)[i].u.object)) +  Pike_error ("create: Too big integer in stat array.\n"); +  } +  else +  SIMPLE_ARG_TYPE_ERROR ("create", 1, "array(int)"); +  stat_compat_set (i, val); +  } +  } +  +  else +  SIMPLE_ARG_TYPE_ERROR ("create", 1, "void|Stdio.Stat|array(int)"); +  } +  +  pop_n_elems (args); + }   #undef THIS_STAT      void push_stat(PIKE_STAT_T *s)   {    struct object *o;    struct stat_storage *stor;    o=clone_object(stat_program,0); -  stor=(struct stat_storage*)get_storage(o,stat_program); +  stor=get_storage(o,stat_program);    stor->s=*s;    push_object(o);   }    -  +    /*! @endclass    */   /*! @endmodule    */      /* ---------------------------------------------------------------- */    - void init_stdio_stat() + void init_stdio_stat(void)   { -  INT_TYPE n=0; +  unsigned int n=0;    -  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"); +  static const struct { +  const char *name; +  const INT_TYPE id; +  } __indices[] = { +  {"dev",STAT_DEV}, +  {"ino",STAT_INO}, +  {"mode",STAT_MODE}, +  {"nlink",STAT_NLINK}, +  {"uid",STAT_UID}, +  {"gid",STAT_GID}, +  {"rdev",STAT_RDEV}, +  {"size",STAT_SIZE},   #ifdef HAVE_STRUCT_STAT_BLOCKS -  INIT_INDEX (STAT_BLKSIZE, "blksize"); -  INIT_INDEX (STAT_BLOCKS, "blocks"); +  {"blksize",STAT_BLKSIZE}, +  {"blocks",STAT_BLOCKS},   #endif -  INIT_INDEX (STAT_ATIME, "atime"); -  INIT_INDEX (STAT_MTIME, "mtime"); -  INIT_INDEX (STAT_CTIME, "ctime"); +  {"atime",STAT_ATIME}, +  {"mtime",STAT_MTIME}, +  {"ctime",STAT_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"); +  {"atime_nsec",STAT_ATIME_NSEC}, +  {"mtime_nsec",STAT_MTIME_NSEC}, +  {"ctime_nsec",STAT_CTIME_NSEC},    -  INIT_INDEX (STAT_TYPE, "type"); -  INIT_INDEX (STAT_MODE_STRING, "mode_string"); +  {"islnk",STAT_ISLNK}, +  {"isreg",STAT_ISREG}, +  {"isdir",STAT_ISDIR}, +  {"ischr",STAT_ISCHR}, +  {"isblk",STAT_ISBLK}, +  {"isfifo",STAT_ISFIFO}, +  {"issock",STAT_ISSOCK},    -  f_aggregate_mapping(n*2); -  stat_map=sp[-1].u.mapping; +  {"type",STAT_TYPE}, +  {"mode_string",STAT_MODE_STRING} +  }; +  +  str_type_reg = make_shared_string("reg"); +  str_type_dir = make_shared_string("dir"); +  str_type_lnk = make_shared_string("lnk"); +  str_type_chr = make_shared_string("chr"); +  str_type_blk = make_shared_string("blk"); +  str_type_fifo = make_shared_string("fifo"); +  str_type_sock = make_shared_string( "sock"); +  str_type_unknown = make_shared_string( "unknown"); +  +  stat_map=allocate_mapping(1); +  push_int(0); +  for( n=0; n<sizeof(__indices)/sizeof(__indices[0]); n++ ) +  { +  struct pike_string *s = make_shared_string(__indices[n].name); +  stat_index_strs[__indices[n].id]=s; +  sp[-1].u.integer = __indices[n].id; +  mapping_string_insert( stat_map, s, sp-1); +  }    sp--;    dmalloc_touch_svalue(sp);       START_NEW_PROGRAM_ID(STDIO_STAT);    ADD_STORAGE(struct stat_storage);       ADD_FUNCTION ("create", stat_create,    tFunc(tOr5(tVoid,tObjImpl_STDIO_STAT,tPrg(tObj),tMapping,tArr(tInt)),    tVoid), ID_PROTECTED);   
pike.git/src/modules/_Stdio/stat.c:987:    tOr(tFunc(tOr(tStr,tInt06),tOr3(tStr,tInt,tFunction)),    tFunc(tInt tInt,tArr(tInt))),0);       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);    -  ADD_FUNCTION("cast",stat_cast,tFunc(tStr,tArray),0); +  ADD_FUNCTION("cast",stat_cast,tFunc(tStr,tOr(tMapping,tArray)),ID_PROTECTED); +  ADD_FUNCTION("_equal", stat__equal, tFunc(tMix,tInt01), ID_PROTECTED);    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);       set_init_callback (stat_init);       stat_program=end_program();    add_program_constant("Stat",stat_program,0);   }    - void exit_stdio_stat() + void exit_stdio_stat(void)   {    size_t i;       free_program(stat_program);    free_mapping(stat_map);       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);   }