(linenum→info "unix/slp.c:2238")

ruby/1.9.0/file.c

    1: /**********************************************************************
    2: 
    3:   file.c -
    4: 
    5:   $Author: matz $
    6:   $Date: 2007-12-21 12:34:26 +0900 (Fri, 21 Dec 2007) $
    7:   created at: Mon Nov 15 12:24:34 JST 1993
    8: 
    9:   Copyright (C) 1993-2007 Yukihiro Matsumoto
   10:   Copyright (C) 2000  Network Applied Communication Laboratory, Inc.
   11:   Copyright (C) 2000  Information-technology Promotion Agency, Japan
   12: 
   13: **********************************************************************/
   14: 
   15: #ifdef _WIN32
   16: #include "missing/file.h"
   17: #endif
   18: 
   19: #include "ruby/ruby.h"
   20: #include "ruby/io.h"
   21: #include "ruby/signal.h"
   22: #include "ruby/util.h"
   23: #include "dln.h"
   24: 
   25: #ifdef HAVE_UNISTD_H
   26: #include <unistd.h>
   27: #endif
   28: 
   29: #ifdef HAVE_SYS_FILE_H
   30: # include <sys/file.h>
   31: #else
   32: int flock(int, int);
   33: #endif
   34: 
   35: #ifdef HAVE_SYS_PARAM_H
   36: # include <sys/param.h>
   37: #endif
   38: #ifndef MAXPATHLEN
   39: # define MAXPATHLEN 1024
   40: #endif
   41: 
   42: #include <ctype.h>
   43: 
   44: #include <time.h>
   45: 
   46: #ifdef HAVE_UTIME_H
   47: #include <utime.h>
   48: #elif defined HAVE_SYS_UTIME_H
   49: #include <sys/utime.h>
   50: #endif
   51: 
   52: #ifdef HAVE_PWD_H
   53: #include <pwd.h>
   54: #endif
   55: 
   56: #include <sys/types.h>
   57: #include <sys/stat.h>
   58: 
   59: #ifdef HAVE_SYS_MKDEV_H
   60: #include <sys/mkdev.h>
   61: #endif
   62: 
   63: #if !defined HAVE_LSTAT && !defined lstat
   64: #define lstat stat
   65: #endif
   66: 
   67: #ifdef __BEOS__ /* should not change ID if -1 */
   68: static int
   69: be_chown(const char *path, uid_t owner, gid_t group)
   70: {
   71:     if (owner == -1 || group == -1) {
   72:         struct stat st;
   73:         if (stat(path, &st) < 0) return -1;
   74:         if (owner == -1) owner = st.st_uid;
   75:         if (group == -1) group = st.st_gid;
   76:     }
   77:     return chown(path, owner, group);
   78: }
   79: #define chown be_chown
   80: static int
   81: be_fchown(int fd, uid_t owner, gid_t group)
   82: {
   83:     if (owner == -1 || group == -1) {
   84:         struct stat st;
   85:         if (fstat(fd, &st) < 0) return -1;
   86:         if (owner == -1) owner = st.st_uid;
   87:         if (group == -1) group = st.st_gid;
   88:     }
   89:     return fchown(fd, owner, group);
   90: }
   91: #define fchown be_fchown
   92: #endif /* __BEOS__ */
   93: 
   94: VALUE rb_cFile;
   95: VALUE rb_mFileTest;
   96: VALUE rb_cStat;
   97: 
   98: static VALUE
   99: rb_get_path_check(VALUE obj, int check)
  100: {
  101:     VALUE tmp;
  102:     static ID to_path;
  103: 
  104:     if (check) rb_check_safe_obj(obj);
  105:     tmp = rb_check_string_type(obj);
  106:     if (!NIL_P(tmp)) goto exit;
  107: 
  108:     if (!to_path) {
  109:         to_path = rb_intern("to_path");
  110:     }
  111:     if (rb_respond_to(obj, to_path)) {
  112:         tmp = rb_funcall(obj, to_path, 0, 0);
  113:     }
  114:     else {
  115:         tmp = obj;
  116:     }
  117:   exit:
  118:     StringValueCStr(tmp);
  119:     if (check && obj != tmp) {
  120:         rb_check_safe_obj(tmp);
  121:     }
  122:     return rb_str_new4(tmp);
  123: }
  124: 
  125: VALUE
  126: rb_get_path_no_checksafe(VALUE obj)
  127: {
  128:     return rb_get_path_check(obj, 0);
  129: }
  130: 
  131: VALUE
  132: rb_get_path(VALUE obj)
  133: {
  134:     return rb_get_path_check(obj, 1);
  135: }
  136: 
  137: static long
  138: apply2files(void (*func)(const char *, void *), VALUE vargs, void *arg)
  139: {
  140:     long i;
  141:     volatile VALUE path;
  142: 
  143:     rb_secure(4);
  144:     for (i=0; i<RARRAY_LEN(vargs); i++) {
  145:         path = rb_get_path(RARRAY_PTR(vargs)[i]);
  146:         (*func)(StringValueCStr(path), arg);
  147:     }
  148: 
  149:     return RARRAY_LEN(vargs);
  150: }
  151: 
  152: /*
  153:  *  call-seq:
  154:  *     file.path -> filename
  155:  *  
  156:  *  Returns the pathname used to create <i>file</i> as a string. Does
  157:  *  not normalize the name.
  158:  *     
  159:  *     File.new("testfile").path               #=> "testfile"
  160:  *     File.new("/tmp/../tmp/xxx", "w").path   #=> "/tmp/../tmp/xxx"
  161:  *     
  162:  */
  163: 
  164: static VALUE
  165: rb_file_path(VALUE obj)
  166: {
  167:     rb_io_t *fptr;
  168: 
  169:     fptr = RFILE(rb_io_taint_check(obj))->fptr;
  170:     rb_io_check_initialized(fptr);
  171:     if (!fptr->path) return Qnil;
  172:     return rb_tainted_str_new2(fptr->path);
  173: }
  174: 
  175: static VALUE
  176: stat_new_0(VALUE klass, struct stat *st)
  177: {
  178:     struct stat *nst = 0;
  179: 
  180:     if (st) {
  181:         nst = ALLOC(struct stat);
  182:         *nst = *st;
  183:     }
  184:     return Data_Wrap_Struct(klass, NULL, free, nst);
  185: }
  186: 
  187: static VALUE
  188: stat_new(struct stat *st)
  189: {
  190:     return stat_new_0(rb_cStat, st);
  191: }
  192: 
  193: static struct stat*
  194: get_stat(VALUE self)
  195: {
  196:     struct stat* st;
  197:     Data_Get_Struct(self, struct stat, st);
  198:     if (!st) rb_raise(rb_eTypeError, "uninitialized File::Stat");
  199:     return st;
  200: }
  201: 
  202: static struct timespec stat_mtimespec(struct stat *st);
  203: 
  204: /*
  205:  *  call-seq:
  206:  *     stat <=> other_stat    => -1, 0, 1
  207:  *  
  208:  *  Compares <code>File::Stat</code> objects by comparing their
  209:  *  respective modification times.
  210:  *     
  211:  *     f1 = File.new("f1", "w")
  212:  *     sleep 1
  213:  *     f2 = File.new("f2", "w")
  214:  *     f1.stat <=> f2.stat   #=> -1
  215:  */
  216: 
  217: static VALUE
  218: rb_stat_cmp(VALUE self, VALUE other)
  219: {
  220:     if (rb_obj_is_kind_of(other, rb_obj_class(self))) {
  221:         struct timespec ts1 = stat_mtimespec(get_stat(self));
  222:         struct timespec ts2 = stat_mtimespec(get_stat(other));
  223:         if (ts1.tv_sec == ts2.tv_sec) {
  224:             if (ts1.tv_nsec == ts2.tv_nsec) return INT2FIX(0);
  225:             if (ts1.tv_nsec < ts2.tv_nsec) return INT2FIX(-1);
  226:             return INT2FIX(1);
  227:         }
  228:         if (ts1.tv_sec < ts2.tv_sec) return INT2FIX(-1);
  229:         return INT2FIX(1);
  230:     }
  231:     return Qnil;
  232: }
  233: 
  234: /*
  235:  *  call-seq:
  236:  *     stat.dev    => fixnum
  237:  *  
  238:  *  Returns an integer representing the device on which <i>stat</i>
  239:  *  resides.
  240:  *     
  241:  *     File.stat("testfile").dev   #=> 774
  242:  */
  243: 
  244: static VALUE
  245: rb_stat_dev(VALUE self)
  246: {
  247:     return INT2NUM(get_stat(self)->st_dev);
  248: }
  249: 
  250: /*
  251:  *  call-seq:
  252:  *     stat.dev_major   => fixnum
  253:  *  
  254:  *  Returns the major part of <code>File_Stat#dev</code> or
  255:  *  <code>nil</code>.
  256:  *     
  257:  *     File.stat("/dev/fd1").dev_major   #=> 2
  258:  *     File.stat("/dev/tty").dev_major   #=> 5
  259:  */
  260: 
  261: static VALUE
  262: rb_stat_dev_major(VALUE self)
  263: {
  264: #if defined(major)
  265:     long dev = get_stat(self)->st_dev;
  266:     return ULONG2NUM(major(dev));
  267: #else
  268:     return Qnil;
  269: #endif
  270: }
  271: 
  272: /*
  273:  *  call-seq:
  274:  *     stat.dev_minor   => fixnum
  275:  *  
  276:  *  Returns the minor part of <code>File_Stat#dev</code> or
  277:  *  <code>nil</code>.
  278:  *     
  279:  *     File.stat("/dev/fd1").dev_minor   #=> 1
  280:  *     File.stat("/dev/tty").dev_minor   #=> 0
  281:  */
  282: 
  283: static VALUE
  284: rb_stat_dev_minor(VALUE self)
  285: {
  286: #if defined(minor)
  287:     long dev = get_stat(self)->st_dev;
  288:     return ULONG2NUM(minor(dev));
  289: #else
  290:     return Qnil;
  291: #endif
  292: }
  293: 
  294: 
  295: /*
  296:  *  call-seq:
  297:  *     stat.ino   => fixnum
  298:  *  
  299:  *  Returns the inode number for <i>stat</i>.
  300:  *     
  301:  *     File.stat("testfile").ino   #=> 1083669
  302:  *     
  303:  */
  304: 
  305: static VALUE
  306: rb_stat_ino(VALUE self)
  307: {
  308: #ifdef HUGE_ST_INO
  309:     return ULL2NUM(get_stat(self)->st_ino);
  310: #else
  311:     return ULONG2NUM(get_stat(self)->st_ino);
  312: #endif
  313: }
  314: 
  315: /*
  316:  *  call-seq:
  317:  *     stat.mode   => fixnum
  318:  *  
  319:  *  Returns an integer representing the permission bits of
  320:  *  <i>stat</i>. The meaning of the bits is platform dependent; on
  321:  *  Unix systems, see <code>stat(2)</code>.
  322:  *     
  323:  *     File.chmod(0644, "testfile")   #=> 1
  324:  *     s = File.stat("testfile")
  325:  *     sprintf("%o", s.mode)          #=> "100644"
  326:  */
  327: 
  328: static VALUE
  329: rb_stat_mode(VALUE self)
  330: {
  331: #ifdef __BORLANDC__
  332:     return UINT2NUM((unsigned short)(get_stat(self)->st_mode));
  333: #else
  334:     return UINT2NUM(get_stat(self)->st_mode);
  335: #endif
  336: }
  337: 
  338: /*
  339:  *  call-seq:
  340:  *     stat.nlink   => fixnum
  341:  *  
  342:  *  Returns the number of hard links to <i>stat</i>.
  343:  *     
  344:  *     File.stat("testfile").nlink             #=> 1
  345:  *     File.link("testfile", "testfile.bak")   #=> 0
  346:  *     File.stat("testfile").nlink             #=> 2
  347:  *     
  348:  */
  349: 
  350: static VALUE
  351: rb_stat_nlink(VALUE self)
  352: {
  353:     return UINT2NUM(get_stat(self)->st_nlink);
  354: }
  355: 
  356: 
  357: /*
  358:  *  call-seq:
  359:  *     stat.uid    => fixnum
  360:  *  
  361:  *  Returns the numeric user id of the owner of <i>stat</i>.
  362:  *     
  363:  *     File.stat("testfile").uid   #=> 501
  364:  *     
  365:  */
  366: 
  367: static VALUE
  368: rb_stat_uid(VALUE self)
  369: {
  370:     return UIDT2NUM(get_stat(self)->st_uid);
  371: }
  372: 
  373: /*
  374:  *  call-seq:
  375:  *     stat.gid   => fixnum
  376:  *  
  377:  *  Returns the numeric group id of the owner of <i>stat</i>.
  378:  *     
  379:  *     File.stat("testfile").gid   #=> 500
  380:  *     
  381:  */
  382: 
  383: static VALUE
  384: rb_stat_gid(VALUE self)
  385: {
  386:     return GIDT2NUM(get_stat(self)->st_gid);
  387: }
  388: 
  389: 
  390: /*
  391:  *  call-seq:
  392:  *     stat.rdev   =>  fixnum or nil
  393:  *  
  394:  *  Returns an integer representing the device type on which
  395:  *  <i>stat</i> resides. Returns <code>nil</code> if the operating
  396:  *  system doesn't support this feature.
  397:  *     
  398:  *     File.stat("/dev/fd1").rdev   #=> 513
  399:  *     File.stat("/dev/tty").rdev   #=> 1280
  400:  */
  401: 
  402: static VALUE
  403: rb_stat_rdev(VALUE self)
  404: {
  405: #ifdef HAVE_ST_RDEV
  406:     return ULONG2NUM(get_stat(self)->st_rdev);
  407: #else
  408:     return Qnil;
  409: #endif
  410: }
  411: 
  412: /*
  413:  *  call-seq:
  414:  *     stat.rdev_major   => fixnum
  415:  *  
  416:  *  Returns the major part of <code>File_Stat#rdev</code> or
  417:  *  <code>nil</code>.
  418:  *     
  419:  *     File.stat("/dev/fd1").rdev_major   #=> 2
  420:  *     File.stat("/dev/tty").rdev_major   #=> 5
  421:  */
  422: 
  423: static VALUE
  424: rb_stat_rdev_major(VALUE self)
  425: {
  426: #if defined(HAVE_ST_RDEV) && defined(major)
  427:     long rdev = get_stat(self)->st_rdev;
  428:     return ULONG2NUM(major(rdev));
  429: #else
  430:     return Qnil;
  431: #endif
  432: }
  433: 
  434: /*
  435:  *  call-seq:
  436:  *     stat.rdev_minor   => fixnum
  437:  *  
  438:  *  Returns the minor part of <code>File_Stat#rdev</code> or
  439:  *  <code>nil</code>.
  440:  *     
  441:  *     File.stat("/dev/fd1").rdev_minor   #=> 1
  442:  *     File.stat("/dev/tty").rdev_minor   #=> 0
  443:  */
  444: 
  445: static VALUE
  446: rb_stat_rdev_minor(VALUE self)
  447: {
  448: #if defined(HAVE_ST_RDEV) && defined(minor)
  449:     long rdev = get_stat(self)->st_rdev;
  450:     return ULONG2NUM(minor(rdev));
  451: #else
  452:     return Qnil;
  453: #endif
  454: }
  455: 
  456: /*
  457:  *  call-seq:
  458:  *     stat.size    => fixnum
  459:  *  
  460:  *  Returns the size of <i>stat</i> in bytes.
  461:  *     
  462:  *     File.stat("testfile").size   #=> 66
  463:  */
  464: 
  465: static VALUE
  466: rb_stat_size(VALUE self)
  467: {
  468:     return OFFT2NUM(get_stat(self)->st_size);
  469: }
  470: 
  471: /*
  472:  *  call-seq:
  473:  *     stat.blksize   => integer or nil
  474:  *  
  475:  *  Returns the native file system's block size. Will return <code>nil</code>
  476:  *  on platforms that don't support this information.
  477:  *     
  478:  *     File.stat("testfile").blksize   #=> 4096
  479:  *     
  480:  */
  481: 
  482: static VALUE
  483: rb_stat_blksize(VALUE self)
  484: {
  485: #ifdef HAVE_ST_BLKSIZE
  486:     return ULONG2NUM(get_stat(self)->st_blksize);
  487: #else
  488:     return Qnil;
  489: #endif
  490: }
  491: 
  492: /*
  493:  *  call-seq:
  494:  *     stat.blocks    => integer or nil
  495:  *  
  496:  *  Returns the number of native file system blocks allocated for this
  497:  *  file, or <code>nil</code> if the operating system doesn't 
  498:  *  support this feature.
  499:  *     
  500:  *     File.stat("testfile").blocks   #=> 2
  501:  */
  502: 
  503: static VALUE
  504: rb_stat_blocks(VALUE self)
  505: {
  506: #ifdef HAVE_ST_BLOCKS
  507:     return ULONG2NUM(get_stat(self)->st_blocks);
  508: #else
  509:     return Qnil;
  510: #endif
  511: }
  512: 
  513: static struct timespec
  514: stat_atimespec(struct stat *st)
  515: {
  516:     struct timespec ts;
  517:     ts.tv_sec = st->st_atime;
  518: #if defined(HAVE_STRUCT_STAT_ST_ATIM)
  519:     ts.tv_nsec = st->st_atim.tv_nsec;
  520: #elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC)
  521:     ts.tv_nsec = st->st_atimespec.tv_nsec;
  522: #elif defined(HAVE_STRUCT_STAT_ST_ATIMENSEC)
  523:     ts.tv_nsec = st->st_atimensec;
  524: #else
  525:     ts.tv_nsec = 0;
  526: #endif
  527:     return ts;
  528: }
  529: 
  530: static VALUE
  531: stat_atime(struct stat *st)
  532: {
  533:     struct timespec ts = stat_atimespec(st);
  534:     return rb_time_nano_new(ts.tv_sec, ts.tv_nsec);
  535: }
  536: 
  537: static struct timespec
  538: stat_mtimespec(struct stat *st)
  539: {
  540:     struct timespec ts;
  541:     ts.tv_sec = st->st_mtime;
  542: #if defined(HAVE_STRUCT_STAT_ST_MTIM)
  543:     ts.tv_nsec = st->st_mtim.tv_nsec;
  544: #elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC)
  545:     ts.tv_nsec = st->st_mtimespec.tv_nsec;
  546: #elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC)
  547:     ts.tv_nsec = st->st_mtimensec;
  548: #else
  549:     ts.tv_nsec = 0;
  550: #endif
  551:     return ts;
  552: }
  553: 
  554: static VALUE
  555: stat_mtime(struct stat *st)
  556: {
  557:     struct timespec ts = stat_mtimespec(st);
  558:     return rb_time_nano_new(ts.tv_sec, ts.tv_nsec);
  559: }
  560: 
  561: static struct timespec
  562: stat_ctimespec(struct stat *st)
  563: {
  564:     struct timespec ts;
  565:     ts.tv_sec = st->st_ctime;
  566: #if defined(HAVE_STRUCT_STAT_ST_CTIM)
  567:     ts.tv_nsec = st->st_ctim.tv_nsec;
  568: #elif defined(HAVE_STRUCT_STAT_ST_CTIMESPEC)
  569:     ts.tv_nsec = st->st_ctimespec.tv_nsec;
  570: #elif defined(HAVE_STRUCT_STAT_ST_CTIMENSEC)
  571:     ts.tv_nsec = st->st_ctimensec;
  572: #else
  573:     ts.tv_nsec = 0;
  574: #endif
  575:     return ts;
  576: }
  577: 
  578: static VALUE
  579: stat_ctime(struct stat *st)
  580: {
  581:     struct timespec ts = stat_ctimespec(st);
  582:     return rb_time_nano_new(ts.tv_sec, ts.tv_nsec);
  583: }
  584: 
  585: /*
  586:  *  call-seq:
  587:  *     stat.atime   => time
  588:  *  
  589:  *  Returns the last access time for this file as an object of class
  590:  *  <code>Time</code>.
  591:  *     
  592:  *     File.stat("testfile").atime   #=> Wed Dec 31 18:00:00 CST 1969
  593:  *     
  594:  */
  595: 
  596: static VALUE
  597: rb_stat_atime(VALUE self)
  598: {
  599:     return stat_atime(get_stat(self));
  600: }
  601: 
  602: /*
  603:  *  call-seq:
  604:  *     stat.mtime -> aTime
  605:  *  
  606:  *  Returns the modification time of <i>stat</i>.
  607:  *     
  608:  *     File.stat("testfile").mtime   #=> Wed Apr 09 08:53:14 CDT 2003
  609:  *     
  610:  */
  611: 
  612: static VALUE
  613: rb_stat_mtime(VALUE self)
  614: {
  615:     return stat_mtime(get_stat(self));
  616: }
  617: 
  618: /*
  619:  *  call-seq:
  620:  *     stat.ctime -> aTime
  621:  *  
  622:  *  Returns the change time for <i>stat</i> (that is, the time
  623:  *  directory information about the file was changed, not the file
  624:  *  itself).
  625:  *     
  626:  *     File.stat("testfile").ctime   #=> Wed Apr 09 08:53:14 CDT 2003
  627:  *     
  628:  */
  629: 
  630: static VALUE
  631: rb_stat_ctime(VALUE self)
  632: {
  633:     return stat_ctime(get_stat(self));
  634: }
  635: 
  636: /*
  637:  * call-seq:
  638:  *   stat.inspect  =>  string
  639:  *
  640:  * Produce a nicely formatted description of <i>stat</i>.
  641:  *
  642:  *   File.stat("/etc/passwd").inspect
  643:  *      #=> "#<File::Stat dev=0xe000005, ino=1078078, mode=0100644, 
  644:  *           nlink=1, uid=0, gid=0, rdev=0x0, size=1374, blksize=4096, 
  645:  *           blocks=8, atime=Wed Dec 10 10:16:12 CST 2003, 
  646:  *           mtime=Fri Sep 12 15:41:41 CDT 2003, 
  647:  *           ctime=Mon Oct 27 11:20:27 CST 2003>"
  648: