Ruby  2.1.10p492(2016-04-01revision54464)
file.c
Go to the documentation of this file.
1 /**********************************************************************
2 
3  file.c -
4 
5  $Author: usa $
6  created at: Mon Nov 15 12:24:34 JST 1993
7 
8  Copyright (C) 1993-2007 Yukihiro Matsumoto
9  Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
10  Copyright (C) 2000 Information-technology Promotion Agency, Japan
11 
12 **********************************************************************/
13 
14 #ifdef _WIN32
15 #include "missing/file.h"
16 #endif
17 #ifdef __CYGWIN__
18 #include <windows.h>
19 #include <sys/cygwin.h>
20 #include <wchar.h>
21 #endif
22 #ifdef __APPLE__
23 #include <CoreFoundation/CFString.h>
24 #endif
25 
26 #include "ruby/ruby.h"
27 #include "ruby/io.h"
28 #include "ruby/util.h"
29 #include "ruby/thread.h"
30 #include "dln.h"
31 #include "internal.h"
32 
33 #ifdef HAVE_UNISTD_H
34 #include <unistd.h>
35 #endif
36 
37 #ifdef HAVE_SYS_FILE_H
38 # include <sys/file.h>
39 #else
40 int flock(int, int);
41 #endif
42 
43 #ifdef HAVE_SYS_PARAM_H
44 # include <sys/param.h>
45 #endif
46 #ifndef MAXPATHLEN
47 # define MAXPATHLEN 1024
48 #endif
49 
50 #include <ctype.h>
51 
52 #include <time.h>
53 
54 #ifdef HAVE_UTIME_H
55 #include <utime.h>
56 #elif defined HAVE_SYS_UTIME_H
57 #include <sys/utime.h>
58 #endif
59 
60 #ifdef HAVE_PWD_H
61 #include <pwd.h>
62 #endif
63 
64 #include <sys/types.h>
65 #include <sys/stat.h>
66 
67 #if defined(__native_client__) && defined(NACL_NEWLIB)
68 # include "nacl/utime.h"
69 # include "nacl/stat.h"
70 # include "nacl/unistd.h"
71 #endif
72 
73 
74 #ifdef HAVE_SYS_MKDEV_H
75 #include <sys/mkdev.h>
76 #endif
77 
78 #if defined(HAVE_FCNTL_H)
79 #include <fcntl.h>
80 #endif
81 
82 #if defined(HAVE_SYS_TIME_H)
83 #include <sys/time.h>
84 #endif
85 
86 #if !defined HAVE_LSTAT && !defined lstat
87 #define lstat stat
88 #endif
89 
90 /* define system APIs */
91 #ifdef _WIN32
92 #define STAT(p, s) rb_w32_ustati64((p), (s))
93 #undef lstat
94 #define lstat(p, s) rb_w32_ustati64((p), (s))
95 #undef access
96 #define access(p, m) rb_w32_uaccess((p), (m))
97 #undef chmod
98 #define chmod(p, m) rb_w32_uchmod((p), (m))
99 #undef chown
100 #define chown(p, o, g) rb_w32_uchown((p), (o), (g))
101 #undef utime
102 #define utime(p, t) rb_w32_uutime((p), (t))
103 #undef link
104 #define link(f, t) rb_w32_ulink((f), (t))
105 #undef unlink
106 #define unlink(p) rb_w32_uunlink(p)
107 #undef rename
108 #define rename(f, t) rb_w32_urename((f), (t))
109 #else
110 #define STAT(p, s) stat((p), (s))
111 #endif
112 
113 #if defined(__BEOS__) || defined(__HAIKU__) /* should not change ID if -1 */
114 static int
115 be_chown(const char *path, uid_t owner, gid_t group)
116 {
117  if (owner == (uid_t)-1 || group == (gid_t)-1) {
118  struct stat st;
119  if (STAT(path, &st) < 0) return -1;
120  if (owner == (uid_t)-1) owner = st.st_uid;
121  if (group == (gid_t)-1) group = st.st_gid;
122  }
123  return chown(path, owner, group);
124 }
125 #define chown be_chown
126 static int
127 be_fchown(int fd, uid_t owner, gid_t group)
128 {
129  if (owner == (uid_t)-1 || group == (gid_t)-1) {
130  struct stat st;
131  if (fstat(fd, &st) < 0) return -1;
132  if (owner == (uid_t)-1) owner = st.st_uid;
133  if (group == (gid_t)-1) group = st.st_gid;
134  }
135  return fchown(fd, owner, group);
136 }
137 #define fchown be_fchown
138 #endif /* __BEOS__ || __HAIKU__ */
139 
143 
144 #define insecure_obj_p(obj, level) ((level) >= 4 || ((level) > 0 && OBJ_TAINTED(obj)))
145 
146 static VALUE
148 {
149 #ifndef _WIN32 /* non Windows == Unix */
150  rb_encoding *fname_encoding = rb_enc_from_index(ENCODING_GET(name));
151  rb_encoding *fs_encoding;
153  && rb_usascii_encoding() != fname_encoding
154  && rb_ascii8bit_encoding() != fname_encoding
155  && (fs_encoding = rb_filesystem_encoding()) != fname_encoding
157  /* Don't call rb_filesystem_encoding() before US-ASCII and ASCII-8BIT */
158  /* fs_encoding should be ascii compatible */
159  name = rb_str_conv_enc(name, fname_encoding, fs_encoding);
160  }
161 #endif
162  return name;
163 }
164 
165 static rb_encoding *
167 {
168  rb_encoding *enc = rb_enc_get(str);
169  if (!rb_enc_asciicompat(enc)) {
170  rb_raise(rb_eEncCompatError, "path name must be ASCII-compatible (%s): %"PRIsVALUE,
171  rb_enc_name(enc), rb_str_inspect(str));
172  }
173  return enc;
174 }
175 
176 VALUE
178 {
179  VALUE tmp;
180  ID to_path;
181 
182  if (insecure_obj_p(obj, level)) {
184  }
185 
186  if (RB_TYPE_P(obj, T_STRING)) {
187  return obj;
188  }
189  CONST_ID(to_path, "to_path");
190  tmp = rb_check_funcall(obj, to_path, 0, 0);
191  if (tmp == Qundef) {
192  tmp = obj;
193  }
194  StringValue(tmp);
195  return tmp;
196 }
197 
198 VALUE
200 {
201  tmp = file_path_convert(tmp);
202  if (obj != tmp && insecure_obj_p(tmp, level)) {
204  }
205 
206  check_path_encoding(tmp);
207  StringValueCStr(tmp);
208 
209  return rb_str_new4(tmp);
210 }
211 
212 static VALUE
214 {
216  return rb_get_path_check_convert(obj, tmp, level);
217 }
218 
219 VALUE
221 {
222  return rb_get_path_check(obj, 0);
223 }
224 
225 VALUE
227 {
228  return rb_get_path_check(obj, rb_safe_level());
229 }
230 
231 VALUE
233 {
234 #ifdef _WIN32
235  rb_encoding *enc = rb_enc_get(path);
236  rb_encoding *utf8 = rb_utf8_encoding();
237  if (enc == rb_ascii8bit_encoding()) {
238  enc = rb_filesystem_encoding();
239  }
240  if (enc != utf8) {
241  path = rb_str_conv_enc(path, enc, utf8);
242  }
243 #elif defined __APPLE__
244  path = rb_str_conv_enc(path, NULL, rb_utf8_encoding());
245 #endif
246  return path;
247 }
248 
249 #ifdef __APPLE__
250 static VALUE
251 rb_str_normalize_ospath0(const char *ptr, long len)
252 {
253  VALUE str;
254  CFIndex buflen = 0;
255  CFRange all;
256  CFStringRef s = CFStringCreateWithBytesNoCopy(kCFAllocatorDefault,
257  (const UInt8 *)ptr, len,
258  kCFStringEncodingUTF8, FALSE,
259  kCFAllocatorNull);
260  CFMutableStringRef m = CFStringCreateMutableCopy(kCFAllocatorDefault, len, s);
261 
262  CFStringNormalize(m, kCFStringNormalizationFormC);
263  all = CFRangeMake(0, CFStringGetLength(m));
264  CFStringGetBytes(m, all, kCFStringEncodingUTF8, '?', FALSE, NULL, 0, &buflen);
265  str = rb_enc_str_new(0, buflen, rb_utf8_encoding());
266  CFStringGetBytes(m, all, kCFStringEncodingUTF8, '?', FALSE, (UInt8 *)RSTRING_PTR(str),
267  buflen, &buflen);
268  rb_str_set_len(str, buflen);
269  CFRelease(m);
270  CFRelease(s);
271  return str;
272 }
273 
274 VALUE
275 rb_str_normalize_ospath(const char *ptr, long len)
276 {
277  const char *p = ptr;
278  const char *e = ptr + len;
279  const char *p1 = p;
280  VALUE str = rb_str_buf_new(len);
281  rb_encoding *enc = rb_utf8_encoding();
282  rb_enc_associate(str, enc);
283 
284  while (p < e) {
285  int l, c;
286  int r = rb_enc_precise_mbclen(p, e, enc);
287  if (!MBCLEN_CHARFOUND_P(r)) {
288  /* invalid byte shall not happen but */
289  rb_str_append(str, rb_str_normalize_ospath0(p1, p-p1));
290  rb_str_cat2(str, "\xEF\xBF\xBD");
291  p += 1;
292  }
293  l = MBCLEN_CHARFOUND_LEN(r);
294  c = rb_enc_mbc_to_codepoint(p, e, enc);
295  if ((0x2000 <= c && c <= 0x2FFF) || (0xF900 <= c && c <= 0xFAFF) ||
296  (0x2F800 <= c && c <= 0x2FAFF)) {
297  if (p - p1 > 0) {
298  rb_str_append(str, rb_str_normalize_ospath0(p1, p-p1));
299  }
300  rb_str_cat(str, p, l);
301  p += l;
302  p1 = p;
303  }
304  else {
305  p += l;
306  }
307  }
308  if (p - p1 > 0) {
309  rb_str_append(str, rb_str_normalize_ospath0(p1, p-p1));
310  }
311 
312  return str;
313 }
314 #endif
315 
316 static long
317 apply2files(void (*func)(const char *, VALUE, void *), VALUE vargs, void *arg)
318 {
319  long i;
320  volatile VALUE path;
321 
322  for (i=0; i<RARRAY_LEN(vargs); i++) {
323  const char *s;
324  path = rb_get_path(RARRAY_AREF(vargs, i));
325  path = rb_str_encode_ospath(path);
326  s = RSTRING_PTR(path);
327  (*func)(s, path, arg);
328  }
329 
330  return RARRAY_LEN(vargs);
331 }
332 
333 /*
334  * call-seq:
335  * file.path -> filename
336  * file.to_path -> filename
337  *
338  * Returns the pathname used to create <i>file</i> as a string. Does
339  * not normalize the name.
340  *
341  * File.new("testfile").path #=> "testfile"
342  * File.new("/tmp/../tmp/xxx", "w").path #=> "/tmp/../tmp/xxx"
343  *
344  */
345 
346 static VALUE
348 {
349  rb_io_t *fptr;
350 
351  fptr = RFILE(rb_io_taint_check(obj))->fptr;
353  if (NIL_P(fptr->pathv)) return Qnil;
354  return rb_obj_taint(rb_str_dup(fptr->pathv));
355 }
356 
357 static size_t
358 stat_memsize(const void *p)
359 {
360  return p ? sizeof(struct stat) : 0;
361 }
362 
364  "stat",
367 };
368 
369 static VALUE
370 stat_new_0(VALUE klass, const struct stat *st)
371 {
372  struct stat *nst = 0;
373 
374  if (st) {
375  nst = ALLOC(struct stat);
376  *nst = *st;
377  }
378  return TypedData_Wrap_Struct(klass, &stat_data_type, nst);
379 }
380 
381 VALUE
382 rb_stat_new(const struct stat *st)
383 {
384  return stat_new_0(rb_cStat, st);
385 }
386 
387 static struct stat*
389 {
390  struct stat* st;
391  TypedData_Get_Struct(self, struct stat, &stat_data_type, st);
392  if (!st) rb_raise(rb_eTypeError, "uninitialized File::Stat");
393  return st;
394 }
395 
396 static struct timespec stat_mtimespec(struct stat *st);
397 
398 /*
399  * call-seq:
400  * stat <=> other_stat -> -1, 0, 1, nil
401  *
402  * Compares File::Stat objects by comparing their respective modification
403  * times.
404  *
405  * +nil+ is returned if the two values are incomparable.
406  *
407  * f1 = File.new("f1", "w")
408  * sleep 1
409  * f2 = File.new("f2", "w")
410  * f1.stat <=> f2.stat #=> -1
411  */
412 
413 static VALUE
414 rb_stat_cmp(VALUE self, VALUE other)
415 {
416  if (rb_obj_is_kind_of(other, rb_obj_class(self))) {
417  struct timespec ts1 = stat_mtimespec(get_stat(self));
418  struct timespec ts2 = stat_mtimespec(get_stat(other));
419  if (ts1.tv_sec == ts2.tv_sec) {
420  if (ts1.tv_nsec == ts2.tv_nsec) return INT2FIX(0);
421  if (ts1.tv_nsec < ts2.tv_nsec) return INT2FIX(-1);
422  return INT2FIX(1);
423  }
424  if (ts1.tv_sec < ts2.tv_sec) return INT2FIX(-1);
425  return INT2FIX(1);
426  }
427  return Qnil;
428 }
429 
430 #define ST2UINT(val) ((val) & ~(~1UL << (sizeof(val) * CHAR_BIT - 1)))
431 
432 #ifndef NUM2DEVT
433 # define NUM2DEVT(v) NUM2UINT(v)
434 #endif
435 #ifndef DEVT2NUM
436 # define DEVT2NUM(v) UINT2NUM(v)
437 #endif
438 #ifndef PRI_DEVT_PREFIX
439 # define PRI_DEVT_PREFIX ""
440 #endif
441 
442 /*
443  * call-seq:
444  * stat.dev -> fixnum
445  *
446  * Returns an integer representing the device on which <i>stat</i>
447  * resides.
448  *
449  * File.stat("testfile").dev #=> 774
450  */
451 
452 static VALUE
454 {
455  return DEVT2NUM(get_stat(self)->st_dev);
456 }
457 
458 /*
459  * call-seq:
460  * stat.dev_major -> fixnum
461  *
462  * Returns the major part of <code>File_Stat#dev</code> or
463  * <code>nil</code>.
464  *
465  * File.stat("/dev/fd1").dev_major #=> 2
466  * File.stat("/dev/tty").dev_major #=> 5
467  */
468 
469 static VALUE
471 {
472 #if defined(major)
473  return INT2NUM(major(get_stat(self)->st_dev));
474 #else
475  return Qnil;
476 #endif
477 }
478 
479 /*
480  * call-seq:
481  * stat.dev_minor -> fixnum
482  *
483  * Returns the minor part of <code>File_Stat#dev</code> or
484  * <code>nil</code>.
485  *
486  * File.stat("/dev/fd1").dev_minor #=> 1
487  * File.stat("/dev/tty").dev_minor #=> 0
488  */
489 
490 static VALUE
492 {
493 #if defined(minor)
494  return INT2NUM(minor(get_stat(self)->st_dev));
495 #else
496  return Qnil;
497 #endif
498 }
499 
500 /*
501  * call-seq:
502  * stat.ino -> fixnum
503  *
504  * Returns the inode number for <i>stat</i>.
505  *
506  * File.stat("testfile").ino #=> 1083669
507  *
508  */
509 
510 static VALUE
512 {
513 #if SIZEOF_STRUCT_STAT_ST_INO > SIZEOF_LONG
514  return ULL2NUM(get_stat(self)->st_ino);
515 #else
516  return ULONG2NUM(get_stat(self)->st_ino);
517 #endif
518 }
519 
520 /*
521  * call-seq:
522  * stat.mode -> fixnum
523  *
524  * Returns an integer representing the permission bits of
525  * <i>stat</i>. The meaning of the bits is platform dependent; on
526  * Unix systems, see <code>stat(2)</code>.
527  *
528  * File.chmod(0644, "testfile") #=> 1
529  * s = File.stat("testfile")
530  * sprintf("%o", s.mode) #=> "100644"
531  */
532 
533 static VALUE
535 {
536  return UINT2NUM(ST2UINT(get_stat(self)->st_mode));
537 }
538 
539 /*
540  * call-seq:
541  * stat.nlink -> fixnum
542  *
543  * Returns the number of hard links to <i>stat</i>.
544  *
545  * File.stat("testfile").nlink #=> 1
546  * File.link("testfile", "testfile.bak") #=> 0
547  * File.stat("testfile").nlink #=> 2
548  *
549  */
550 
551 static VALUE
553 {
554  return UINT2NUM(get_stat(self)->st_nlink);
555 }
556 
557 /*
558  * call-seq:
559  * stat.uid -> fixnum
560  *
561  * Returns the numeric user id of the owner of <i>stat</i>.
562  *
563  * File.stat("testfile").uid #=> 501
564  *
565  */
566 
567 static VALUE
569 {
570  return UIDT2NUM(get_stat(self)->st_uid);
571 }
572 
573 /*
574  * call-seq:
575  * stat.gid -> fixnum
576  *
577  * Returns the numeric group id of the owner of <i>stat</i>.
578  *
579  * File.stat("testfile").gid #=> 500
580  *
581  */
582 
583 static VALUE
585 {
586  return GIDT2NUM(get_stat(self)->st_gid);
587 }
588 
589 /*
590  * call-seq:
591  * stat.rdev -> fixnum or nil
592  *
593  * Returns an integer representing the device type on which
594  * <i>stat</i> resides. Returns <code>nil</code> if the operating
595  * system doesn't support this feature.
596  *
597  * File.stat("/dev/fd1").rdev #=> 513
598  * File.stat("/dev/tty").rdev #=> 1280
599  */
600 
601 static VALUE
603 {
604 #ifdef HAVE_STRUCT_STAT_ST_RDEV
605  return DEVT2NUM(get_stat(self)->st_rdev);
606 #else
607  return Qnil;
608 #endif
609 }
610 
611 /*
612  * call-seq:
613  * stat.rdev_major -> fixnum
614  *
615  * Returns the major part of <code>File_Stat#rdev</code> or
616  * <code>nil</code>.
617  *
618  * File.stat("/dev/fd1").rdev_major #=> 2
619  * File.stat("/dev/tty").rdev_major #=> 5
620  */
621 
622 static VALUE
624 {
625 #if defined(HAVE_STRUCT_STAT_ST_RDEV) && defined(major)
626  return DEVT2NUM(major(get_stat(self)->st_rdev));
627 #else
628  return Qnil;
629 #endif
630 }
631 
632 /*
633  * call-seq:
634  * stat.rdev_minor -> fixnum
635  *
636  * Returns the minor part of <code>File_Stat#rdev</code> or
637  * <code>nil</code>.
638  *
639  * File.stat("/dev/fd1").rdev_minor #=> 1
640  * File.stat("/dev/tty").rdev_minor #=> 0
641  */
642 
643 static VALUE
645 {
646 #if defined(HAVE_STRUCT_STAT_ST_RDEV) && defined(minor)
647  return DEVT2NUM(minor(get_stat(self)->st_rdev));
648 #else
649  return Qnil;
650 #endif
651 }
652 
653 /*
654  * call-seq:
655  * stat.size -> fixnum
656  *
657  * Returns the size of <i>stat</i> in bytes.
658  *
659  * File.stat("testfile").size #=> 66
660  */
661 
662 static VALUE
664 {
665  return OFFT2NUM(get_stat(self)->st_size);
666 }
667 
668 /*
669  * call-seq:
670  * stat.blksize -> integer or nil
671  *
672  * Returns the native file system's block size. Will return <code>nil</code>
673  * on platforms that don't support this information.
674  *
675  * File.stat("testfile").blksize #=> 4096
676  *
677  */
678 
679 static VALUE
681 {
682 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
683  return ULONG2NUM(get_stat(self)->st_blksize);
684 #else
685  return Qnil;
686 #endif
687 }
688 
689 /*
690  * call-seq:
691  * stat.blocks -> integer or nil
692  *
693  * Returns the number of native file system blocks allocated for this
694  * file, or <code>nil</code> if the operating system doesn't
695  * support this feature.
696  *
697  * File.stat("testfile").blocks #=> 2
698  */
699 
700 static VALUE
702 {
703 #ifdef HAVE_STRUCT_STAT_ST_BLOCKS
704 # if SIZEOF_STRUCT_STAT_ST_BLOCKS > SIZEOF_LONG
705  return ULL2NUM(get_stat(self)->st_blocks);
706 # else
707  return ULONG2NUM(get_stat(self)->st_blocks);
708 # endif
709 #else
710  return Qnil;
711 #endif
712 }
713 
714 static struct timespec
715 stat_atimespec(struct stat *st)
716 {
717  struct timespec ts;
718  ts.tv_sec = st->st_atime;
719 #if defined(HAVE_STRUCT_STAT_ST_ATIM)
720  ts.tv_nsec = st->st_atim.tv_nsec;
721 #elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC)
722  ts.tv_nsec = st->st_atimespec.tv_nsec;
723 #elif defined(HAVE_STRUCT_STAT_ST_ATIMENSEC)
724  ts.tv_nsec = st->st_atimensec;
725 #else
726  ts.tv_nsec = 0;
727 #endif
728  return ts;
729 }
730 
731 static VALUE
732 stat_atime(struct stat *st)
733 {
734  struct timespec ts = stat_atimespec(st);
735  return rb_time_nano_new(ts.tv_sec, ts.tv_nsec);
736 }
737 
738 static struct timespec
739 stat_mtimespec(struct stat *st)
740 {
741  struct timespec ts;
742  ts.tv_sec = st->st_mtime;
743 #if defined(HAVE_STRUCT_STAT_ST_MTIM)
744  ts.tv_nsec = st->st_mtim.tv_nsec;
745 #elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC)
746  ts.tv_nsec = st->st_mtimespec.tv_nsec;
747 #elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC)
748  ts.tv_nsec = st->st_mtimensec;
749 #else
750  ts.tv_nsec = 0;
751 #endif
752  return ts;
753 }
754 
755 static VALUE
756 stat_mtime(struct stat *st)
757 {
758  struct timespec ts = stat_mtimespec(st);
759  return rb_time_nano_new(ts.tv_sec, ts.tv_nsec);
760 }
761 
762 static struct timespec
763 stat_ctimespec(struct stat *st)
764 {
765  struct timespec ts;
766  ts.tv_sec = st->st_ctime;
767 #if defined(HAVE_STRUCT_STAT_ST_CTIM)
768  ts.tv_nsec = st->st_ctim.tv_nsec;
769 #elif defined(HAVE_STRUCT_STAT_ST_CTIMESPEC)
770  ts.tv_nsec = st->st_ctimespec.tv_nsec;
771 #elif defined(HAVE_STRUCT_STAT_ST_CTIMENSEC)
772  ts.tv_nsec = st->st_ctimensec;
773 #else
774  ts.tv_nsec = 0;
775 #endif
776  return ts;
777 }
778 
779 static VALUE
780 stat_ctime(struct stat *st)
781 {
782  struct timespec ts = stat_ctimespec(st);
783  return rb_time_nano_new(ts.tv_sec, ts.tv_nsec);
784 }
785 
786 /*
787  * call-seq:
788  * stat.atime -> time
789  *
790  * Returns the last access time for this file as an object of class
791  * <code>Time</code>.
792  *
793  * File.stat("testfile").atime #=> Wed Dec 31 18:00:00 CST 1969
794  *
795  */
796 
797 static VALUE
799 {
800  return stat_atime(get_stat(self));
801 }
802 
803 /*
804  * call-seq:
805  * stat.mtime -> aTime
806  *
807  * Returns the modification time of <i>stat</i>.
808  *
809  * File.stat("testfile").mtime #=> Wed Apr 09 08:53:14 CDT 2003
810  *
811  */
812 
813 static VALUE
815 {
816  return stat_mtime(get_stat(self));
817 }
818 
819 /*
820  * call-seq:
821  * stat.ctime -> aTime
822  *
823  * Returns the change time for <i>stat</i> (that is, the time
824  * directory information about the file was changed, not the file
825  * itself).
826  *
827  * Note that on Windows (NTFS), returns creation time (birth time).
828  *
829  * File.stat("testfile").ctime #=> Wed Apr 09 08:53:14 CDT 2003
830  *
831  */
832 
833 static VALUE
835 {
836  return stat_ctime(get_stat(self));
837 }
838 
839 /*
840  * call-seq:
841  * stat.inspect -> string
842  *
843  * Produce a nicely formatted description of <i>stat</i>.
844  *
845  * File.stat("/etc/passwd").inspect
846  * #=> "#<File::Stat dev=0xe000005, ino=1078078, mode=0100644,
847  * # nlink=1, uid=0, gid=0, rdev=0x0, size=1374, blksize=4096,
848  * # blocks=8, atime=Wed Dec 10 10:16:12 CST 2003,
849  * # mtime=Fri Sep 12 15:41:41 CDT 2003,
850  * # ctime=Mon Oct 27 11:20:27 CST 2003>"
851  */
852 
853 static VALUE
855 {
856  VALUE str;
857  size_t i;
858  static const struct {
859  const char *name;
860  VALUE (*func)(VALUE);
861  } member[] = {
862  {"dev", rb_stat_dev},
863  {"ino", rb_stat_ino},
864  {"mode", rb_stat_mode},
865  {"nlink", rb_stat_nlink},
866  {"uid", rb_stat_uid},
867  {"gid", rb_stat_gid},
868  {"rdev", rb_stat_rdev},
869  {"size", rb_stat_size},
870  {"blksize", rb_stat_blksize},
871  {"blocks", rb_stat_blocks},
872  {"atime", rb_stat_atime},
873  {"mtime", rb_stat_mtime},
874  {"ctime", rb_stat_ctime},
875  };
876 
877  struct stat* st;
878  TypedData_Get_Struct(self, struct stat, &stat_data_type, st);
879  if (!st) {
880  return rb_sprintf("#<%s: uninitialized>", rb_obj_classname(self));
881  }
882 
883  str = rb_str_buf_new2("#<");
884  rb_str_buf_cat2(str, rb_obj_classname(self));
885  rb_str_buf_cat2(str, " ");
886 
887  for (i = 0; i < sizeof(member)/sizeof(member[0]); i++) {
888  VALUE v;
889 
890  if (i > 0) {
891  rb_str_buf_cat2(str, ", ");
892  }
893  rb_str_buf_cat2(str, member[i].name);
894  rb_str_buf_cat2(str, "=");
895  v = (*member[i].func)(self);
896  if (i == 2) { /* mode */
897  rb_str_catf(str, "0%lo", (unsigned long)NUM2ULONG(v));
898  }
899  else if (i == 0 || i == 6) { /* dev/rdev */
900  rb_str_catf(str, "0x%"PRI_DEVT_PREFIX"x", NUM2DEVT(v));
901  }
902  else {
903  rb_str_append(str, rb_inspect(v));
904  }
905  }
906  rb_str_buf_cat2(str, ">");
907  OBJ_INFECT(str, self);
908 
909  return str;
910 }
911 
912 static int
913 rb_stat(VALUE file, struct stat *st)
914 {
915  VALUE tmp;
916 
917  rb_secure(2);
918  tmp = rb_check_convert_type(file, T_FILE, "IO", "to_io");
919  if (!NIL_P(tmp)) {
920  rb_io_t *fptr;
921 
922  GetOpenFile(tmp, fptr);
923  return fstat(fptr->fd, st);
924  }
925  FilePathValue(file);
926  file = rb_str_encode_ospath(file);
927  return STAT(StringValueCStr(file), st);
928 }
929 
930 #ifdef _WIN32
931 static HANDLE
932 w32_io_info(VALUE *file, BY_HANDLE_FILE_INFORMATION *st)
933 {
934  VALUE tmp;
935  HANDLE f, ret = 0;
936 
937  tmp = rb_check_convert_type(*file, T_FILE, "IO", "to_io");
938  if (!NIL_P(tmp)) {
939  rb_io_t *fptr;
940 
941  GetOpenFile(tmp, fptr);
942  f = (HANDLE)rb_w32_get_osfhandle(fptr->fd);
943  if (f == (HANDLE)-1) return INVALID_HANDLE_VALUE;
944  }
945  else {
946  VALUE tmp;
947  WCHAR *ptr;
948  int len;
949  VALUE v;
950 
951  FilePathValue(*file);
952  tmp = rb_str_encode_ospath(*file);
953  len = MultiByteToWideChar(CP_UTF8, 0, RSTRING_PTR(tmp), -1, NULL, 0);
954  ptr = ALLOCV_N(WCHAR, v, len);
955  MultiByteToWideChar(CP_UTF8, 0, RSTRING_PTR(tmp), -1, ptr, len);
956  f = CreateFileW(ptr, 0,
957  FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
958  FILE_FLAG_BACKUP_SEMANTICS, NULL);
959  ALLOCV_END(v);
960  if (f == INVALID_HANDLE_VALUE) return f;
961  ret = f;
962  }
963  if (GetFileType(f) == FILE_TYPE_DISK) {
964  ZeroMemory(st, sizeof(*st));
965  if (GetFileInformationByHandle(f, st)) return ret;
966  }
967  if (ret) CloseHandle(ret);
968  return INVALID_HANDLE_VALUE;
969 }
970 #endif
971 
972 /*
973  * call-seq:
974  * File.stat(file_name) -> stat
975  *
976  * Returns a <code>File::Stat</code> object for the named file (see
977  * <code>File::Stat</code>).
978  *
979  * File.stat("testfile").mtime #=> Tue Apr 08 12:58:04 CDT 2003
980  *
981  */
982 
983 static VALUE
985 {
986  struct stat st;
987 
988  FilePathValue(fname);
989  if (rb_stat(fname, &st) < 0) {
990  rb_sys_fail_path(fname);
991  }
992  return rb_stat_new(&st);
993 }
994 
995 /*
996  * call-seq:
997  * ios.stat -> stat
998  *
999  * Returns status information for <em>ios</em> as an object of type
1000  * <code>File::Stat</code>.
1001  *
1002  * f = File.new("testfile")
1003  * s = f.stat
1004  * "%o" % s.mode #=> "100644"
1005  * s.blksize #=> 4096
1006  * s.atime #=> Wed Apr 09 08:53:54 CDT 2003
1007  *
1008  */
1009 
1010 static VALUE
1012 {
1013  rb_io_t *fptr;
1014  struct stat st;
1015 
1016  GetOpenFile(obj, fptr);
1017  if (fstat(fptr->fd, &st) == -1) {
1018  rb_sys_fail_path(fptr->pathv);
1019  }
1020  return rb_stat_new(&st);
1021 }
1022 
1023 /*
1024  * call-seq:
1025  * File.lstat(file_name) -> stat
1026  *
1027  * Same as <code>File::stat</code>, but does not follow the last symbolic
1028  * link. Instead, reports on the link itself.
1029  *
1030  * File.symlink("testfile", "link2test") #=> 0
1031  * File.stat("testfile").size #=> 66
1032  * File.lstat("link2test").size #=> 8
1033  * File.stat("link2test").size #=> 66
1034  *
1035  */
1036 
1037 static VALUE
1039 {
1040 #ifdef HAVE_LSTAT
1041  struct stat st;
1042 
1043  rb_secure(2);
1044  FilePathValue(fname);
1045  fname = rb_str_encode_ospath(fname);
1046  if (lstat(StringValueCStr(fname), &st) == -1) {
1047  rb_sys_fail_path(fname);
1048  }
1049  return rb_stat_new(&st);
1050 #else
1051  return rb_file_s_stat(klass, fname);
1052 #endif
1053 }
1054 
1055 /*
1056  * call-seq:
1057  * file.lstat -> stat
1058  *
1059  * Same as <code>IO#stat</code>, but does not follow the last symbolic
1060  * link. Instead, reports on the link itself.
1061  *
1062  * File.symlink("testfile", "link2test") #=> 0
1063  * File.stat("testfile").size #=> 66
1064  * f = File.new("link2test")
1065  * f.lstat.size #=> 8
1066  * f.stat.size #=> 66
1067  */
1068 
1069 static VALUE
1071 {
1072 #ifdef HAVE_LSTAT
1073  rb_io_t *fptr;
1074  struct stat st;
1075  VALUE path;
1076 
1077  rb_secure(2);
1078  GetOpenFile(obj, fptr);
1079  if (NIL_P(fptr->pathv)) return Qnil;
1080  path = rb_str_encode_ospath(fptr->pathv);
1081  if (lstat(RSTRING_PTR(path), &st) == -1) {
1082  rb_sys_fail_path(fptr->pathv);
1083  }
1084  return rb_stat_new(&st);
1085 #else
1086  return rb_io_stat(obj);
1087 #endif
1088 }
1089 
1090 static int
1091 rb_group_member(GETGROUPS_T gid)
1092 {
1093 #ifdef _WIN32
1094  return FALSE;
1095 #else
1096  int rv = FALSE;
1097  int groups = 16;
1098  VALUE v = 0;
1099  GETGROUPS_T *gary;
1100  int anum = -1;
1101 
1102  if (getgid() == gid || getegid() == gid)
1103  return TRUE;
1104 
1105  /*
1106  * On Mac OS X (Mountain Lion), NGROUPS is 16. But libc and kernel
1107  * accept more larger value.
1108  * So we don't trunk NGROUPS anymore.
1109  */
1110  while (groups <= RB_MAX_GROUPS) {
1111  gary = ALLOCV_N(GETGROUPS_T, v, groups);
1112  anum = getgroups(groups, gary);
1113  if (anum != -1 && anum != groups)
1114  break;
1115  groups *= 2;
1116  if (v) {
1117  ALLOCV_END(v);
1118  v = 0;
1119  }
1120  }
1121  if (anum == -1)
1122  return FALSE;
1123 
1124  while (--anum >= 0) {
1125  if (gary[anum] == gid) {
1126  rv = TRUE;
1127  break;
1128  }
1129  }
1130  if (v)
1131  ALLOCV_END(v);
1132 
1133  return rv;
1134 #endif
1135 }
1136 
1137 #ifndef S_IXUGO
1138 # define S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH)
1139 #endif
1140 
1141 #if defined(S_IXGRP) && !defined(_WIN32) && !defined(__CYGWIN__)
1142 #define USE_GETEUID 1
1143 #endif
1144 
1145 #ifndef HAVE_EACCESS
1146 int
1147 eaccess(const char *path, int mode)
1148 {
1149 #ifdef USE_GETEUID
1150  struct stat st;
1151  rb_uid_t euid;
1152 
1153  euid = geteuid();
1154 
1155  /* no setuid nor setgid. run shortcut. */
1156  if (getuid() == euid && getgid() == getegid())
1157  return access(path, mode);
1158 
1159  if (STAT(path, &st) < 0)
1160  return -1;
1161 
1162  if (euid == 0) {
1163  /* Root can read or write any file. */
1164  if (!(mode & X_OK))
1165  return 0;
1166 
1167  /* Root can execute any file that has any one of the execute
1168  bits set. */
1169  if (st.st_mode & S_IXUGO)
1170  return 0;
1171 
1172  return -1;
1173  }
1174 
1175  if (st.st_uid == euid) /* owner */
1176  mode <<= 6;
1177  else if (rb_group_member(st.st_gid))
1178  mode <<= 3;
1179 
1180  if ((int)(st.st_mode & mode) == mode) return 0;
1181 
1182  return -1;
1183 #else
1184  return access(path, mode);
1185 #endif
1186 }
1187 #endif
1188 
1189 
1190 /*
1191  * Document-class: FileTest
1192  *
1193  * <code>FileTest</code> implements file test operations similar to
1194  * those used in <code>File::Stat</code>. It exists as a standalone
1195  * module, and its methods are also insinuated into the <code>File</code>
1196  * class. (Note that this is not done by inclusion: the interpreter cheats).
1197  *
1198  */
1199 
1200 /*
1201  * Document-method: directory?
1202  *
1203  * call-seq:
1204  * File.directory?(file_name) -> true or false
1205  *
1206  * Returns <code>true</code> if the named file is a directory,
1207  * or a symlink that points at a directory, and <code>false</code>
1208  * otherwise.
1209  *
1210  * _file_name_ can be an IO object.
1211  *
1212  * File.directory?(".")
1213  */
1214 
1215 VALUE
1217 {
1218 #ifndef S_ISDIR
1219 # define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
1220 #endif
1221 
1222  struct stat st;
1223 
1224  if (rb_stat(fname, &st) < 0) return Qfalse;
1225  if (S_ISDIR(st.st_mode)) return Qtrue;
1226  return Qfalse;
1227 }
1228 
1229 /*
1230  * call-seq:
1231  * File.pipe?(file_name) -> true or false
1232  *
1233  * Returns <code>true</code> if the named file is a pipe.
1234  *
1235  * _file_name_ can be an IO object.
1236  */
1237 
1238 static VALUE
1240 {
1241 #ifdef S_IFIFO
1242 # ifndef S_ISFIFO
1243 # define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
1244 # endif
1245 
1246  struct stat st;
1247 
1248  if (rb_stat(fname, &st) < 0) return Qfalse;
1249  if (S_ISFIFO(st.st_mode)) return Qtrue;
1250 
1251 #endif
1252  return Qfalse;
1253 }
1254 
1255 /*
1256  * call-seq:
1257  * File.symlink?(file_name) -> true or false
1258  *
1259  * Returns <code>true</code> if the named file is a symbolic link.
1260  */
1261 
1262 static VALUE
1264 {
1265 #ifndef S_ISLNK
1266 # ifdef _S_ISLNK
1267 # define S_ISLNK(m) _S_ISLNK(m)
1268 # else
1269 # ifdef _S_IFLNK
1270 # define S_ISLNK(m) (((m) & S_IFMT) == _S_IFLNK)
1271 # else
1272 # ifdef S_IFLNK
1273 # define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
1274 # endif
1275 # endif
1276 # endif
1277 #endif
1278 
1279 #ifdef S_ISLNK
1280  struct stat st;
1281 
1282  rb_secure(2);
1283  FilePathValue(fname);
1284  fname = rb_str_encode_ospath(fname);
1285  if (lstat(StringValueCStr(fname), &st) < 0) return Qfalse;
1286  if (S_ISLNK(st.st_mode)) return Qtrue;
1287 #endif
1288 
1289  return Qfalse;
1290 }
1291 
1292 /*
1293  * call-seq:
1294  * File.socket?(file_name) -> true or false
1295  *
1296  * Returns <code>true</code> if the named file is a socket.
1297  *
1298  * _file_name_ can be an IO object.
1299  */
1300 
1301 static VALUE
1303 {
1304 #ifndef S_ISSOCK
1305 # ifdef _S_ISSOCK
1306 # define S_ISSOCK(m) _S_ISSOCK(m)
1307 # else
1308 # ifdef _S_IFSOCK
1309 # define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
1310 # else
1311 # ifdef S_IFSOCK
1312 # define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
1313 # endif
1314 # endif
1315 # endif
1316 #endif
1317 
1318 #ifdef S_ISSOCK
1319  struct stat st;
1320 
1321  if (rb_stat(fname, &st) < 0) return Qfalse;
1322  if (S_ISSOCK(st.st_mode)) return Qtrue;
1323 
1324 #endif
1325  return Qfalse;
1326 }
1327 
1328 /*
1329  * call-seq:
1330  * File.blockdev?(file_name) -> true or false
1331  *
1332  * Returns <code>true</code> if the named file is a block device.
1333  *
1334  * _file_name_ can be an IO object.
1335  */
1336 
1337 static VALUE
1339 {
1340 #ifndef S_ISBLK
1341 # ifdef S_IFBLK
1342 # define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
1343 # else
1344 # define S_ISBLK(m) (0) /* anytime false */
1345 # endif
1346 #endif
1347 
1348 #ifdef S_ISBLK
1349  struct stat st;
1350 
1351  if (rb_stat(fname, &st) < 0) return Qfalse;
1352  if (S_ISBLK(st.st_mode)) return Qtrue;
1353 
1354 #endif
1355  return Qfalse;
1356 }
1357 
1358 /*
1359  * call-seq:
1360  * File.chardev?(file_name) -> true or false
1361  *
1362  * Returns <code>true</code> if the named file is a character device.
1363  *
1364  * _file_name_ can be an IO object.
1365  */
1366 static VALUE
1368 {
1369 #ifndef S_ISCHR
1370 # define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
1371 #endif
1372 
1373  struct stat st;
1374 
1375  if (rb_stat(fname, &st) < 0) return Qfalse;
1376  if (S_ISCHR(st.st_mode)) return Qtrue;
1377 
1378  return Qfalse;
1379 }
1380 
1381 /*
1382  * call-seq:
1383  * File.exist?(file_name) -> true or false
1384  * File.exists?(file_name) -> true or false
1385  *
1386  * Return <code>true</code> if the named file exists.
1387  *
1388  * _file_name_ can be an IO object.
1389  *
1390  * "file exists" means that stat() or fstat() system call is successful.
1391  */
1392 
1393 static VALUE
1395 {
1396  struct stat st;
1397 
1398  if (rb_stat(fname, &st) < 0) return Qfalse;
1399  return Qtrue;
1400 }
1401 
1402 static VALUE
1404 {
1405  const char *s = "FileTest#";
1406  if (obj == rb_mFileTest) {
1407  s = "FileTest.";
1408  }
1409  else if (obj == rb_cFile ||
1410  (RB_TYPE_P(obj, T_CLASS) &&
1412  s = "File.";
1413  }
1414  rb_warning("%sexists? is a deprecated name, use %sexist? instead", s, s);
1415  return rb_file_exist_p(obj, fname);
1416 }
1417 
1418 /*
1419  * call-seq:
1420  * File.readable?(file_name) -> true or false
1421  *
1422  * Returns <code>true</code> if the named file is readable by the effective
1423  * user id of this process.
1424  */
1425 
1426 static VALUE
1428 {
1429  rb_secure(2);
1430  FilePathValue(fname);
1431  fname = rb_str_encode_ospath(fname);
1432  if (eaccess(StringValueCStr(fname), R_OK) < 0) return Qfalse;
1433  return Qtrue;
1434 }
1435 
1436 /*
1437  * call-seq:
1438  * File.readable_real?(file_name) -> true or false
1439  *
1440  * Returns <code>true</code> if the named file is readable by the real
1441  * user id of this process.
1442  */
1443 
1444 static VALUE
1446 {
1447  rb_secure(2);
1448  FilePathValue(fname);
1449  fname = rb_str_encode_ospath(fname);
1450  if (access(StringValueCStr(fname), R_OK) < 0) return Qfalse;
1451  return Qtrue;
1452 }
1453 
1454 #ifndef S_IRUGO
1455 # define S_IRUGO (S_IRUSR | S_IRGRP | S_IROTH)
1456 #endif
1457 
1458 #ifndef S_IWUGO
1459 # define S_IWUGO (S_IWUSR | S_IWGRP | S_IWOTH)
1460 #endif
1461 
1462 /*
1463  * call-seq:
1464  * File.world_readable?(file_name) -> fixnum or nil
1465  *
1466  * If <i>file_name</i> is readable by others, returns an integer
1467  * representing the file permission bits of <i>file_name</i>. Returns
1468  * <code>nil</code> otherwise. The meaning of the bits is platform
1469  * dependent; on Unix systems, see <code>stat(2)</code>.
1470  *
1471  * _file_name_ can be an IO object.
1472  *
1473  * File.world_readable?("/etc/passwd") #=> 420
1474  * m = File.world_readable?("/etc/passwd")
1475  * sprintf("%o", m) #=> "644"
1476  */
1477 
1478 static VALUE
1480 {
1481 #ifdef S_IROTH
1482  struct stat st;
1483 
1484  if (rb_stat(fname, &st) < 0) return Qnil;
1485  if ((st.st_mode & (S_IROTH)) == S_IROTH) {
1486  return UINT2NUM(st.st_mode & (S_IRUGO|S_IWUGO|S_IXUGO));
1487  }
1488 #endif
1489  return Qnil;
1490 }
1491 
1492 /*
1493  * call-seq:
1494  * File.writable?(file_name) -> true or false
1495  *
1496  * Returns <code>true</code> if the named file is writable by the effective
1497  * user id of this process.
1498  */
1499 
1500 static VALUE
1502 {
1503  rb_secure(2);
1504  FilePathValue(fname);
1505  fname = rb_str_encode_ospath(fname);
1506  if (eaccess(StringValueCStr(fname), W_OK) < 0) return Qfalse;
1507  return Qtrue;
1508 }
1509 
1510 /*
1511  * call-seq:
1512  * File.writable_real?(file_name) -> true or false
1513  *
1514  * Returns <code>true</code> if the named file is writable by the real
1515  * user id of this process.
1516  */
1517 
1518 static VALUE
1520 {
1521  rb_secure(2);
1522  FilePathValue(fname);
1523  fname = rb_str_encode_ospath(fname);
1524  if (access(StringValueCStr(fname), W_OK) < 0) return Qfalse;
1525  return Qtrue;
1526 }
1527 
1528 /*
1529  * call-seq:
1530  * File.world_writable?(file_name) -> fixnum or nil
1531  *
1532  * If <i>file_name</i> is writable by others, returns an integer
1533  * representing the file permission bits of <i>file_name</i>. Returns
1534  * <code>nil</code> otherwise. The meaning of the bits is platform
1535  * dependent; on Unix systems, see <code>stat(2)</code>.
1536  *
1537  * _file_name_ can be an IO object.
1538  *
1539  * File.world_writable?("/tmp") #=> 511
1540  * m = File.world_writable?("/tmp")
1541  * sprintf("%o", m) #=> "777"
1542  */
1543 
1544 static VALUE
1546 {
1547 #ifdef S_IWOTH
1548  struct stat st;
1549 
1550  if (rb_stat(fname, &st) < 0) return Qnil;
1551  if ((st.st_mode & (S_IWOTH)) == S_IWOTH) {
1552  return UINT2NUM(st.st_mode & (S_IRUGO|S_IWUGO|S_IXUGO));
1553  }
1554 #endif
1555  return Qnil;
1556 }
1557 
1558 /*
1559  * call-seq:
1560  * File.executable?(file_name) -> true or false
1561  *
1562  * Returns <code>true</code> if the named file is executable by the effective
1563  * user id of this process.
1564  */
1565 
1566 static VALUE
1568 {
1569  rb_secure(2);
1570  FilePathValue(fname);
1571  fname = rb_str_encode_ospath(fname);
1572  if (eaccess(StringValueCStr(fname), X_OK) < 0) return Qfalse;
1573  return Qtrue;
1574 }
1575 
1576 /*
1577  * call-seq:
1578  * File.executable_real?(file_name) -> true or false
1579  *
1580  * Returns <code>true</code> if the named file is executable by the real
1581  * user id of this process.
1582  */
1583 
1584 static VALUE
1586 {
1587  rb_secure(2);
1588  FilePathValue(fname);
1589  fname = rb_str_encode_ospath(fname);
1590  if (access(StringValueCStr(fname), X_OK) < 0) return Qfalse;
1591  return Qtrue;
1592 }
1593 
1594 #ifndef S_ISREG
1595 # define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1596 #endif
1597 
1598 /*
1599  * call-seq:
1600  * File.file?(file_name) -> true or false
1601  *
1602  * Returns <code>true</code> if the named file exists and is a
1603  * regular file.
1604  *
1605  * _file_name_ can be an IO object.
1606  */
1607 
1608 static VALUE
1610 {
1611  struct stat st;
1612 
1613  if (rb_stat(fname, &st) < 0) return Qfalse;
1614  if (S_ISREG(st.st_mode)) return Qtrue;
1615  return Qfalse;
1616 }
1617 
1618 /*
1619  * call-seq:
1620  * File.zero?(file_name) -> true or false
1621  *
1622  * Returns <code>true</code> if the named file exists and has
1623  * a zero size.
1624  *
1625  * _file_name_ can be an IO object.
1626  */
1627 
1628 static VALUE
1630 {
1631  struct stat st;
1632 
1633  if (rb_stat(fname, &st) < 0) return Qfalse;
1634  if (st.st_size == 0) return Qtrue;
1635  return Qfalse;
1636 }
1637 
1638 /*
1639  * call-seq:
1640  * File.size?(file_name) -> Integer or nil
1641  *
1642  * Returns +nil+ if +file_name+ doesn't exist or has zero size, the size of the
1643  * file otherwise.
1644  *
1645  * _file_name_ can be an IO object.
1646  */
1647 
1648 static VALUE
1650 {
1651  struct stat st;
1652 
1653  if (rb_stat(fname, &st) < 0) return Qnil;
1654  if (st.st_size == 0) return Qnil;
1655  return OFFT2NUM(st.st_size);
1656 }
1657 
1658 /*
1659  * call-seq:
1660  * File.owned?(file_name) -> true or false
1661  *
1662  * Returns <code>true</code> if the named file exists and the
1663  * effective used id of the calling process is the owner of
1664  * the file.
1665  *
1666  * _file_name_ can be an IO object.
1667  */
1668 
1669 static VALUE
1671 {
1672  struct stat st;
1673 
1674  if (rb_stat(fname, &st) < 0) return Qfalse;
1675  if (st.st_uid == geteuid()) return Qtrue;
1676  return Qfalse;
1677 }
1678 
1679 static VALUE
1681 {
1682  struct stat st;
1683 
1684  if (rb_stat(fname, &st) < 0) return Qfalse;
1685  if (st.st_uid == getuid()) return Qtrue;
1686  return Qfalse;
1687 }
1688 
1689 /*
1690  * call-seq:
1691  * File.grpowned?(file_name) -> true or false
1692  *
1693  * Returns <code>true</code> if the named file exists and the
1694  * effective group id of the calling process is the owner of
1695  * the file. Returns <code>false</code> on Windows.
1696  *
1697  * _file_name_ can be an IO object.
1698  */
1699 
1700 static VALUE
1702 {
1703 #ifndef _WIN32
1704  struct stat st;
1705 
1706  if (rb_stat(fname, &st) < 0) return Qfalse;
1707  if (rb_group_member(st.st_gid)) return Qtrue;
1708 #endif
1709  return Qfalse;
1710 }
1711 
1712 #if defined(S_ISUID) || defined(S_ISGID) || defined(S_ISVTX)
1713 static VALUE
1714 check3rdbyte(VALUE fname, int mode)
1715 {
1716  struct stat st;
1717 
1718  rb_secure(2);
1719  FilePathValue(fname);
1720  fname = rb_str_encode_ospath(fname);
1721  if (STAT(StringValueCStr(fname), &st) < 0) return Qfalse;
1722  if (st.st_mode & mode) return Qtrue;
1723  return Qfalse;
1724 }
1725 #endif
1726 
1727 /*
1728  * call-seq:
1729  * File.setuid?(file_name) -> true or false
1730  *
1731  * Returns <code>true</code> if the named file has the setuid bit set.
1732  */
1733 
1734 static VALUE
1736 {
1737 #ifdef S_ISUID
1738  return check3rdbyte(fname, S_ISUID);
1739 #else
1740  return Qfalse;
1741 #endif
1742 }
1743 
1744 /*
1745  * call-seq:
1746  * File.setgid?(file_name) -> true or false
1747  *
1748  * Returns <code>true</code> if the named file has the setgid bit set.
1749  */
1750 
1751 static VALUE
1753 {
1754 #ifdef S_ISGID
1755  return check3rdbyte(fname, S_ISGID);
1756 #else
1757  return Qfalse;
1758 #endif
1759 }
1760 
1761 /*
1762  * call-seq:
1763  * File.sticky?(file_name) -> true or false
1764  *
1765  * Returns <code>true</code> if the named file has the sticky bit set.
1766  */
1767 
1768 static VALUE
1770 {
1771 #ifdef S_ISVTX
1772  return check3rdbyte(fname, S_ISVTX);
1773 #else
1774  return Qnil;
1775 #endif
1776 }
1777 
1778 /*
1779  * call-seq:
1780  * File.identical?(file_1, file_2) -> true or false
1781  *
1782  * Returns <code>true</code> if the named files are identical.
1783  *
1784  * _file_1_ and _file_2_ can be an IO object.
1785  *
1786  * open("a", "w") {}
1787  * p File.identical?("a", "a") #=> true
1788  * p File.identical?("a", "./a") #=> true
1789  * File.link("a", "b")
1790  * p File.identical?("a", "b") #=> true
1791  * File.symlink("a", "c")
1792  * p File.identical?("a", "c") #=> true
1793  * open("d", "w") {}
1794  * p File.identical?("a", "d") #=> false
1795  */
1796 
1797 static VALUE
1798 rb_file_identical_p(VALUE obj, VALUE fname1, VALUE fname2)
1799 {
1800 #ifndef DOSISH
1801  struct stat st1, st2;
1802 
1803  if (rb_stat(fname1, &st1) < 0) return Qfalse;
1804  if (rb_stat(fname2, &st2) < 0) return Qfalse;
1805  if (st1.st_dev != st2.st_dev) return Qfalse;
1806  if (st1.st_ino != st2.st_ino) return Qfalse;
1807 #else
1808 # ifdef _WIN32
1809  BY_HANDLE_FILE_INFORMATION st1, st2;
1810  HANDLE f1 = 0, f2 = 0;
1811 # endif
1812 
1813  rb_secure(2);
1814 # ifdef _WIN32
1815  f1 = w32_io_info(&fname1, &st1);
1816  if (f1 == INVALID_HANDLE_VALUE) return Qfalse;
1817  f2 = w32_io_info(&fname2, &st2);
1818  if (f1) CloseHandle(f1);
1819  if (f2 == INVALID_HANDLE_VALUE) return Qfalse;
1820  if (f2) CloseHandle(f2);
1821 
1822  if (st1.dwVolumeSerialNumber == st2.dwVolumeSerialNumber &&
1823  st1.nFileIndexHigh == st2.nFileIndexHigh &&
1824  st1.nFileIndexLow == st2.nFileIndexLow)
1825  return Qtrue;
1826  if (!f1 || !f2) return Qfalse;
1827 # else
1828  FilePathValue(fname1);
1829  fname1 = rb_str_new4(fname1);
1830  fname1 = rb_str_encode_ospath(fname1);
1831  FilePathValue(fname2);
1832  fname2 = rb_str_encode_ospath(fname2);
1833  if (access(RSTRING_PTR(fname1), 0)) return Qfalse;
1834  if (access(RSTRING_PTR(fname2), 0)) return Qfalse;
1835 # endif
1836  fname1 = rb_file_expand_path(fname1, Qnil);
1837  fname2 = rb_file_expand_path(fname2, Qnil);
1838  if (RSTRING_LEN(fname1) != RSTRING_LEN(fname2)) return Qfalse;
1839  if (rb_memcicmp(RSTRING_PTR(fname1), RSTRING_PTR(fname2), RSTRING_LEN(fname1)))
1840  return Qfalse;
1841 #endif
1842  return Qtrue;
1843 }
1844 
1845 /*
1846  * call-seq:
1847  * File.size(file_name) -> integer
1848  *
1849  * Returns the size of <code>file_name</code>.
1850  *
1851  * _file_name_ can be an IO object.
1852  */
1853 
1854 static VALUE
1856 {
1857  struct stat st;
1858 
1859  if (rb_stat(fname, &st) < 0) {
1860  FilePathValue(fname);
1861  rb_sys_fail_path(fname);
1862  }
1863  return OFFT2NUM(st.st_size);
1864 }
1865 
1866 static VALUE
1867 rb_file_ftype(const struct stat *st)
1868 {
1869  const char *t;
1870 
1871  if (S_ISREG(st->st_mode)) {
1872  t = "file";
1873  }
1874  else if (S_ISDIR(st->st_mode)) {
1875  t = "directory";
1876  }
1877  else if (S_ISCHR(st->st_mode)) {
1878  t = "characterSpecial";
1879  }
1880 #ifdef S_ISBLK
1881  else if (S_ISBLK(st->st_mode)) {
1882  t = "blockSpecial";
1883  }
1884 #endif
1885 #ifdef S_ISFIFO
1886  else if (S_ISFIFO(st->st_mode)) {
1887  t = "fifo";
1888  }
1889 #endif
1890 #ifdef S_ISLNK
1891  else if (S_ISLNK(st->st_mode)) {
1892  t = "link";
1893  }
1894 #endif
1895 #ifdef S_ISSOCK
1896  else if (S_ISSOCK(st->st_mode)) {
1897  t = "socket";
1898  }
1899 #endif
1900  else {
1901  t = "unknown";
1902  }
1903 
1904  return rb_usascii_str_new2(t);
1905 }
1906 
1907 /*
1908  * call-seq:
1909  * File.ftype(file_name) -> string
1910  *
1911  * Identifies the type of the named file; the return string is one of
1912  * ``<code>file</code>'', ``<code>directory</code>'',
1913  * ``<code>characterSpecial</code>'', ``<code>blockSpecial</code>'',
1914  * ``<code>fifo</code>'', ``<code>link</code>'',
1915  * ``<code>socket</code>'', or ``<code>unknown</code>''.
1916  *
1917  * File.ftype("testfile") #=> "file"
1918  * File.ftype("/dev/tty") #=> "characterSpecial"
1919  * File.ftype("/tmp/.X11-unix/X0") #=> "socket"
1920  */
1921 
1922 static VALUE
1924 {
1925  struct stat st;
1926 
1927  rb_secure(2);
1928  FilePathValue(fname);
1929  fname = rb_str_encode_ospath(fname);
1930  if (lstat(StringValueCStr(fname), &st) == -1) {
1931  rb_sys_fail_path(fname);
1932  }
1933 
1934  return rb_file_ftype(&st);
1935 }
1936 
1937 /*
1938  * call-seq:
1939  * File.atime(file_name) -> time
1940  *
1941  * Returns the last access time for the named file as a Time object).
1942  *
1943  * _file_name_ can be an IO object.
1944  *
1945  * File.atime("testfile") #=> Wed Apr 09 08:51:48 CDT 2003
1946  *
1947  */
1948 
1949 static VALUE
1951 {
1952  struct stat st;
1953 
1954  if (rb_stat(fname, &st) < 0) {
1955  FilePathValue(fname);
1956  rb_sys_fail_path(fname);
1957  }
1958  return stat_atime(&st);
1959 }
1960 
1961 /*
1962  * call-seq:
1963  * file.atime -> time
1964  *
1965  * Returns the last access time (a <code>Time</code> object)
1966  * for <i>file</i>, or epoch if <i>file</i> has not been accessed.
1967  *
1968  * File.new("testfile").atime #=> Wed Dec 31 18:00:00 CST 1969
1969  *
1970  */
1971 
1972 static VALUE
1974 {
1975  rb_io_t *fptr;
1976  struct stat st;
1977 
1978  GetOpenFile(obj, fptr);
1979  if (fstat(fptr->fd, &st) == -1) {
1980  rb_sys_fail_path(fptr->pathv);
1981  }
1982  return stat_atime(&st);
1983 }
1984 
1985 /*
1986  * call-seq:
1987  * File.mtime(file_name) -> time
1988  *
1989  * Returns the modification time for the named file as a Time object.
1990  *
1991  * _file_name_ can be an IO object.
1992  *
1993  * File.mtime("testfile") #=> Tue Apr 08 12:58:04 CDT 2003
1994  *
1995  */
1996 
1997 static VALUE
1999 {
2000  struct stat st;
2001 
2002  if (rb_stat(fname, &st) < 0) {
2003  FilePathValue(fname);
2004  rb_sys_fail_path(fname);
2005  }
2006  return stat_mtime(&st);
2007 }
2008 
2009 /*
2010  * call-seq:
2011  * file.mtime -> time
2012  *
2013  * Returns the modification time for <i>file</i>.
2014  *
2015  * File.new("testfile").mtime #=> Wed Apr 09 08:53:14 CDT 2003
2016  *
2017  */
2018 
2019 static VALUE
2021 {
2022  rb_io_t *fptr;
2023  struct stat st;
2024 
2025  GetOpenFile(obj, fptr);
2026  if (fstat(fptr->fd, &st) == -1) {
2027  rb_sys_fail_path(fptr->pathv);
2028  }
2029  return stat_mtime(&st);
2030 }
2031 
2032 /*
2033  * call-seq:
2034  * File.ctime(file_name) -> time
2035  *
2036  * Returns the change time for the named file (the time at which
2037  * directory information about the file was changed, not the file
2038  * itself).
2039  *
2040  * _file_name_ can be an IO object.
2041  *
2042  * Note that on Windows (NTFS), returns creation time (birth time).
2043  *
2044  * File.ctime("testfile") #=> Wed Apr 09 08:53:13 CDT 2003
2045  *
2046  */
2047 
2048 static VALUE
2050 {
2051  struct stat st;
2052 
2053  if (rb_stat(fname, &st) < 0) {
2054  FilePathValue(fname);
2055  rb_sys_fail_path(fname);
2056  }
2057  return stat_ctime(&st);
2058 }
2059 
2060 /*
2061  * call-seq:
2062  * file.ctime -> time
2063  *
2064  * Returns the change time for <i>file</i> (that is, the time directory
2065  * information about the file was changed, not the file itself).
2066  *
2067  * Note that on Windows (NTFS), returns creation time (birth time).
2068  *
2069  * File.new("testfile").ctime #=> Wed Apr 09 08:53:14 CDT 2003
2070  *
2071  */
2072 
2073 static VALUE
2075 {
2076  rb_io_t *fptr;
2077  struct stat st;
2078 
2079  GetOpenFile(obj, fptr);
2080  if (fstat(fptr->fd, &st) == -1) {
2081  rb_sys_fail_path(fptr->pathv);
2082  }
2083  return stat_ctime(&st);
2084 }
2085 
2086 /*
2087  * call-seq:
2088  * file.size -> integer
2089  *
2090  * Returns the size of <i>file</i> in bytes.
2091  *
2092  * File.new("testfile").size #=> 66
2093  *
2094  */
2095 
2096 static VALUE
2098 {
2099  rb_io_t *fptr;
2100  struct stat st;
2101 
2102  GetOpenFile(obj, fptr);
2103  if (fptr->mode & FMODE_WRITABLE) {
2104  rb_io_flush_raw(obj, 0);
2105  }
2106  if (fstat(fptr->fd, &st) == -1) {
2107  rb_sys_fail_path(fptr->pathv);
2108  }
2109  return OFFT2NUM(st.st_size);
2110 }
2111 
2112 static void
2113 chmod_internal(const char *path, VALUE pathv, void *mode)
2114 {
2115  if (chmod(path, *(int *)mode) < 0)
2116  rb_sys_fail_path(pathv);
2117 }
2118 
2119 /*
2120  * call-seq:
2121  * File.chmod(mode_int, file_name, ... ) -> integer
2122  *
2123  * Changes permission bits on the named file(s) to the bit pattern
2124  * represented by <i>mode_int</i>. Actual effects are operating system
2125  * dependent (see the beginning of this section). On Unix systems, see
2126  * <code>chmod(2)</code> for details. Returns the number of files
2127  * processed.
2128  *
2129  * File.chmod(0644, "testfile", "out") #=> 2
2130  */
2131 
2132 static VALUE
2134 {
2135  VALUE vmode;
2136  VALUE rest;
2137  int mode;
2138  long n;
2139 
2140  rb_secure(2);
2141  rb_scan_args(argc, argv, "1*", &vmode, &rest);
2142  mode = NUM2INT(vmode);
2143 
2144  n = apply2files(chmod_internal, rest, &mode);
2145  return LONG2FIX(n);
2146 }
2147 
2148 /*
2149  * call-seq:
2150  * file.chmod(mode_int) -> 0
2151  *
2152  * Changes permission bits on <i>file</i> to the bit pattern
2153  * represented by <i>mode_int</i>. Actual effects are platform
2154  * dependent; on Unix systems, see <code>chmod(2)</code> for details.
2155  * Follows symbolic links. Also see <code>File#lchmod</code>.
2156  *
2157  * f = File.new("out", "w");
2158  * f.chmod(0644) #=> 0
2159  */
2160 
2161 static VALUE
2163 {
2164  rb_io_t *fptr;
2165  int mode;
2166 #ifndef HAVE_FCHMOD
2167  VALUE path;
2168 #endif
2169 
2170  rb_secure(2);
2171  mode = NUM2INT(vmode);
2172 
2173  GetOpenFile(obj, fptr);
2174 #ifdef HAVE_FCHMOD
2175  if (fchmod(fptr->fd, mode) == -1)
2176  rb_sys_fail_path(fptr->pathv);
2177 #else
2178  if (NIL_P(fptr->pathv)) return Qnil;
2179  path = rb_str_encode_ospath(fptr->pathv);
2180  if (chmod(RSTRING_PTR(path), mode) == -1)
2181  rb_sys_fail_path(fptr->pathv);
2182 #endif
2183 
2184  return INT2FIX(0);
2185 }
2186 
2187 #if defined(HAVE_LCHMOD)
2188 static void
2189 lchmod_internal(const char *path, VALUE pathv, void *mode)
2190 {
2191  if (lchmod(path, (int)(VALUE)mode) < 0)
2192  rb_sys_fail_path(pathv);
2193 }
2194 
2195 /*
2196  * call-seq:
2197  * File.lchmod(mode_int, file_name, ...) -> integer
2198  *
2199  * Equivalent to <code>File::chmod</code>, but does not follow symbolic
2200  * links (so it will change the permissions associated with the link,
2201  * not the file referenced by the link). Often not available.
2202  *
2203  */
2204 
2205 static VALUE
2207 {
2208  VALUE vmode;
2209  VALUE rest;
2210  long mode, n;
2211 
2212  rb_secure(2);
2213  rb_scan_args(argc, argv, "1*", &vmode, &rest);
2214  mode = NUM2INT(vmode);
2215 
2216  n = apply2files(lchmod_internal, rest, (void *)(long)mode);
2217  return LONG2FIX(n);
2218 }
2219 #else
2220 #define rb_file_s_lchmod rb_f_notimplement
2221 #endif
2222 
2223 struct chown_args {
2224  rb_uid_t owner;
2225  rb_gid_t group;
2226 };
2227 
2228 static void
2229 chown_internal(const char *path, VALUE pathv, void *arg)
2230 {
2231  struct chown_args *args = arg;
2232  if (chown(path, args->owner, args->group) < 0)
2233  rb_sys_fail_path(pathv);
2234 }
2235 
2236 /*
2237  * call-seq:
2238  * File.chown(owner_int, group_int, file_name,... ) -> integer
2239  *
2240  * Changes the owner and group of the named file(s) to the given
2241  * numeric owner and group id's. Only a process with superuser
2242  * privileges may change the owner of a file. The current owner of a
2243  * file may change the file's group to any group to which the owner
2244  * belongs. A <code>nil</code> or -1 owner or group id is ignored.
2245  * Returns the number of files processed.
2246  *
2247  * File.chown(nil, 100, "testfile")
2248  *
2249  */
2250 
2251 static VALUE
2253 {
2254  VALUE o, g, rest;
2255  struct chown_args arg;
2256  long n;
2257 
2258  rb_secure(2);
2259  rb_scan_args(argc, argv, "2*", &o, &g, &rest);
2260  if (NIL_P(o)) {
2261  arg.owner = -1;
2262  }
2263  else {
2264  arg.owner = NUM2UIDT(o);
2265  }
2266  if (NIL_P(g)) {
2267  arg.group = -1;
2268  }
2269  else {
2270  arg.group = NUM2GIDT(g);
2271  }
2272 
2273  n = apply2files(chown_internal, rest, &arg);
2274  return LONG2FIX(n);
2275 }
2276 
2277 /*
2278  * call-seq:
2279  * file.chown(owner_int, group_int ) -> 0
2280  *
2281  * Changes the owner and group of <i>file</i> to the given numeric
2282  * owner and group id's. Only a process with superuser privileges may
2283  * change the owner of a file. The current owner of a file may change
2284  * the file's group to any group to which the owner belongs. A
2285  * <code>nil</code> or -1 owner or group id is ignored. Follows
2286  * symbolic links. See also <code>File#lchown</code>.
2287  *
2288  * File.new("testfile").chown(502, 1000)
2289  *
2290  */
2291 
2292 static VALUE
2294 {
2295  rb_io_t *fptr;
2296  int o, g;
2297 #ifndef HAVE_FCHOWN
2298  VALUE path;
2299 #endif
2300 
2301  rb_secure(2);
2302  o = NIL_P(owner) ? -1 : NUM2INT(owner);
2303  g = NIL_P(group) ? -1 : NUM2INT(group);
2304  GetOpenFile(obj, fptr);
2305 #ifndef HAVE_FCHOWN
2306  if (NIL_P(fptr->pathv)) return Qnil;
2307  path = rb_str_encode_ospath(fptr->pathv);
2308  if (chown(RSTRING_PTR(path), o, g) == -1)
2309  rb_sys_fail_path(fptr->pathv);
2310 #else
2311  if (fchown(fptr->fd, o, g) == -1)
2312  rb_sys_fail_path(fptr->pathv);
2313 #endif
2314 
2315  return INT2FIX(0);
2316 }
2317 
2318 #if defined(HAVE_LCHOWN)
2319 static void
2320 lchown_internal(const char *path, VALUE pathv, void *arg)
2321 {
2322  struct chown_args *args = arg;
2323  if (lchown(path, args->owner, args->group) < 0)
2324  rb_sys_fail_path(pathv);
2325 }
2326 
2327 /*
2328  * call-seq:
2329  * File.lchown(owner_int, group_int, file_name,..) -> integer
2330  *
2331  * Equivalent to <code>File::chown</code>, but does not follow symbolic
2332  * links (so it will change the owner associated with the link, not the
2333  * file referenced by the link). Often not available. Returns number
2334  * of files in the argument list.
2335  *
2336  */
2337 
2338 static VALUE
2340 {
2341  VALUE o, g, rest;
2342  struct chown_args arg;
2343  long n;
2344 
2345  rb_secure(2);
2346  rb_scan_args(argc, argv, "2*", &o, &g, &rest);
2347  if (NIL_P(o)) {
2348  arg.owner = -1;
2349  }
2350  else {
2351  arg.owner = NUM2UIDT(o);
2352  }
2353  if (NIL_P(g)) {
2354  arg.group = -1;
2355  }
2356  else {
2357  arg.group = NUM2GIDT(g);
2358  }
2359 
2360  n = apply2files(lchown_internal, rest, &arg);
2361  return LONG2FIX(n);
2362 }
2363 #else
2364 #define rb_file_s_lchown rb_f_notimplement
2365 #endif
2366 
2367 struct utime_args {
2368  const struct timespec* tsp;
2370 };
2371 
2372 #if defined DOSISH || defined __CYGWIN__
2373 NORETURN(static void utime_failed(VALUE, const struct timespec *, VALUE, VALUE));
2374 
2375 static void
2376 utime_failed(VALUE path, const struct timespec *tsp, VALUE atime, VALUE mtime)
2377 {
2378  if (tsp && errno == EINVAL) {
2379  VALUE e[2], a = Qnil, m = Qnil;
2380  int d = 0;
2381  if (!NIL_P(atime)) {
2382  a = rb_inspect(atime);
2383  }
2384  if (!NIL_P(mtime) && mtime != atime && !rb_equal(atime, mtime)) {
2385  m = rb_inspect(mtime);
2386  }
2387  if (NIL_P(a)) e[0] = m;
2388  else if (NIL_P(m) || rb_str_cmp(a, m) == 0) e[0] = a;
2389  else {
2390  e[0] = rb_str_plus(a, rb_str_new_cstr(" or "));
2391  rb_str_append(e[0], m);
2392  d = 1;
2393  }
2394  if (!NIL_P(e[0])) {
2395  if (path) {
2396  if (!d) e[0] = rb_str_dup(e[0]);
2397  rb_str_append(rb_str_cat2(e[0], " for "), path);
2398  }
2399  e[1] = INT2FIX(EINVAL);
2401  }
2402  errno = EINVAL;
2403  }
2404  rb_sys_fail_path(path);
2405 }
2406 #else
2407 #define utime_failed(path, tsp, atime, mtime) rb_sys_fail_path(path)
2408 #endif
2409 
2410 #if defined(HAVE_UTIMES)
2411 
2412 static void
2413 utime_internal(const char *path, VALUE pathv, void *arg)
2414 {
2415  struct utime_args *v = arg;
2416  const struct timespec *tsp = v->tsp;
2417  struct timeval tvbuf[2], *tvp = NULL;
2418 
2419 #ifdef HAVE_UTIMENSAT
2420  static int try_utimensat = 1;
2421 
2422  if (try_utimensat) {
2423  if (utimensat(AT_FDCWD, path, tsp, 0) < 0) {
2424  if (errno == ENOSYS) {
2425  try_utimensat = 0;
2426  goto no_utimensat;
2427  }
2428  utime_failed(pathv, tsp, v->atime, v->mtime);
2429  }
2430  return;
2431  }
2432 no_utimensat:
2433 #endif
2434 
2435  if (tsp) {
2436  tvbuf[0].tv_sec = tsp[0].tv_sec;
2437  tvbuf[0].tv_usec = (int)(tsp[0].tv_nsec / 1000);
2438  tvbuf[1].tv_sec = tsp[1].tv_sec;
2439  tvbuf[1].tv_usec = (int)(tsp[1].tv_nsec / 1000);
2440  tvp = tvbuf;
2441  }
2442  if (utimes(path, tvp) < 0)
2443  utime_failed(pathv, tsp, v->atime, v->mtime);
2444 }
2445 
2446 #else
2447 
2448 #if !defined HAVE_UTIME_H && !defined HAVE_SYS_UTIME_H
2449 struct utimbuf {
2450  long actime;
2451  long modtime;
2452 };
2453 #endif
2454 
2455 static void
2456 utime_internal(const char *path, VALUE pathv, void *arg)
2457 {
2458  struct utime_args *v = arg;
2459  const struct timespec *tsp = v->tsp;
2460  struct utimbuf utbuf, *utp = NULL;
2461  if (tsp) {
2462  utbuf.actime = tsp[0].tv_sec;
2463  utbuf.modtime = tsp[1].tv_sec;
2464  utp = &utbuf;
2465  }
2466  if (utime(path, utp) < 0)
2467  utime_failed(pathv, tsp, v->atime, v->mtime);
2468 }
2469 
2470 #endif
2471 
2472 /*
2473  * call-seq:
2474  * File.utime(atime, mtime, file_name,...) -> integer
2475  *
2476  * Sets the access and modification times of each
2477  * named file to the first two arguments. Returns
2478  * the number of file names in the argument list.
2479  */
2480 
2481 static VALUE
2483 {
2484  VALUE rest;
2485  struct utime_args args;
2486  struct timespec tss[2], *tsp = NULL;
2487  long n;
2488 
2489  rb_secure(2);
2490  rb_scan_args(argc, argv, "2*", &args.atime, &args.mtime, &rest);
2491 
2492  if (!NIL_P(args.atime) || !NIL_P(args.mtime)) {
2493  tsp = tss;
2494  tsp[0] = rb_time_timespec(args.atime);
2495  tsp[1] = rb_time_timespec(args.mtime);
2496  }
2497  args.tsp = tsp;
2498 
2499  n = apply2files(utime_internal, rest, &args);
2500  return LONG2FIX(n);
2501 }
2502 
2503 NORETURN(static void sys_fail2(VALUE,VALUE));
2504 static void
2506 {
2507  VALUE str;
2508 #ifdef MAX_PATH
2509  const int max_pathlen = MAX_PATH;
2510 #else
2511  const int max_pathlen = MAXPATHLEN;
2512 #endif
2513 
2514  str = rb_str_new_cstr("(");
2515  rb_str_append(str, rb_str_ellipsize(s1, max_pathlen));
2516  rb_str_cat2(str, ", ");
2517  rb_str_append(str, rb_str_ellipsize(s2, max_pathlen));
2518  rb_str_cat2(str, ")");
2519  rb_sys_fail_path(str);
2520 }
2521 
2522 #ifdef HAVE_LINK
2523 /*
2524  * call-seq:
2525  * File.link(old_name, new_name) -> 0
2526  *
2527  * Creates a new name for an existing file using a hard link. Will not
2528  * overwrite <i>new_name</i> if it already exists (raising a subclass
2529  * of <code>SystemCallError</code>). Not available on all platforms.
2530  *
2531  * File.link("testfile", ".testfile") #=> 0
2532  * IO.readlines(".testfile")[0] #=> "This is line one\n"
2533  */
2534 
2535 static VALUE
2536 rb_file_s_link(VALUE klass, VALUE from, VALUE to)
2537 {
2538  rb_secure(2);
2539  FilePathValue(from);
2540  FilePathValue(to);
2541  from = rb_str_encode_ospath(from);
2542  to = rb_str_encode_ospath(to);
2543 
2544  if (link(StringValueCStr(from), StringValueCStr(to)) < 0) {
2545  sys_fail2(from, to);
2546  }
2547  return INT2FIX(0);
2548 }
2549 #else
2550 #define rb_file_s_link rb_f_notimplement
2551 #endif
2552 
2553 #ifdef HAVE_SYMLINK
2554 /*
2555  * call-seq:
2556  * File.symlink(old_name, new_name) -> 0
2557  *
2558  * Creates a symbolic link called <i>new_name</i> for the existing file
2559  * <i>old_name</i>. Raises a <code>NotImplemented</code> exception on
2560  * platforms that do not support symbolic links.
2561  *
2562  * File.symlink("testfile", "link2test") #=> 0
2563  *
2564  */
2565 
2566 static VALUE
2567 rb_file_s_symlink(VALUE klass, VALUE from, VALUE to)
2568 {
2569  rb_secure(2);
2570  FilePathValue(from);
2571  FilePathValue(to);
2572  from = rb_str_encode_ospath(from);
2573  to = rb_str_encode_ospath(to);
2574 
2575  if (symlink(StringValueCStr(from), StringValueCStr(to)) < 0) {
2576  sys_fail2(from, to);
2577  }
2578  return INT2FIX(0);
2579 }
2580 #else
2581 #define rb_file_s_symlink rb_f_notimplement
2582 #endif
2583 
2584 #ifdef HAVE_READLINK
2585 static VALUE rb_readlink(VALUE path);
2586 
2587 /*
2588  * call-seq:
2589  * File.readlink(link_name) -> file_name
2590  *
2591  * Returns the name of the file referenced by the given link.
2592  * Not available on all platforms.
2593  *
2594  * File.symlink("testfile", "link2test") #=> 0
2595  * File.readlink("link2test") #=> "testfile"
2596  */
2597 
2598 static VALUE
2599 rb_file_s_readlink(VALUE klass, VALUE path)
2600 {
2601  return rb_readlink(path);
2602 }
2603 
2604 static VALUE
2605 rb_readlink(VALUE path)
2606 {
2607  int size = 100;
2608  ssize_t rv;
2609  VALUE v;
2610 
2611  rb_secure(2);
2612  FilePathValue(path);
2613  path = rb_str_encode_ospath(path);
2615  while ((rv = readlink(RSTRING_PTR(path), RSTRING_PTR(v), size)) == size
2616 #ifdef _AIX
2617  || (rv < 0 && errno == ERANGE) /* quirky behavior of GPFS */
2618 #endif
2619  ) {
2621  size *= 2;
2622  rb_str_set_len(v, size);
2623  }
2624  if (rv < 0) {
2625  rb_str_resize(v, 0);
2626  rb_sys_fail_path(path);
2627  }
2628  rb_str_resize(v, rv);
2629 
2630  return v;
2631 }
2632 #else
2633 #define rb_file_s_readlink rb_f_notimplement
2634 #endif
2635 
2636 static void
2637 unlink_internal(const char *path, VALUE pathv, void *arg)
2638 {
2639  if (unlink(path) < 0)
2640  rb_sys_fail_path(pathv);
2641 }
2642 
2643 /*
2644  * call-seq:
2645  * File.delete(file_name, ...) -> integer
2646  * File.unlink(file_name, ...) -> integer
2647  *
2648  * Deletes the named files, returning the number of names
2649  * passed as arguments. Raises an exception on any error.
2650  * See also <code>Dir::rmdir</code>.
2651  */
2652 
2653 static VALUE
2655 {
2656  long n;
2657 
2658  rb_secure(2);
2659  n = apply2files(unlink_internal, args, 0);
2660  return LONG2FIX(n);
2661 }
2662 
2663 /*
2664  * call-seq:
2665  * File.rename(old_name, new_name) -> 0
2666  *
2667  * Renames the given file to the new name. Raises a
2668  * <code>SystemCallError</code> if the file cannot be renamed.
2669  *
2670  * File.rename("afile", "afile.bak") #=> 0
2671  */
2672 
2673 static VALUE
2675 {
2676  const char *src, *dst;
2677  VALUE f, t;
2678 
2679  rb_secure(2);
2680  FilePathValue(from);
2681  FilePathValue(to);
2682  f = rb_str_encode_ospath(from);
2683  t = rb_str_encode_ospath(to);
2684  src = StringValueCStr(f);
2685  dst = StringValueCStr(t);
2686 #if defined __CYGWIN__
2687  errno = 0;
2688 #endif
2689  if (rename(src, dst) < 0) {
2690 #if defined DOSISH
2691  switch (errno) {
2692  case EEXIST:
2693 #if defined (__EMX__)
2694  case EACCES:
2695 #endif
2696  if (chmod(dst, 0666) == 0 &&
2697  unlink(dst) == 0 &&
2698  rename(src, dst) == 0)
2699  return INT2FIX(0);
2700  }
2701 #endif
2702  sys_fail2(from, to);
2703  }
2704 
2705  return INT2FIX(0);
2706 }
2707 
2708 /*
2709  * call-seq:
2710  * File.umask() -> integer
2711  * File.umask(integer) -> integer
2712  *
2713  * Returns the current umask value for this process. If the optional
2714  * argument is given, set the umask to that value and return the
2715  * previous value. Umask values are <em>subtracted</em> from the
2716  * default permissions, so a umask of <code>0222</code> would make a
2717  * file read-only for everyone.
2718  *
2719  * File.umask(0006) #=> 18
2720  * File.umask #=> 6
2721  */
2722 
2723 static VALUE
2725 {
2726  int omask = 0;
2727 
2728  rb_secure(2);
2729  if (argc == 0) {
2730  omask = umask(0);
2731  umask(omask);
2732  }
2733  else if (argc == 1) {
2734  omask = umask(NUM2INT(argv[0]));
2735  }
2736  else {
2737  rb_check_arity(argc, 0, 1);
2738  }
2739  return INT2FIX(omask);
2740 }
2741 
2742 #ifdef __CYGWIN__
2743 #undef DOSISH
2744 #endif
2745 #if defined __CYGWIN__ || defined DOSISH
2746 #define DOSISH_UNC
2747 #define DOSISH_DRIVE_LETTER
2748 #define FILE_ALT_SEPARATOR '\\'
2749 #endif
2750 #ifdef FILE_ALT_SEPARATOR
2751 #define isdirsep(x) ((x) == '/' || (x) == FILE_ALT_SEPARATOR)
2752 static const char file_alt_separator[] = {FILE_ALT_SEPARATOR, '\0'};
2753 #else
2754 #define isdirsep(x) ((x) == '/')
2755 #endif
2756 
2757 #ifndef USE_NTFS
2758 #if defined _WIN32 || defined __CYGWIN__
2759 #define USE_NTFS 1
2760 #else
2761 #define USE_NTFS 0
2762 #endif
2763 #endif
2764 
2765 #if USE_NTFS
2766 #define istrailinggarbage(x) ((x) == '.' || (x) == ' ')
2767 #else
2768 #define istrailinggarbage(x) 0
2769 #endif
2770 
2771 #define Next(p, e, enc) ((p) + rb_enc_mbclen((p), (e), (enc)))
2772 #define Inc(p, e, enc) ((p) = Next((p), (e), (enc)))
2773 
2774 #if defined(DOSISH_UNC)
2775 #define has_unc(buf) (isdirsep((buf)[0]) && isdirsep((buf)[1]))
2776 #else
2777 #define has_unc(buf) 0
2778 #endif
2779 
2780 #ifdef DOSISH_DRIVE_LETTER
2781 static inline int
2782 has_drive_letter(const char *buf)
2783 {
2784  if (ISALPHA(buf[0]) && buf[1] == ':') {
2785  return 1;
2786  }
2787  else {
2788  return 0;
2789  }
2790 }
2791 
2792 #ifndef _WIN32
2793 static char*
2794 getcwdofdrv(int drv)
2795 {
2796  char drive[4];
2797  char *drvcwd, *oldcwd;
2798 
2799  drive[0] = drv;
2800  drive[1] = ':';
2801  drive[2] = '\0';
2802 
2803  /* the only way that I know to get the current directory
2804  of a particular drive is to change chdir() to that drive,
2805  so save the old cwd before chdir()
2806  */
2807  oldcwd = my_getcwd();
2808  if (chdir(drive) == 0) {
2809  drvcwd = my_getcwd();
2810  chdir(oldcwd);
2811  xfree(oldcwd);
2812  }
2813  else {
2814  /* perhaps the drive is not exist. we return only drive letter */
2815  drvcwd = strdup(drive);
2816  }
2817  return drvcwd;
2818 }
2819 #endif
2820 
2821 static inline int
2822 not_same_drive(VALUE path, int drive)
2823 {
2824  const char *p = RSTRING_PTR(path);
2825  if (RSTRING_LEN(path) < 2) return 0;
2826  if (has_drive_letter(p)) {
2827  return TOLOWER(p[0]) != TOLOWER(drive);
2828  }
2829  else {
2830  return has_unc(p);
2831  }
2832 }
2833 #endif
2834 
2835 static inline char *
2836 skiproot(const char *path, const char *end, rb_encoding *enc)
2837 {
2838 #ifdef DOSISH_DRIVE_LETTER
2839  if (path + 2 <= end && has_drive_letter(path)) path += 2;
2840 #endif
2841  while (path < end && isdirsep(*path)) path++;
2842  return (char *)path;
2843 }
2844 
2845 #define nextdirsep rb_enc_path_next
2846 char *
2847 rb_enc_path_next(const char *s, const char *e, rb_encoding *enc)
2848 {
2849  while (s < e && !isdirsep(*s)) {
2850  Inc(s, e, enc);
2851  }
2852  return (char *)s;
2853 }
2854 
2855 #if defined(DOSISH_UNC) || defined(DOSISH_DRIVE_LETTER)
2856 #define skipprefix rb_enc_path_skip_prefix
2857 #else
2858 #define skipprefix(path, end, enc) (path)
2859 #endif
2860 char *
2861 rb_enc_path_skip_prefix(const char *path, const char *end, rb_encoding *enc)
2862 {
2863 #if defined(DOSISH_UNC) || defined(DOSISH_DRIVE_LETTER)
2864 #ifdef DOSISH_UNC
2865  if (path + 2 <= end && isdirsep(path[0]) && isdirsep(path[1])) {
2866  path += 2;
2867  while (path < end && isdirsep(*path)) path++;
2868  if ((path = rb_enc_path_next(path, end, enc)) < end && path[0] && path[1] && !isdirsep(path[1]))
2869  path = rb_enc_path_next(path + 1, end, enc);
2870  return (char *)path;
2871  }
2872 #endif
2873 #ifdef DOSISH_DRIVE_LETTER
2874  if (has_drive_letter(path))
2875  return (char *)(path + 2);
2876 #endif
2877 #endif
2878  return (char *)path;
2879 }
2880 
2881 static inline char *
2882 skipprefixroot(const char *path, const char *end, rb_encoding *enc)
2883 {
2884 #if defined(DOSISH_UNC) || defined(DOSISH_DRIVE_LETTER)
2885  char *p = skipprefix(path, end, enc);
2886  while (isdirsep(*p)) p++;
2887  return p;
2888 #else
2889  return skiproot(path, end, enc);
2890 #endif
2891 }
2892 
2893 #define strrdirsep rb_enc_path_last_separator
2894 char *
2895 rb_enc_path_last_separator(const char *path, const char *end, rb_encoding *enc)
2896 {
2897  char *last = NULL;
2898  while (path < end) {
2899  if (isdirsep(*path)) {
2900  const char *tmp = path++;
2901  while (path < end && isdirsep(*path)) path++;
2902  if (path >= end) break;
2903  last = (char *)tmp;
2904  }
2905  else {
2906  Inc(path, end, enc);
2907  }
2908  }
2909  return last;
2910 }
2911 
2912 static char *
2913 chompdirsep(const char *path, const char *end, rb_encoding *enc)
2914 {
2915  while (path < end) {
2916  if (isdirsep(*path)) {
2917  const char *last = path++;
2918  while (path < end && isdirsep(*path)) path++;
2919  if (path >= end) return (char *)last;
2920  }
2921  else {
2922  Inc(path, end, enc);
2923  }
2924  }
2925  return (char *)path;
2926 }
2927 
2928 char *
2929 rb_enc_path_end(const char *path, const char *end, rb_encoding *enc)
2930 {
2931  if (path < end && isdirsep(*path)) path++;
2932  return chompdirsep(path, end, enc);
2933 }
2934 
2935 #if USE_NTFS
2936 static char *
2937 ntfs_tail(const char *path, const char *end, rb_encoding *enc)
2938 {
2939  while (path < end && *path == '.') path++;
2940  while (path < end && *path != ':') {
2941  if (istrailinggarbage(*path)) {
2942  const char *last = path++;
2943  while (path < end && istrailinggarbage(*path)) path++;
2944  if (path >= end || *path == ':') return (char *)last;
2945  }
2946  else if (isdirsep(*path)) {
2947  const char *last = path++;
2948  while (path < end && isdirsep(*path)) path++;
2949  if (path >= end) return (char *)last;
2950  if (*path == ':') path++;
2951  }
2952  else {
2953  Inc(path, end, enc);
2954  }
2955  }
2956  return (char *)path;
2957 }
2958 #endif
2959 
2960 #define BUFCHECK(cond) do {\
2961  bdiff = p - buf;\
2962  if (cond) {\
2963  do {buflen *= 2;} while (cond);\
2964  rb_str_resize(result, buflen);\
2965  buf = RSTRING_PTR(result);\
2966  p = buf + bdiff;\
2967  pend = buf + buflen;\
2968  }\
2969 } while (0)
2970 
2971 #define BUFINIT() (\
2972  p = buf = RSTRING_PTR(result),\
2973  buflen = RSTRING_LEN(result),\
2974  pend = p + buflen)
2975 
2976 static VALUE
2977 copy_home_path(VALUE result, const char *dir)
2978 {
2979  char *buf;
2980 #if defined DOSISH || defined __CYGWIN__
2981  char *p, *bend;
2982 #endif
2983  long dirlen;
2984  rb_encoding *enc;
2985 
2986  dirlen = strlen(dir);
2987  rb_str_resize(result, dirlen);
2988  memcpy(buf = RSTRING_PTR(result), dir, dirlen);
2989  enc = rb_filesystem_encoding();
2990  rb_enc_associate(result, enc);
2991 #if defined DOSISH || defined __CYGWIN__
2992  for (bend = (p = buf) + dirlen; p < bend; Inc(p, bend, enc)) {
2993  if (*p == '\\') {
2994  *p = '/';
2995  }
2996  }
2997 #endif
2998  return result;
2999 }
3000 
3001 VALUE
3003 {
3004 #ifdef HAVE_PWD_H
3005  struct passwd *pwPtr = getpwnam(RSTRING_PTR(user));
3006  if (!pwPtr) {
3007  endpwent();
3008 #endif
3009  rb_raise(rb_eArgError, "user %"PRIsVALUE" doesn't exist", user);
3010 #ifdef HAVE_PWD_H
3011  }
3012  copy_home_path(result, pwPtr->pw_dir);
3013  endpwent();
3014 #endif
3015  return result;
3016 }
3017 
3018 VALUE
3020 {
3021  const char *dir = getenv("HOME");
3022  if (!dir) {
3023  rb_raise(rb_eArgError, "couldn't find HOME environment -- expanding `~'");
3024  }
3025  return copy_home_path(result, dir);
3026 }
3027 
3028 #ifndef _WIN32
3029 static char *
3030 append_fspath(VALUE result, VALUE fname, char *dir, rb_encoding **enc, rb_encoding *fsenc)
3031 {
3032  char *buf, *cwdp = dir;
3033  VALUE dirname = Qnil;
3034  size_t dirlen = strlen(dir), buflen = rb_str_capacity(result);
3035 
3036  if (*enc != fsenc) {
3037  rb_encoding *direnc = rb_enc_check(fname, dirname = rb_enc_str_new(dir, dirlen, fsenc));
3038  if (direnc != fsenc) {
3039  dirname = rb_str_conv_enc(dirname, fsenc, direnc);
3040  RSTRING_GETMEM(dirname, cwdp, dirlen);
3041  }
3042  *enc = direnc;
3043  }
3044  do {buflen *= 2;} while (dirlen > buflen);
3045  rb_str_resize(result, buflen);
3046  buf = RSTRING_PTR(result);
3047  memcpy(buf, cwdp, dirlen);
3048  xfree(dir);
3049  if (!NIL_P(dirname)) rb_str_resize(dirname, 0);
3050  rb_enc_associate(result, *enc);
3051  return buf + dirlen;
3052 }
3053 
3054 VALUE
3055 rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_name, VALUE result)
3056 {
3057  const char *s, *b, *fend;
3058  char *buf, *p, *pend, *root;
3059  size_t buflen, bdiff;
3060  int tainted;
3061  rb_encoding *enc, *fsenc = rb_filesystem_encoding();
3062 
3063  s = StringValuePtr(fname);
3064  fend = s + RSTRING_LEN(fname);
3065  enc = rb_enc_get(fname);
3066  BUFINIT();
3067  tainted = OBJ_TAINTED(fname);
3068 
3069  if (s[0] == '~' && abs_mode == 0) { /* execute only if NOT absolute_path() */
3070  long userlen = 0;
3071  tainted = 1;
3072  if (isdirsep(s[1]) || s[1] == '\0') {
3073  buf = 0;
3074  b = 0;
3075  rb_str_set_len(result, 0);
3076  if (*++s) ++s;
3078  }
3079  else {
3080  s = nextdirsep(b = s, fend, enc);
3081  b++; /* b[0] is '~' */
3082  userlen = s - b;
3083  BUFCHECK(bdiff + userlen >= buflen);
3084  memcpy(p, b, userlen);
3086  rb_str_set_len(result, userlen);
3087  rb_enc_associate(result, enc);
3089  buf = p + 1;
3090  p += userlen;
3091  }
3093  if (userlen) {
3094  rb_enc_raise(enc, rb_eArgError, "non-absolute home of %.*s%.0"PRIsVALUE,
3095  (int)userlen, b, fname);
3096  }
3097  else {
3098  rb_raise(rb_eArgError, "non-absolute home");
3099  }
3100  }
3101  BUFINIT();
3102  p = pend;
3103  }
3104 #ifdef DOSISH_DRIVE_LETTER
3105  /* skip drive letter */
3106  else if (has_drive_letter(s)) {
3107  if (isdirsep(s[2])) {
3108  /* specified drive letter, and full path */
3109  /* skip drive letter */
3110  BUFCHECK(bdiff + 2 >= buflen);
3111  memcpy(p, s, 2);
3112  p += 2;
3113  s += 2;
3114  rb_enc_copy(result, fname);
3115  }
3116  else {
3117  /* specified drive, but not full path */
3118  int same = 0;
3119  if (!NIL_P(dname) && !not_same_drive(dname, s[0])) {
3120  rb_file_expand_path_internal(dname, Qnil, abs_mode, long_name, result);
3121  BUFINIT();
3122  if (has_drive_letter(p) && TOLOWER(p[0]) == TOLOWER(s[0])) {
3123  /* ok, same drive */
3124  same = 1;
3125  }
3126  }
3127  if (!same) {
3128  char *e = append_fspath(result, fname, getcwdofdrv(*s), &enc, fsenc);
3129  tainted = 1;
3130  BUFINIT();
3131  p = e;
3132  }
3133  else {
3134  rb_enc_associate(result, enc = rb_enc_check(result, fname));
3135  p = pend;
3136  }
3137  p = chompdirsep(skiproot(buf, p, enc), p, enc);
3138  s += 2;
3139  }
3140  }
3141 #endif
3142  else if (!rb_is_absolute_path(s)) {
3143  if (!NIL_P(dname)) {
3144  rb_file_expand_path_internal(dname, Qnil, abs_mode, long_name, result);
3146  BUFINIT();
3147  p = pend;
3148  }
3149  else {
3150  char *e = append_fspath(result, fname, my_getcwd(), &enc, fsenc);
3151  tainted = 1;
3152  BUFINIT();
3153  p = e;
3154  }
3155 #if defined DOSISH || defined __CYGWIN__
3156  if (isdirsep(*s)) {
3157  /* specified full path, but not drive letter nor UNC */
3158  /* we need to get the drive letter or UNC share name */
3159  p = skipprefix(buf, p, enc);
3160  }
3161  else
3162 #endif
3163  p = chompdirsep(skiproot(buf, p, enc), p, enc);
3164  }
3165  else {
3166  size_t len;
3167  b = s;
3168  do s++; while (isdirsep(*s));
3169  len = s - b;
3170  p = buf + len;
3171  BUFCHECK(bdiff >= buflen);
3172  memset(buf, '/', len);
3173  rb_str_set_len(result, len);
3175  }
3176  if (p > buf && p[-1] == '/')
3177  --p;
3178  else {
3180  BUFCHECK(bdiff + 1 >= buflen);
3181  *p = '/';
3182  }
3183 
3184  rb_str_set_len(result, p-buf+1);
3185  BUFCHECK(bdiff + 1 >= buflen);
3186  p[1] = 0;
3187  root = skipprefix(buf, p+1, enc);
3188 
3189  b = s;
3190  while (*s) {
3191  switch (*s) {
3192  case '.':
3193  if (b == s++) { /* beginning of path element */
3194  switch (*s) {
3195  case '\0':
3196  b = s;
3197  break;
3198  case '.':
3199  if (*(s+1) == '\0' || isdirsep(*(s+1))) {
3200  /* We must go back to the parent */
3201  char *n;
3202  *p = '\0';
3203  if (!(n = strrdirsep(root, p, enc))) {
3204  *p = '/';
3205  }
3206  else {
3207  p = n;
3208  }
3209  b = ++s;
3210  }
3211 #if USE_NTFS
3212  else {
3213  do ++s; while (istrailinggarbage(*s));
3214  }
3215 #endif
3216  break;
3217  case '/':
3218 #if defined DOSISH || defined __CYGWIN__
3219  case '\\':
3220 #endif
3221  b = ++s;
3222  break;
3223  default:
3224  /* ordinary path element, beginning don't move */
3225  break;
3226  }
3227  }
3228 #if USE_NTFS
3229  else {
3230  --s;
3231  case ' ': {
3232  const char *e = s;
3233  while (s < fend && istrailinggarbage(*s)) s++;
3234  if (!*s) {
3235  s = e;
3236  goto endpath;
3237  }
3238  }
3239  }
3240 #endif
3241  break;
3242  case '/':
3243 #if defined DOSISH || defined __CYGWIN__
3244  case '\\':
3245 #endif
3246  if (s > b) {
3247  long rootdiff = root - buf;
3248  rb_str_set_len(result, p-buf+1);
3249  BUFCHECK(bdiff + (s-b+1) >= buflen);
3250  root = buf + rootdiff;
3251  memcpy(++p, b, s-b);
3252  p += s-b;
3253  *p = '/';
3254  }
3255  b = ++s;
3256  break;
3257  default:
3258  Inc(s, fend, enc);
3259  break;
3260  }
3261  }
3262 
3263  if (s > b) {
3264 #if USE_NTFS
3265  static const char prime[] = ":$DATA";
3266  enum {prime_len = sizeof(prime) -1};
3267  endpath:
3268  if (s > b + prime_len && strncasecmp(s - prime_len, prime, prime_len) == 0) {
3269  /* alias of stream */
3270  /* get rid of a bug of x64 VC++ */
3271  if (*(s - (prime_len+1)) == ':') {
3272  s -= prime_len + 1; /* prime */
3273  }
3274  else if (memchr(b, ':', s - prime_len - b)) {
3275  s -= prime_len; /* alternative */
3276  }
3277  }
3278 #endif
3279  rb_str_set_len(result, p-buf+1);
3280  BUFCHECK(bdiff + (s-b) >= buflen);
3281  memcpy(++p, b, s-b);
3282  p += s-b;
3284  }
3285  if (p == skiproot(buf, p + !!*p, enc) - 1) p++;
3286 
3287 #if USE_NTFS
3288  *p = '\0';
3289  if ((s = strrdirsep(b = buf, p, enc)) != 0 && !strpbrk(s, "*?")) {
3290  VALUE tmp, v;
3291  size_t len;
3292  rb_encoding *enc;
3293  WCHAR *wstr;
3294  WIN32_FIND_DATAW wfd;
3295  HANDLE h;
3296 #ifdef __CYGWIN__
3297 #ifdef HAVE_CYGWIN_CONV_PATH
3298  char *w32buf = NULL;
3299  const int flags = CCP_POSIX_TO_WIN_A | CCP_RELATIVE;
3300 #else
3301  char w32buf[MAXPATHLEN];
3302 #endif
3303  const char *path;
3304  ssize_t bufsize;
3305  int lnk_added = 0, is_symlink = 0;
3306  struct stat st;
3307  p = (char *)s;
3308  len = strlen(p);
3309  if (lstat(buf, &st) == 0 && S_ISLNK(st.st_mode)) {
3310  is_symlink = 1;
3311  if (len > 4 && STRCASECMP(p + len - 4, ".lnk") != 0) {
3312  lnk_added = 1;
3313  }
3314  }
3315  path = *buf ? buf : "/";
3316 #ifdef HAVE_CYGWIN_CONV_PATH
3317  bufsize = cygwin_conv_path(flags, path, NULL, 0);
3318  if (bufsize > 0) {
3319  bufsize += len;
3320  if (lnk_added) bufsize += 4;
3321  w32buf = ALLOCA_N(char, bufsize);
3322  if (cygwin_conv_path(flags, path, w32buf, bufsize) == 0) {
3323  b = w32buf;
3324  }
3325  }
3326 #else
3327  bufsize = MAXPATHLEN;
3328  if (cygwin_conv_to_win32_path(path, w32buf) == 0) {
3329  b = w32buf;
3330  }
3331 #endif
3332  if (is_symlink && b == w32buf) {
3333  *p = '\\';
3334  strlcat(w32buf, p, bufsize);
3335  if (lnk_added) {
3336  strlcat(w32buf, ".lnk", bufsize);
3337  }
3338  }
3339  else {
3340  lnk_added = 0;
3341  }
3342  *p = '/';
3343 #endif
3344  rb_str_set_len(result, p - buf + strlen(p));
3345  enc = rb_enc_get(result);
3346  tmp = result;
3349  }
3350  len = MultiByteToWideChar(CP_UTF8, 0, RSTRING_PTR(tmp), -1, NULL, 0);
3351  wstr = ALLOCV_N(WCHAR, v, len);
3352  MultiByteToWideChar(CP_UTF8, 0, RSTRING_PTR(tmp), -1, wstr, len);
3353  if (tmp != result) rb_str_resize(tmp, 0);
3354  h = FindFirstFileW(wstr, &wfd);
3355  ALLOCV_END(v);
3356  if (h != INVALID_HANDLE_VALUE) {
3357  size_t wlen;
3358  FindClose(h);
3359  len = lstrlenW(wfd.cFileName);
3360 #ifdef __CYGWIN__
3361  if (lnk_added && len > 4 &&
3362  wcscasecmp(wfd.cFileName + len - 4, L".lnk") == 0) {
3363  wfd.cFileName[len -= 4] = L'\0';
3364  }
3365 #else
3366  p = (char *)s;
3367 #endif
3368  ++p;
3369  wlen = (int)len;
3370  len = WideCharToMultiByte(CP_UTF8, 0, wfd.cFileName, wlen, NULL, 0, NULL, NULL);
3371  BUFCHECK(bdiff + len >= buflen);
3372  WideCharToMultiByte(CP_UTF8, 0, wfd.cFileName, wlen, p, len + 1, NULL, NULL);
3373  if (tmp != result) {
3374  rb_str_buf_cat(tmp, p, len);
3375  tmp = rb_str_encode(tmp, rb_enc_from_encoding(enc), 0, Qnil);
3376  len = RSTRING_LEN(tmp);
3377  BUFCHECK(bdiff + len >= buflen);
3378  memcpy(p, RSTRING_PTR(tmp), len);
3379  rb_str_resize(tmp, 0);
3380  }
3381  p += len;
3382  }
3383 #ifdef __CYGWIN__
3384  else {
3385  p += strlen(p);
3386  }
3387 #endif
3388  }
3389 #endif
3390 
3391  if (tainted) OBJ_TAINT(result);
3392  rb_str_set_len(result, p - buf);
3393  rb_enc_check(fname, result);
3395  return result;
3396 }
3397 #endif /* _WIN32 */
3398 
3399 #define EXPAND_PATH_BUFFER() rb_usascii_str_new(0, MAXPATHLEN + 2)
3400 
3401 static VALUE
3403 {
3404  rb_str_resize(str, RSTRING_LEN(str));
3405  return str;
3406 }
3407 
3408 #define expand_path(fname, dname, abs_mode, long_name, result) \
3409  str_shrink(rb_file_expand_path_internal(fname, dname, abs_mode, long_name, result))
3410 
3411 #define check_expand_path_args(fname, dname) \
3412  (((fname) = rb_get_path(fname)), \
3413  (void)(NIL_P(dname) ? (dname) : ((dname) = rb_get_path(dname))))
3414 
3415 static VALUE
3417 {
3418  return rb_file_expand_path_internal(fname, Qnil, 0, 0, EXPAND_PATH_BUFFER());
3419 }
3420 
3421 VALUE
3423 {
3424  check_expand_path_args(fname, dname);
3425  return expand_path(fname, dname, 0, 1, EXPAND_PATH_BUFFER());
3426 }
3427 
3428 VALUE
3430 {
3431  return expand_path(fname, dname, 0, 0, EXPAND_PATH_BUFFER());
3432 }
3433 
3434 /*
3435  * call-seq:
3436  * File.expand_path(file_name [, dir_string] ) -> abs_file_name
3437  *
3438  * Converts a pathname to an absolute pathname. Relative paths are
3439  * referenced from the current working directory of the process unless
3440  * +dir_string+ is given, in which case it will be used as the
3441  * starting point. The given pathname may start with a
3442  * ``<code>~</code>'', which expands to the process owner's home
3443  * directory (the environment variable +HOME+ must be set
3444  * correctly). ``<code>~</code><i>user</i>'' expands to the named
3445  * user's home directory.
3446  *
3447  * File.expand_path("~oracle/bin") #=> "/home/oracle/bin"
3448  *
3449  * A simple example of using +dir_string+ is as follows.
3450  * File.expand_path("ruby", "/usr/bin") #=> "/usr/bin/ruby"
3451  *
3452  * A more complex example which also resolves parent directory is as follows.
3453  * Suppose we are in bin/mygem and want the absolute path of lib/mygem.rb.
3454  *
3455  * File.expand_path("../../lib/mygem.rb", __FILE__)
3456  * #=> ".../path/to/project/lib/mygem.rb"
3457  *
3458  * So first it resolves the parent of __FILE__, that is bin/, then go to the
3459  * parent, the root of the project and appends +lib/mygem.rb+.
3460  */
3461 
3462 VALUE
3464 {
3465  VALUE fname, dname;
3466 
3467  if (argc == 1) {
3468  return rb_file_expand_path(argv[0], Qnil);
3469  }
3470  rb_scan_args(argc, argv, "11", &fname, &dname);
3471 
3472  return rb_file_expand_path(fname, dname);
3473 }
3474 
3475 VALUE
3477 {
3478  check_expand_path_args(fname, dname);
3479  return expand_path(fname, dname, 1, 1, EXPAND_PATH_BUFFER());
3480 }
3481 
3482 /*
3483  * call-seq:
3484  * File.absolute_path(file_name [, dir_string] ) -> abs_file_name
3485  *
3486  * Converts a pathname to an absolute pathname. Relative paths are
3487  * referenced from the current working directory of the process unless
3488  * <i>dir_string</i> is given, in which case it will be used as the
3489  * starting point. If the given pathname starts with a ``<code>~</code>''
3490  * it is NOT expanded, it is treated as a normal directory name.
3491  *
3492  * File.absolute_path("~oracle/bin") #=> "<relative_path>/~oracle/bin"
3493  */
3494 
3495 VALUE
3497 {
3498  VALUE fname, dname;
3499 
3500  if (argc == 1) {
3501  return rb_file_absolute_path(argv[0], Qnil);
3502  }
3503  rb_scan_args(argc, argv, "11", &fname, &dname);
3504 
3505  return rb_file_absolute_path(fname, dname);
3506 }
3507 
3508 static void
3509 realpath_rec(long *prefixlenp, VALUE *resolvedp, const char *unresolved, VALUE loopcheck, int strict, int last)
3510 {
3511  const char *pend = unresolved + strlen(unresolved);
3512  rb_encoding *enc = rb_enc_get(*resolvedp);
3513  ID resolving;
3514  CONST_ID(resolving, "resolving");
3515  while (unresolved < pend) {
3516  const char *testname = unresolved;
3517  const char *unresolved_firstsep = rb_enc_path_next(unresolved, pend, enc);
3518  long testnamelen = unresolved_firstsep - unresolved;
3519  const char *unresolved_nextname = unresolved_firstsep;
3520  while (unresolved_nextname < pend && isdirsep(*unresolved_nextname))
3521  unresolved_nextname++;
3522  unresolved = unresolved_nextname;
3523  if (testnamelen == 1 && testname[0] == '.') {
3524  }
3525  else if (testnamelen == 2 && testname[0] == '.' && testname[1] == '.') {
3526  if (*prefixlenp < RSTRING_LEN(*resolvedp)) {
3527  const char *resolved_str = RSTRING_PTR(*resolvedp);
3528  const char *resolved_names = resolved_str + *prefixlenp;
3529  const char *lastsep = strrdirsep(resolved_names, resolved_str + RSTRING_LEN(*resolvedp), enc);
3530  long len = lastsep ? lastsep - resolved_names : 0;
3531  rb_str_resize(*resolvedp, *prefixlenp + len);
3532  }
3533  }
3534  else {
3535  VALUE checkval;
3536  VALUE testpath = rb_str_dup(*resolvedp);
3537  if (*prefixlenp < RSTRING_LEN(testpath))
3538  rb_str_cat2(testpath, "/");
3539 #if defined(DOSISH_UNC) || defined(DOSISH_DRIVE_LETTER)
3540  if (*prefixlenp > 1 && *prefixlenp == RSTRING_LEN(testpath)) {
3541  const char *prefix = RSTRING_PTR(testpath);
3542  const char *last = rb_enc_left_char_head(prefix, prefix + *prefixlenp - 1, prefix + *prefixlenp, enc);
3543  if (!isdirsep(*last)) rb_str_cat2(testpath, "/");
3544  }
3545 #endif
3546  rb_str_cat(testpath, testname, testnamelen);
3547  checkval = rb_hash_aref(loopcheck, testpath);
3548  if (!NIL_P(checkval)) {
3549  if (checkval == ID2SYM(resolving)) {
3550  errno = ELOOP;
3551  rb_sys_fail_path(testpath);
3552  }
3553  else {
3554  *resolvedp = rb_str_dup(checkval);
3555  }
3556  }
3557  else {
3558  struct stat sbuf;
3559  int ret;
3560  VALUE testpath2 = rb_str_encode_ospath(testpath);
3561 #ifdef __native_client__
3562  ret = stat(RSTRING_PTR(testpath2), &sbuf);
3563 #else
3564  ret = lstat(RSTRING_PTR(testpath2), &sbuf);
3565 #endif
3566  if (ret == -1) {
3567  if (errno == ENOENT) {
3568  if (strict || !last || *unresolved_firstsep)
3569  rb_sys_fail_path(testpath);
3570  *resolvedp = testpath;
3571  break;
3572  }
3573  else {
3574  rb_sys_fail_path(testpath);
3575  }
3576  }
3577 #ifdef HAVE_READLINK
3578  if (S_ISLNK(sbuf.st_mode)) {
3579  VALUE link;
3580  volatile VALUE link_orig = Qnil;
3581  const char *link_prefix, *link_names;
3582  long link_prefixlen;
3583  rb_hash_aset(loopcheck, testpath, ID2SYM(resolving));
3584  link = rb_readlink(testpath);
3585  link_prefix = RSTRING_PTR(link);
3586  link_names = skipprefixroot(link_prefix, link_prefix + RSTRING_LEN(link), rb_enc_get(link));
3587  link_prefixlen = link_names - link_prefix;
3588  if (link_prefixlen > 0) {
3589  rb_encoding *enc, *linkenc = rb_enc_get(link);
3590  link_orig = link;
3591  link = rb_str_subseq(link, 0, link_prefixlen);
3592  enc = rb_enc_check(*resolvedp, link);
3593  if (enc != linkenc) link = rb_str_conv_enc(link, linkenc, enc);
3594  *resolvedp = link;
3595  *prefixlenp = link_prefixlen;
3596  }
3597  realpath_rec(prefixlenp, resolvedp, link_names, loopcheck, strict, *unresolved_firstsep == '\0');
3598  RB_GC_GUARD(link_orig);
3599  rb_hash_aset(loopcheck, testpath, rb_str_dup_frozen(*resolvedp));
3600  }
3601  else
3602 #endif
3603  {
3604  VALUE s = rb_str_dup_frozen(testpath);
3605  rb_hash_aset(loopcheck, s, s);
3606  *resolvedp = testpath;
3607  }
3608  }
3609  }
3610  }
3611 }
3612 
3613 #ifdef __native_client__
3614 VALUE
3615 rb_realpath_internal(VALUE basedir, VALUE path, int strict)
3616 {
3617  return path;
3618 }
3619 #else
3620 VALUE
3621 rb_realpath_internal(VALUE basedir, VALUE path, int strict)
3622 {
3623  long prefixlen;
3624  VALUE resolved;
3625  volatile VALUE unresolved_path;
3626  VALUE loopcheck;
3627  volatile VALUE curdir = Qnil;
3628 
3629  rb_encoding *enc;
3630  char *path_names = NULL, *basedir_names = NULL, *curdir_names = NULL;
3631  char *ptr, *prefixptr = NULL, *pend;
3632  long len;
3633 
3634  rb_secure(2);
3635 
3636  FilePathValue(path);
3637  unresolved_path = rb_str_dup_frozen(path);
3638 
3639  if (!NIL_P(basedir)) {
3640  FilePathValue(basedir);
3641  basedir = rb_str_dup_frozen(basedir);
3642  }
3643 
3644  RSTRING_GETMEM(unresolved_path, ptr, len);
3645  path_names = skipprefixroot(ptr, ptr + len, rb_enc_get(unresolved_path));
3646  if (ptr != path_names) {
3647  resolved = rb_str_subseq(unresolved_path, 0, path_names - ptr);
3648  goto root_found;
3649  }
3650 
3651  if (!NIL_P(basedir)) {
3652  RSTRING_GETMEM(basedir, ptr, len);
3653  basedir_names = skipprefixroot(ptr, ptr + len, rb_enc_get(basedir));
3654  if (ptr != basedir_names) {
3655  resolved = rb_str_subseq(basedir, 0, basedir_names - ptr);
3656  goto root_found;
3657  }
3658  }
3659 
3660  curdir = rb_dir_getwd();
3661  RSTRING_GETMEM(curdir, ptr, len);
3662  curdir_names = skipprefixroot(ptr, ptr + len, rb_enc_get(curdir));
3663  resolved = rb_str_subseq(curdir, 0, curdir_names - ptr);
3664 
3665  root_found:
3666  RSTRING_GETMEM(resolved, prefixptr, prefixlen);
3667  pend = prefixptr + prefixlen;
3668  enc = rb_enc_get(resolved);
3669  ptr = chompdirsep(prefixptr, pend, enc);
3670  if (ptr < pend) {
3671  prefixlen = ++ptr - prefixptr;
3672  rb_str_set_len(resolved, prefixlen);
3673  }
3674 #ifdef FILE_ALT_SEPARATOR
3675  while (prefixptr < ptr) {
3676  if (*prefixptr == FILE_ALT_SEPARATOR) {
3677  *prefixptr = '/';
3678  }
3679  Inc(prefixptr, pend, enc);
3680  }
3681 #endif
3682 
3683  loopcheck = rb_hash_new();
3684  if (curdir_names)
3685  realpath_rec(&prefixlen, &resolved, curdir_names, loopcheck, 1, 0);
3686  if (basedir_names)
3687  realpath_rec(&prefixlen, &resolved, basedir_names, loopcheck, 1, 0);
3688  realpath_rec(&prefixlen, &resolved, path_names, loopcheck, strict, 1);
3689 
3690  OBJ_TAINT(resolved);
3691  return resolved;
3692 }
3693 #endif
3694 
3695 /*
3696  * call-seq:
3697  * File.realpath(pathname [, dir_string]) -> real_pathname
3698  *
3699  * Returns the real (absolute) pathname of _pathname_ in the actual
3700  * filesystem not containing symlinks or useless dots.
3701  *
3702  * If _dir_string_ is given, it is used as a base directory
3703  * for interpreting relative pathname instead of the current directory.
3704  *
3705  * All components of the pathname must exist when this method is
3706  * called.
3707  */
3708 static VALUE
3710 {
3711  VALUE path, basedir;
3712  rb_scan_args(argc, argv, "11", &path, &basedir);
3713  return rb_realpath_internal(basedir, path, 1);
3714 }
3715 
3716 /*
3717  * call-seq:
3718  * File.realdirpath(pathname [, dir_string]) -> real_pathname
3719  *
3720  * Returns the real (absolute) pathname of _pathname_ in the actual filesystem.
3721  * The real pathname doesn't contain symlinks or useless dots.
3722  *
3723  * If _dir_string_ is given, it is used as a base directory
3724  * for interpreting relative pathname instead of the current directory.
3725  *
3726  * The last component of the real pathname can be nonexistent.
3727  */
3728 static VALUE
3730 {
3731  VALUE path, basedir;
3732  rb_scan_args(argc, argv, "11", &path, &basedir);
3733  return rb_realpath_internal(basedir, path, 0);
3734 }
3735 
3736 static size_t
3737 rmext(const char *p, long l0, long l1, const char *e, long l2, rb_encoding *enc)
3738 {
3739  int len1, len2;
3740  unsigned int c;
3741  const char *s, *last;
3742 
3743  if (!e || !l2) return 0;
3744 
3745  c = rb_enc_codepoint_len(e, e + l2, &len1, enc);
3746  if (rb_enc_ascget(e + len1, e + l2, &len2, enc) == '*' && len1 + len2 == l2) {
3747  if (c == '.') return l0;
3748  s = p;
3749  e = p + l1;
3750  last = e;
3751  while (s < e) {
3752  if (rb_enc_codepoint_len(s, e, &len1, enc) == c) last = s;
3753  s += len1;
3754  }
3755  return last - p;
3756  }
3757  if (l1 < l2) return l1;
3758 
3759  s = p+l1-l2;
3760  if (rb_enc_left_char_head(p, s, p+l1, enc) != s) return 0;
3761 #if CASEFOLD_FILESYSTEM
3762 #define fncomp strncasecmp
3763 #else
3764 #define fncomp strncmp
3765 #endif
3766  if (fncomp(s, e, l2) == 0) {
3767  return l1-l2;
3768  }
3769  return 0;
3770 }
3771 
3772 const char *
3773 ruby_enc_find_basename(const char *name, long *baselen, long *alllen, rb_encoding *enc)
3774 {
3775  const char *p, *q, *e, *end;
3776 #if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC
3777  const char *root;
3778 #endif
3779  long f = 0, n = -1;
3780 
3781  end = name + (alllen ? (size_t)*alllen : strlen(name));
3782  name = skipprefix(name, end, enc);
3783 #if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC
3784  root = name;
3785 #endif
3786  while (isdirsep(*name))
3787  name++;
3788  if (!*name) {
3789  p = name - 1;
3790  f = 1;
3791 #if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC
3792  if (name != root) {
3793  /* has slashes */
3794  }
3795 #ifdef DOSISH_DRIVE_LETTER
3796  else if (*p == ':') {
3797  p++;
3798  f = 0;
3799  }
3800 #endif
3801 #ifdef DOSISH_UNC
3802  else {
3803  p = "/";
3804  }
3805 #endif
3806 #endif
3807  }
3808  else {
3809  if (!(p = strrdirsep(name, end, enc))) {
3810  p = name;
3811  }
3812  else {
3813  while (isdirsep(*p)) p++; /* skip last / */
3814  }
3815 #if USE_NTFS
3816  n = ntfs_tail(p, end, enc) - p;
3817 #else
3818  n = chompdirsep(p, end, enc) - p;
3819 #endif
3820  for (q = p; q - p < n && *q == '.'; q++);
3821  for (e = 0; q - p < n; Inc(q, end, enc)) {
3822  if (*q == '.') e = q;
3823  }
3824  if (e) f = e - p;
3825  else f = n;
3826  }
3827 
3828  if (baselen)
3829  *baselen = f;
3830  if (alllen)
3831  *alllen = n;
3832  return p;
3833 }
3834 
3835 /*
3836  * call-seq:
3837  * File.basename(file_name [, suffix] ) -> base_name
3838  *
3839  * Returns the last component of the filename given in <i>file_name</i>,
3840  * which can be formed using both <code>File::SEPARATOR</code> and
3841  * <code>File::ALT_SEPARATOR</code> as the separator when
3842  * <code>File::ALT_SEPARATOR</code> is not <code>nil</code>. If
3843  * <i>suffix</i> is given and present at the end of <i>file_name</i>,
3844  * it is removed.
3845  *
3846  * File.basename("/home/gumby/work/ruby.rb") #=> "ruby.rb"
3847  * File.basename("/home/gumby/work/ruby.rb", ".rb") #=> "ruby"
3848  */
3849 
3850 static VALUE
3852 {
3853  VALUE fname, fext, basename;
3854  const char *name, *p;
3855  long f, n;
3856  rb_encoding *enc;
3857 
3858  if (rb_scan_args(argc, argv, "11", &fname, &fext) == 2) {
3859  StringValue(fext);
3860  enc = check_path_encoding(fext);
3861  }
3862  FilePathStringValue(fname);
3863  if (NIL_P(fext) || !(enc = rb_enc_compatible(fname, fext))) {
3864  enc = rb_enc_get(fname);
3865  fext = Qnil;
3866  }
3867  if ((n = RSTRING_LEN(fname)) == 0 || !*(name = RSTRING_PTR(fname)))
3868  return rb_str_new_shared(fname);
3869 
3870  p = ruby_enc_find_basename(name, &f, &n, enc);
3871  if (n >= 0) {
3872  if (NIL_P(fext)) {
3873  f = n;
3874  }
3875  else {
3876  const char *fp;
3877  fp = StringValueCStr(fext);
3878  if (!(f = rmext(p, f, n, fp, RSTRING_LEN(fext), enc))) {
3879  f = n;
3880  }
3881  RB_GC_GUARD(fext);
3882  }
3883  if (f == RSTRING_LEN(fname)) return rb_str_new_shared(fname);
3884  }
3885 
3886  basename = rb_str_new(p, f);
3887  rb_enc_copy(basename, fname);
3888  OBJ_INFECT(basename, fname);
3889  return basename;
3890 }
3891 
3892 /*
3893  * call-seq:
3894  * File.dirname(file_name) -> dir_name
3895  *
3896  * Returns all components of the filename given in <i>file_name</i>
3897  * except the last one. The filename can be formed using both
3898  * <code>File::SEPARATOR</code> and <code>File::ALT_SEPARATOR</code> as the
3899  * separator when <code>File::ALT_SEPARATOR</code> is not <code>nil</code>.
3900  *
3901  * File.dirname("/home/gumby/work/ruby.rb") #=> "/home/gumby/work"
3902  */
3903 
3904 static VALUE
3906 {
3907  return rb_file_dirname(fname);
3908 }
3909 
3910 VALUE
3912 {
3913  const char *name, *root, *p, *end;
3914  VALUE dirname;
3915  rb_encoding *enc;
3916 
3917  FilePathStringValue(fname);
3918  name = StringValueCStr(fname);
3919  end = name + RSTRING_LEN(fname);
3920  enc = rb_enc_get(fname);
3921  root = skiproot(name, end, enc);
3922 #ifdef DOSISH_UNC
3923  if (root > name + 1 && isdirsep(*name))
3924  root = skipprefix(name = root - 2, end, enc);
3925 #else
3926  if (root > name + 1)
3927  name = root - 1;
3928 #endif
3929  p = strrdirsep(root, end, enc);
3930  if (!p) {
3931  p = root;
3932  }
3933  if (p == name)
3934  return rb_usascii_str_new2(".");
3935 #ifdef DOSISH_DRIVE_LETTER
3936  if (has_drive_letter(name) && isdirsep(*(name + 2))) {
3937  const char *top = skiproot(name + 2, end, enc);
3938  dirname = rb_str_new(name, 3);
3939  rb_str_cat(dirname, top, p - top);
3940  }
3941  else
3942 #endif
3943  dirname = rb_str_new(name, p - name);
3944 #ifdef DOSISH_DRIVE_LETTER
3945  if (has_drive_letter(name) && root == name + 2 && p - name == 2)
3946  rb_str_cat(dirname, ".", 1);
3947 #endif
3948  rb_enc_copy(dirname, fname);
3949  OBJ_INFECT(dirname, fname);
3950  return dirname;
3951 }
3952 
3953 /*
3954  * accept a String, and return the pointer of the extension.
3955  * if len is passed, set the length of extension to it.
3956  * returned pointer is in ``name'' or NULL.
3957  * returns *len
3958  * no dot NULL 0
3959  * dotfile top 0
3960  * end with dot dot 1
3961  * .ext dot len of .ext
3962  * .ext:stream dot len of .ext without :stream (NT only)
3963  *
3964  */
3965 const char *
3966 ruby_enc_find_extname(const char *name, long *len, rb_encoding *enc)
3967 {
3968  const char *p, *e, *end = name + (len ? *len : (long)strlen(name));
3969 
3970  p = strrdirsep(name, end, enc); /* get the last path component */
3971  if (!p)
3972  p = name;
3973  else
3974  do name = ++p; while (isdirsep(*p));
3975 
3976  e = 0;
3977  while (*p && *p == '.') p++;
3978  while (*p) {
3979  if (*p == '.' || istrailinggarbage(*p)) {
3980 #if USE_NTFS
3981  const char *last = p++, *dot = last;
3982  while (istrailinggarbage(*p)) {
3983  if (*p == '.') dot = p;
3984  p++;
3985  }
3986  if (!*p || *p == ':') {
3987  p = last;
3988  break;
3989  }
3990  if (*last == '.' || dot > last) e = dot;
3991  continue;
3992 #else
3993  e = p; /* get the last dot of the last component */
3994 #endif
3995  }
3996 #if USE_NTFS
3997  else if (*p == ':') {
3998  break;
3999  }
4000 #endif
4001  else if (isdirsep(*p))
4002  break;
4003  Inc(p, end, enc);
4004  }
4005 
4006  if (len) {
4007  /* no dot, or the only dot is first or end? */
4008  if (!e || e == name)
4009  *len = 0;
4010  else if (e+1 == p)
4011  *len = 1;
4012  else
4013  *len = p - e;
4014  }
4015  return e;
4016 }
4017 
4018 /*
4019  * call-seq:
4020  * File.extname(path) -> string
4021  *
4022  * Returns the extension (the portion of file name in +path+
4023  * starting from the last period).
4024  *
4025  * If +path+ is a dotfile, or starts with a period, then the starting
4026  * dot is not dealt with the start of the extension.
4027  *
4028  * An empty string will also be returned when the period is the last character
4029  * in +path+.
4030  *
4031  * File.extname("test.rb") #=> ".rb"
4032  * File.extname("a/b/d/test.rb") #=> ".rb"
4033  * File.extname("foo.") #=> ""
4034  * File.extname("test") #=> ""
4035  * File.extname(".profile") #=> ""
4036  * File.extname(".profile.sh") #=> ".sh"
4037  *
4038  */
4039 
4040 static VALUE
4042 {
4043  const char *name, *e;
4044  long len;
4045  VALUE extname;
4046 
4047  FilePathStringValue(fname);
4048  name = StringValueCStr(fname);
4049  len = RSTRING_LEN(fname);
4050  e = ruby_enc_find_extname(name, &len, rb_enc_get(fname));
4051  if (len <= 1)
4052  return rb_str_new(0, 0);
4053  extname = rb_str_subseq(fname, e - name, len); /* keep the dot, too! */
4054  OBJ_INFECT(extname, fname);
4055  return extname;
4056 }
4057 
4058 /*
4059  * call-seq:
4060  * File.path(path) -> string
4061  *
4062  * Returns the string representation of the path
4063  *
4064  * File.path("/dev/null") #=> "/dev/null"
4065  * File.path(Pathname.new("/tmp")) #=> "/tmp"
4066  *
4067  */
4068 
4069 static VALUE
4071 {
4072  return rb_get_path(fname);
4073 }
4074 
4075 /*
4076  * call-seq:
4077  * File.split(file_name) -> array
4078  *
4079  * Splits the given string into a directory and a file component and
4080  * returns them in a two-element array. See also
4081  * <code>File::dirname</code> and <code>File::basename</code>.
4082  *
4083  * File.split("/home/gumby/.profile") #=> ["/home/gumby", ".profile"]
4084  */
4085 
4086 static VALUE
4088 {
4089  FilePathStringValue(path); /* get rid of converting twice */
4090  return rb_assoc_new(rb_file_s_dirname(Qnil, path), rb_file_s_basename(1,&path));
4091 }
4092 
4094 
4095 static VALUE rb_file_join(VALUE ary, VALUE sep);
4096 
4097 static VALUE
4099 {
4100  VALUE *arg = (VALUE *)argp;
4101  if (recur || ary == arg[0]) rb_raise(rb_eArgError, "recursive array");
4102  return rb_file_join(arg[0], arg[1]);
4103 }
4104 
4105 static VALUE
4107 {
4108  long len, i;
4109  VALUE result, tmp;
4110  const char *name, *tail;
4111  int checked = TRUE;
4112  rb_encoding *enc;
4113 
4114  if (RARRAY_LEN(ary) == 0) return rb_str_new(0, 0);
4115 
4116  len = 1;
4117  for (i=0; i<RARRAY_LEN(ary); i++) {
4118  tmp = RARRAY_AREF(ary, i);
4119  if (RB_TYPE_P(tmp, T_STRING)) {
4120  check_path_encoding(tmp);
4121  len += RSTRING_LEN(tmp);
4122  }
4123  else {
4124  len += 10;
4125  }
4126  }
4127  if (!NIL_P(sep)) {
4128  StringValue(sep);
4129  len += RSTRING_LEN(sep) * (RARRAY_LEN(ary) - 1);
4130  }
4131  result = rb_str_buf_new(len);
4133  OBJ_INFECT(result, ary);
4134  for (i=0; i<RARRAY_LEN(ary); i++) {
4135  tmp = RARRAY_AREF(ary, i);
4136  switch (TYPE(tmp)) {
4137  case T_STRING:
4138  if (!checked) check_path_encoding(tmp);
4139  StringValueCStr(tmp);
4140  break;
4141  case T_ARRAY:
4142  if (ary == tmp) {
4143  rb_raise(rb_eArgError, "recursive array");
4144  }
4145  else {
4146  VALUE args[2];
4147 
4148  args[0] = tmp;
4149  args[1] = sep;
4150  tmp = rb_exec_recursive(file_inspect_join, ary, (VALUE)args);
4151  }
4152  break;
4153  default:
4154  FilePathStringValue(tmp);
4155  checked = FALSE;
4156  }
4157  RSTRING_GETMEM(result, name, len);
4158  if (i == 0) {
4159  rb_enc_copy(result, tmp);
4160  }
4161  else if (!NIL_P(sep)) {
4162  tail = chompdirsep(name, name + len, rb_enc_get(result));
4163  if (RSTRING_PTR(tmp) && isdirsep(RSTRING_PTR(tmp)[0])) {
4165  }
4166  else if (!*tail) {
4167  enc = rb_enc_check(result, sep);
4168  rb_str_buf_append(result, sep);
4169  rb_enc_associate(result, enc);
4170  }
4171  }
4172  enc = rb_enc_check(result, tmp);
4173  rb_str_buf_append(result, tmp);
4174  rb_enc_associate(result, enc);
4175  }
4177 
4178  return result;
4179 }
4180 
4181 /*
4182  * call-seq:
4183  * File.join(string, ...) -> path
4184  *
4185  * Returns a new string formed by joining the strings using
4186  * <code>File::SEPARATOR</code>.
4187  *
4188  * File.join("usr", "mail", "gumby") #=> "usr/mail/gumby"
4189  *
4190  */
4191 
4192 static VALUE
4194 {
4195  return rb_file_join(args, separator);
4196 }
4197 
4198 #if defined(HAVE_TRUNCATE) || defined(HAVE_CHSIZE)
4199 /*
4200  * call-seq:
4201  * File.truncate(file_name, integer) -> 0
4202  *
4203  * Truncates the file <i>file_name</i> to be at most <i>integer</i>
4204  * bytes long. Not available on all platforms.
4205  *
4206  * f = File.new("out", "w")
4207  * f.write("1234567890") #=> 10
4208  * f.close #=> nil
4209  * File.truncate("out", 5) #=> 0
4210  * File.size("out") #=> 5
4211  *
4212  */
4213 
4214 static VALUE
4215 rb_file_s_truncate(VALUE klass, VALUE path, VALUE len)
4216 {
4217 #ifdef HAVE_TRUNCATE
4218 #define NUM2POS(n) NUM2OFFT(n)
4219  off_t pos;
4220 #else
4221 #define NUM2POS(n) NUM2LONG(n)
4222  long pos;
4223 #endif
4224 
4225  rb_secure(2);
4226  pos = NUM2POS(len);
4227  FilePathValue(path);
4228  path = rb_str_encode_ospath(path);
4229 #ifdef HAVE_TRUNCATE
4230  if (truncate(StringValueCStr(path), pos) < 0)
4231  rb_sys_fail_path(path);
4232 #else /* defined(HAVE_CHSIZE) */
4233  {
4234  int tmpfd;
4235 
4236  if ((tmpfd = rb_cloexec_open(StringValueCStr(path), 0, 0)) < 0) {
4237  rb_sys_fail_path(path);
4238  }
4239  rb_update_max_fd(tmpfd);
4240  if (chsize(tmpfd, pos) < 0) {
4241  close(tmpfd);
4242  rb_sys_fail_path(path);
4243  }
4244  close(tmpfd);
4245  }
4246 #endif
4247  return INT2FIX(0);
4248 #undef NUM2POS
4249 }
4250 #else
4251 #define rb_file_s_truncate rb_f_notimplement
4252 #endif
4253 
4254 #if defined(HAVE_FTRUNCATE) || defined(HAVE_CHSIZE)
4255 /*
4256  * call-seq:
4257  * file.truncate(integer) -> 0
4258  *
4259  * Truncates <i>file</i> to at most <i>integer</i> bytes. The file
4260  * must be opened for writing. Not available on all platforms.
4261  *
4262  * f = File.new("out", "w")
4263  * f.syswrite("1234567890") #=> 10
4264  * f.truncate(5) #=> 0
4265  * f.close() #=> nil
4266  * File.size("out") #=> 5
4267  */
4268 
4269 static VALUE
4270 rb_file_truncate(VALUE obj, VALUE len)
4271 {
4272  rb_io_t *fptr;
4273 #if defined(HAVE_FTRUNCATE)
4274 #define NUM2POS(n) NUM2OFFT(n)
4275  off_t pos;
4276 #else
4277 #define NUM2POS(n) NUM2LONG(n)
4278  long pos;
4279 #endif
4280 
4281  rb_secure(2);
4282  pos = NUM2POS(len);
4283  GetOpenFile(obj, fptr);
4284  if (!(fptr->mode & FMODE_WRITABLE)) {
4285  rb_raise(rb_eIOError, "not opened for writing");
4286  }
4287  rb_io_flush_raw(obj, 0);
4288 #ifdef HAVE_FTRUNCATE
4289  if (ftruncate(fptr->fd, pos) < 0)
4290  rb_sys_fail_path(fptr->pathv);
4291 #else /* defined(HAVE_CHSIZE) */
4292  if (chsize(fptr->fd, pos) < 0)
4293  rb_sys_fail_path(fptr->pathv);
4294 #endif
4295  return INT2FIX(0);
4296 #undef NUM2POS
4297 }
4298 #else
4299 #define rb_file_truncate rb_f_notimplement
4300 #endif
4301 
4302 # ifndef LOCK_SH
4303 # define LOCK_SH 1
4304 # endif
4305 # ifndef LOCK_EX
4306 # define LOCK_EX 2
4307 # endif
4308 # ifndef LOCK_NB
4309 # define LOCK_NB 4
4310 # endif
4311 # ifndef LOCK_UN
4312 # define LOCK_UN 8
4313 # endif
4314 
4315 #ifdef __CYGWIN__
4316 #include <winerror.h>
4317 #endif
4318 
4319 static VALUE
4320 rb_thread_flock(void *data)
4321 {
4322 #ifdef __CYGWIN__
4323  int old_errno = errno;
4324 #endif
4325  int *op = data, ret = flock(op[0], op[1]);
4326 
4327 #ifdef __CYGWIN__
4328  if (GetLastError() == ERROR_NOT_LOCKED) {
4329  ret = 0;
4330  errno = old_errno;
4331  }
4332 #endif
4333  return (VALUE)ret;
4334 }
4335 
4336 /*
4337  * call-seq:
4338  * file.flock(locking_constant) -> 0 or false
4339  *
4340  * Locks or unlocks a file according to <i>locking_constant</i> (a
4341  * logical <em>or</em> of the values in the table below).
4342  * Returns <code>false</code> if <code>File::LOCK_NB</code> is
4343  * specified and the operation would otherwise have blocked. Not
4344  * available on all platforms.
4345  *
4346  * Locking constants (in class File):
4347  *
4348  * LOCK_EX | Exclusive lock. Only one process may hold an
4349  * | exclusive lock for a given file at a time.
4350  * ----------+------------------------------------------------
4351  * LOCK_NB | Don't block when locking. May be combined
4352  * | with other lock options using logical or.
4353  * ----------+------------------------------------------------
4354  * LOCK_SH | Shared lock. Multiple processes may each hold a
4355  * | shared lock for a given file at the same time.
4356  * ----------+------------------------------------------------
4357  * LOCK_UN | Unlock.
4358  *
4359  * Example:
4360  *
4361  * # update a counter using write lock
4362  * # don't use "w" because it truncates the file before lock.
4363  * File.open("counter", File::RDWR|File::CREAT, 0644) {|f|
4364  * f.flock(File::LOCK_EX)
4365  * value = f.read.to_i + 1
4366  * f.rewind
4367  * f.write("#{value}\n")
4368  * f.flush
4369  * f.truncate(f.pos)
4370  * }
4371  *
4372  * # read the counter using read lock
4373  * File.open("counter", "r") {|f|
4374  * f.flock(File::LOCK_SH)
4375  * p f.read
4376  * }
4377  *
4378  */
4379 
4380 static VALUE
4381 rb_file_flock(VALUE obj, VALUE operation)
4382 {
4383  rb_io_t *fptr;
4384  int op[2], op1;
4385  struct timeval time;
4386 
4387  rb_secure(2);
4388  op[1] = op1 = NUM2INT(operation);
4389  GetOpenFile(obj, fptr);
4390  op[0] = fptr->fd;
4391 
4392  if (fptr->mode & FMODE_WRITABLE) {
4393  rb_io_flush_raw(obj, 0);
4394  }
4395  while ((int)rb_thread_io_blocking_region(rb_thread_flock, op, fptr->fd) < 0) {
4396  switch (errno) {
4397  case EAGAIN:
4398  case EACCES:
4399 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
4400  case EWOULDBLOCK:
4401 #endif
4402  if (op1 & LOCK_NB) return Qfalse;
4403 
4404  time.tv_sec = 0;
4405  time.tv_usec = 100 * 1000; /* 0.1 sec */
4406  rb_thread_wait_for(time);
4407  rb_io_check_closed(fptr);
4408  continue;
4409 
4410  case EINTR:
4411 #if defined(ERESTART)
4412  case ERESTART:
4413 #endif
4414  break;
4415 
4416  default:
4417  rb_sys_fail_path(fptr->pathv);
4418  }
4419  }
4420  return INT2FIX(0);
4421 }
4422 #undef flock
4423 
4424 static void
4425 test_check(int n, int argc, VALUE *argv)
4426 {
4427  int i;
4428 
4429  rb_secure(2);
4430  n+=1;
4431  rb_check_arity(argc, n, n);
4432  for (i=1; i<n; i++) {
4433  if (!RB_TYPE_P(argv[i], T_FILE)) {
4434  FilePathValue(argv[i]);
4435  }
4436  }
4437 }
4438 
4439 #define CHECK(n) test_check((n), argc, argv)
4440 
4441 /*
4442  * call-seq:
4443  * test(cmd, file1 [, file2] ) -> obj
4444  *
4445  * Uses the integer +cmd+ to perform various tests on +file1+ (first
4446  * table below) or on +file1+ and +file2+ (second table).
4447  *
4448  * File tests on a single file:
4449  *
4450  * Cmd Returns Meaning
4451  * "A" | Time | Last access time for file1
4452  * "b" | boolean | True if file1 is a block device
4453  * "c" | boolean | True if file1 is a character device
4454  * "C" | Time | Last change time for file1
4455  * "d" | boolean | True if file1 exists and is a directory
4456  * "e" | boolean | True if file1 exists
4457  * "f" | boolean | True if file1 exists and is a regular file
4458  * "g" | boolean | True if file1 has the \CF{setgid} bit
4459  * | | set (false under NT)
4460  * "G" | boolean | True if file1 exists and has a group
4461  * | | ownership equal to the caller's group
4462  * "k" | boolean | True if file1 exists and has the sticky bit set
4463  * "l" | boolean | True if file1 exists and is a symbolic link
4464  * "M" | Time | Last modification time for file1
4465  * "o" | boolean | True if file1 exists and is owned by
4466  * | | the caller's effective uid
4467  * "O" | boolean | True if file1 exists and is owned by
4468  * | | the caller's real uid
4469  * "p" | boolean | True if file1 exists and is a fifo
4470  * "r" | boolean | True if file1 is readable by the effective
4471  * | | uid/gid of the caller
4472  * "R" | boolean | True if file is readable by the real
4473  * | | uid/gid of the caller
4474  * "s" | int/nil | If file1 has nonzero size, return the size,
4475  * | | otherwise return nil
4476  * "S" | boolean | True if file1 exists and is a socket
4477  * "u" | boolean | True if file1 has the setuid bit set
4478  * "w" | boolean | True if file1 exists and is writable by
4479  * | | the effective uid/gid
4480  * "W" | boolean | True if file1 exists and is writable by
4481  * | | the real uid/gid
4482  * "x" | boolean | True if file1 exists and is executable by
4483  * | | the effective uid/gid
4484  * "X" | boolean | True if file1 exists and is executable by
4485  * | | the real uid/gid
4486  * "z" | boolean | True if file1 exists and has a zero length
4487  *
4488  * Tests that take two files:
4489  *
4490  * "-" | boolean | True if file1 and file2 are identical
4491  * "=" | boolean | True if the modification times of file1
4492  * | | and file2 are equal
4493  * "<" | boolean | True if the modification time of file1
4494  * | | is prior to that of file2
4495  * ">" | boolean | True if the modification time of file1
4496  * | | is after that of file2
4497  */
4498 
4499 static VALUE
4501 {
4502  int cmd;
4503 
4504  if (argc == 0) rb_check_arity(argc, 2, 3);
4505  cmd = NUM2CHR(argv[0]);
4506  if (cmd == 0) {
4507  unknown:
4508  /* unknown command */
4509  if (ISPRINT(cmd)) {
4510  rb_raise(rb_eArgError, "unknown command '%s%c'", cmd == '\'' || cmd == '\\' ? "\\" : "", cmd);
4511  }
4512  else {
4513  rb_raise(rb_eArgError, "unknown command \"\\x%02X\"", cmd);
4514  }
4515  }
4516  if (strchr("bcdefgGkloOprRsSuwWxXz", cmd)) {
4517  CHECK(1);
4518  switch (cmd) {
4519  case 'b':
4520  return rb_file_blockdev_p(0, argv[1]);
4521 
4522  case 'c':
4523  return rb_file_chardev_p(0, argv[1]);
4524 
4525  case 'd':
4526  return rb_file_directory_p(0, argv[1]);
4527 
4528  case 'a':
4529  case 'e':
4530  return rb_file_exist_p(0, argv[1]);
4531 
4532  case 'f':
4533  return rb_file_file_p(0, argv[1]);
4534 
4535  case 'g':
4536  return rb_file_sgid_p(0, argv[1]);
4537 
4538  case 'G':
4539  return rb_file_grpowned_p(0, argv[1]);
4540 
4541  case 'k':
4542  return rb_file_sticky_p(0, argv[1]);
4543 
4544  case 'l':
4545  return rb_file_symlink_p(0, argv[1]);
4546 
4547  case 'o':
4548  return rb_file_owned_p(0, argv[1]);
4549 
4550  case 'O':
4551  return rb_file_rowned_p(0, argv[1]);
4552 
4553  case 'p':
4554  return rb_file_pipe_p(0, argv[1]);
4555 
4556  case 'r':
4557  return rb_file_readable_p(0, argv[1]);
4558 
4559  case 'R':
4560  return rb_file_readable_real_p(0, argv[1]);
4561 
4562  case 's':
4563  return rb_file_size_p(0, argv[1]);
4564 
4565  case 'S':
4566  return rb_file_socket_p(0, argv[1]);
4567 
4568  case 'u':
4569  return rb_file_suid_p(0, argv[1]);
4570 
4571  case 'w':
4572  return rb_file_writable_p(0, argv[1]);
4573 
4574  case 'W':
4575  return rb_file_writable_real_p(0, argv[1]);
4576 
4577  case 'x':
4578  return rb_file_executable_p(0, argv[1]);
4579 
4580  case 'X':
4581  return rb_file_executable_real_p(0, argv[1]);
4582 
4583  case 'z':
4584  return rb_file_zero_p(0, argv[1]);
4585  }
4586  }
4587 
4588  if (strchr("MAC", cmd)) {
4589  struct stat st;
4590  VALUE fname = argv[1];
4591 
4592  CHECK(1);
4593  if (rb_stat(fname, &st) == -1) {
4594  FilePathValue(fname);
4595  rb_sys_fail_path(fname);
4596  }
4597 
4598  switch (cmd) {
4599  case 'A':
4600  return stat_atime(&st);
4601  case 'M':
4602  return stat_mtime(&st);
4603  case 'C':
4604  return stat_ctime(&st);
4605  }
4606  }
4607 
4608  if (cmd == '-') {
4609  CHECK(2);
4610  return rb_file_identical_p(0, argv[1], argv[2]);
4611  }
4612 
4613  if (strchr("=<>", cmd)) {
4614  struct stat st1, st2;
4615 
4616  CHECK(2);
4617  if (rb_stat(argv[1], &st1) < 0) return Qfalse;
4618  if (rb_stat(argv[2], &st2) < 0) return Qfalse;
4619 
4620  switch (cmd) {
4621  case '=':
4622  if (st1.st_mtime == st2.st_mtime) return Qtrue;
4623  return Qfalse;
4624 
4625  case '>':
4626  if (st1.st_mtime > st2.st_mtime) return Qtrue;
4627  return Qfalse;
4628 
4629  case '<':
4630  if (st1.st_mtime < st2.st_mtime) return Qtrue;
4631  return Qfalse;
4632  }
4633  }
4634  goto unknown;
4635 }
4636 
4637 
4638 /*
4639  * Document-class: File::Stat
4640  *
4641  * Objects of class <code>File::Stat</code> encapsulate common status
4642  * information for <code>File</code> objects. The information is
4643  * recorded at the moment the <code>File::Stat</code> object is
4644  * created; changes made to the file after that point will not be
4645  * reflected. <code>File::Stat</code> objects are returned by
4646  * <code>IO#stat</code>, <code>File::stat</code>,
4647  * <code>File#lstat</code>, and <code>File::lstat</code>. Many of these
4648  * methods return platform-specific values, and not all values are
4649  * meaningful on all systems. See also <code>Kernel#test</code>.
4650  */
4651 
4652 static VALUE
4654 {
4655  return stat_new_0(klass, 0);
4656 }
4657 
4658 /*
4659  * call-seq:
4660  *
4661  * File::Stat.new(file_name) -> stat
4662  *
4663  * Create a File::Stat object for the given file name (raising an
4664  * exception if the file doesn't exist).
4665  */
4666 
4667 static VALUE
4669 {
4670  struct stat st, *nst;
4671 
4672  rb_secure(2);
4673  FilePathValue(fname);
4674  fname = rb_str_encode_ospath(fname);
4675  if (STAT(StringValueCStr(fname), &st) == -1) {
4676  rb_sys_fail_path(fname);
4677  }
4678  if (DATA_PTR(obj)) {
4679  xfree(DATA_PTR(obj));
4680  DATA_PTR(obj) = NULL;
4681  }
4682  nst = ALLOC(struct stat);
4683  *nst = st;
4684  DATA_PTR(obj) = nst;
4685 
4686  return Qnil;
4687 }
4688 
4689 /* :nodoc: */
4690 static VALUE
4692 {
4693  struct stat *nst;
4694 
4695  if (!OBJ_INIT_COPY(copy, orig)) return copy;
4696  if (DATA_PTR(copy)) {
4697  xfree(DATA_PTR(copy));
4698  DATA_PTR(copy) = 0;
4699  }
4700  if (DATA_PTR(orig)) {
4701  nst = ALLOC(struct stat);
4702  *nst = *(struct stat*)DATA_PTR(orig);
4703  DATA_PTR(copy) = nst;
4704  }
4705 
4706  return copy;
4707 }
4708 
4709 /*
4710  * call-seq:
4711  * stat.ftype -> string
4712  *
4713  * Identifies the type of <i>stat</i>. The return string is one of:
4714  * ``<code>file</code>'', ``<code>directory</code>'',
4715  * ``<code>characterSpecial</code>'', ``<code>blockSpecial</code>'',
4716  * ``<code>fifo</code>'', ``<code>link</code>'',
4717  * ``<code>socket</code>'', or ``<code>unknown</code>''.
4718  *
4719  * File.stat("/dev/tty").ftype #=> "characterSpecial"
4720  *
4721  */
4722 
4723 static VALUE
4725 {
4726  return rb_file_ftype(get_stat(obj));
4727 }
4728 
4729 /*
4730  * call-seq:
4731  * stat.directory? -> true or false
4732  *
4733  * Returns <code>true</code> if <i>stat</i> is a directory,
4734  * <code>false</code> otherwise.
4735  *
4736  * File.stat("testfile").directory? #=> false
4737  * File.stat(".").directory? #=> true
4738  */
4739 
4740 static VALUE
4742 {
4743  if (S_ISDIR(get_stat(obj)->st_mode)) return Qtrue;
4744  return Qfalse;
4745 }
4746 
4747 /*
4748  * call-seq:
4749  * stat.pipe? -> true or false
4750  *
4751  * Returns <code>true</code> if the operating system supports pipes and
4752  * <i>stat</i> is a pipe; <code>false</code> otherwise.
4753  */
4754 
4755 static VALUE
4757 {
4758 #ifdef S_IFIFO
4759  if (S_ISFIFO(get_stat(obj)->st_mode)) return Qtrue;
4760 
4761 #endif
4762  return Qfalse;
4763 }
4764 
4765 /*
4766  * call-seq:
4767  * stat.symlink? -> true or false
4768  *
4769  * Returns <code>true</code> if <i>stat</i> is a symbolic link,
4770  * <code>false</code> if it isn't or if the operating system doesn't
4771  * support this feature. As <code>File::stat</code> automatically
4772  * follows symbolic links, <code>symlink?</code> will always be
4773  * <code>false</code> for an object returned by
4774  * <code>File::stat</code>.
4775  *
4776  * File.symlink("testfile", "alink") #=> 0
4777  * File.stat("alink").symlink? #=> false
4778  * File.lstat("alink").symlink? #=> true
4779  *
4780  */
4781 
4782 static VALUE
4784 {
4785 #ifdef S_ISLNK
4786  if (S_ISLNK(get_stat(obj)->st_mode)) return Qtrue;
4787 #endif
4788  return Qfalse;
4789 }
4790 
4791 /*
4792  * call-seq:
4793  * stat.socket? -> true or false
4794  *
4795  * Returns <code>true</code> if <i>stat</i> is a socket,
4796  * <code>false</code> if it isn't or if the operating system doesn't
4797  * support this feature.
4798  *
4799  * File.stat("testfile").socket? #=> false
4800  *
4801  */
4802 
4803 static VALUE
4805 {
4806 #ifdef S_ISSOCK
4807  if (S_ISSOCK(get_stat(obj)->st_mode)) return Qtrue;
4808 
4809 #endif
4810  return Qfalse;
4811 }
4812 
4813 /*
4814  * call-seq:
4815  * stat.blockdev? -> true or false
4816  *
4817  * Returns <code>true</code> if the file is a block device,
4818  * <code>false</code> if it isn't or if the operating system doesn't
4819  * support this feature.
4820  *
4821  * File.stat("testfile").blockdev? #=> false
4822  * File.stat("/dev/hda1").blockdev? #=> true
4823  *
4824  */
4825 
4826 static VALUE
4828 {
4829 #ifdef S_ISBLK
4830  if (S_ISBLK(get_stat(obj)->st_mode)) return Qtrue;
4831 
4832 #endif
4833  return Qfalse;
4834 }
4835 
4836 /*
4837  * call-seq:
4838  * stat.chardev? -> true or false
4839  *
4840  * Returns <code>true</code> if the file is a character device,
4841  * <code>false</code> if it isn't or if the operating system doesn't
4842  * support this feature.
4843  *
4844  * File.stat("/dev/tty").chardev? #=> true
4845  *
4846  */
4847 
4848 static VALUE
4850 {
4851  if (S_ISCHR(get_stat(obj)->st_mode)) return Qtrue;
4852 
4853  return Qfalse;
4854 }
4855 
4856 /*
4857  * call-seq:
4858  * stat.owned? -> true or false
4859  *
4860  * Returns <code>true</code> if the effective user id of the process is
4861  * the same as the owner of <i>stat</i>.
4862  *
4863  * File.stat("testfile").owned? #=> true
4864  * File.stat("/etc/passwd").owned? #=> false
4865  *
4866  */
4867 
4868 static VALUE
4870 {
4871  if (get_stat(obj)->st_uid == geteuid()) return Qtrue;
4872  return Qfalse;
4873 }
4874 
4875 static VALUE
4877 {
4878  if (get_stat(obj)->st_uid == getuid()) return Qtrue;
4879  return Qfalse;
4880 }
4881 
4882 /*
4883  * call-seq:
4884  * stat.grpowned? -> true or false
4885  *
4886  * Returns true if the effective group id of the process is the same as
4887  * the group id of <i>stat</i>. On Windows NT, returns <code>false</code>.
4888  *
4889  * File.stat("testfile").grpowned? #=> true
4890  * File.stat("/etc/passwd").grpowned? #=> false
4891  *
4892  */
4893 
4894 static VALUE
4896 {
4897 #ifndef _WIN32
4898  if (rb_group_member(get_stat(obj)->st_gid)) return Qtrue;
4899 #endif
4900  return Qfalse;
4901 }
4902 
4903 /*
4904  * call-seq:
4905  * stat.readable? -> true or false
4906  *
4907  * Returns <code>true</code> if <i>stat</i> is readable by the
4908  * effective user id of this process.
4909  *
4910  * File.stat("testfile").readable? #=> true
4911  *
4912  */
4913 
4914 static VALUE
4916 {
4917  struct stat *st = get_stat(obj);
4918 
4919 #ifdef USE_GETEUID
4920  if (geteuid() == 0) return Qtrue;
4921 #endif
4922 #ifdef S_IRUSR
4923  if (rb_stat_owned(obj))
4924  return st->st_mode & S_IRUSR ? Qtrue : Qfalse;
4925 #endif
4926 #ifdef S_IRGRP
4927  if (rb_stat_grpowned(obj))
4928  return st->st_mode & S_IRGRP ? Qtrue : Qfalse;
4929 #endif
4930 #ifdef S_IROTH
4931  if (!(st->st_mode & S_IROTH)) return Qfalse;
4932 #endif
4933  return Qtrue;
4934 }
4935 
4936 /*
4937  * call-seq:
4938  * stat.readable_real? -> true or false
4939  *
4940  * Returns <code>true</code> if <i>stat</i> is readable by the real
4941  * user id of this process.
4942  *
4943  * File.stat("testfile").readable_real? #=> true
4944  *
4945  */
4946 
4947 static VALUE
4949 {
4950  struct stat *st = get_stat(obj);
4951 
4952 #ifdef USE_GETEUID
4953  if (getuid() == 0) return Qtrue;
4954 #endif
4955 #ifdef S_IRUSR
4956  if (rb_stat_rowned(obj))
4957  return st->st_mode & S_IRUSR ? Qtrue : Qfalse;
4958 #endif
4959 #ifdef S_IRGRP
4960  if (rb_group_member(get_stat(obj)->st_gid))
4961  return st->st_mode & S_IRGRP ? Qtrue : Qfalse;
4962 #endif
4963 #ifdef S_IROTH
4964  if (!(st->st_mode & S_IROTH)) return Qfalse;
4965 #endif
4966  return Qtrue;
4967 }
4968 
4969 /*
4970  * call-seq:
4971  * stat.world_readable? -> fixnum or nil
4972  *
4973  * If <i>stat</i> is readable by others, returns an integer
4974  * representing the file permission bits of <i>stat</i>. Returns
4975  * <code>nil</code> otherwise. The meaning of the bits is platform
4976  * dependent; on Unix systems, see <code>stat(2)</code>.
4977  *
4978  * m = File.stat("/etc/passwd").world_readable? #=> 420
4979  * sprintf("%o", m) #=> "644"
4980  */
4981 
4982 static VALUE
4984 {
4985 #ifdef S_IROTH
4986  if ((get_stat(obj)->st_mode & (S_IROTH)) == S_IROTH) {
4987  return UINT2NUM(get_stat(obj)->st_mode & (S_IRUGO|S_IWUGO|S_IXUGO));
4988  }
4989  else {
4990  return Qnil;
4991  }
4992 #endif
4993 }
4994 
4995 /*
4996  * call-seq:
4997  * stat.writable? -> true or false
4998  *
4999  * Returns <code>true</code> if <i>stat</i> is writable by the
5000  * effective user id of this process.
5001  *
5002  * File.stat("testfile").writable? #=> true
5003  *
5004  */
5005 
5006 static VALUE
5008 {
5009  struct stat *st = get_stat(obj);
5010 
5011 #ifdef USE_GETEUID
5012  if (geteuid() == 0) return Qtrue;
5013 #endif
5014 #ifdef S_IWUSR
5015  if (rb_stat_owned(obj))
5016  return st->st_mode & S_IWUSR ? Qtrue : Qfalse;
5017 #endif
5018 #ifdef S_IWGRP
5019  if (rb_stat_grpowned(obj))
5020  return st->st_mode & S_IWGRP ? Qtrue : Qfalse;
5021 #endif
5022 #ifdef S_IWOTH
5023  if (!(st->st_mode & S_IWOTH)) return Qfalse;
5024 #endif
5025  return Qtrue;
5026 }
5027 
5028 /*
5029  * call-seq:
5030  * stat.writable_real? -> true or false
5031  *
5032  * Returns <code>true</code> if <i>stat</i> is writable by the real
5033  * user id of this process.
5034  *
5035  * File.stat("testfile").writable_real? #=> true
5036  *
5037  */
5038 
5039 static VALUE
5041 {
5042  struct stat *st = get_stat(obj);
5043 
5044 #ifdef USE_GETEUID
5045  if (getuid() == 0) return Qtrue;
5046 #endif
5047 #ifdef S_IWUSR
5048  if (rb_stat_rowned(obj))
5049  return st->st_mode & S_IWUSR ? Qtrue : Qfalse;
5050 #endif
5051 #ifdef S_IWGRP
5052  if (rb_group_member(get_stat(obj)->st_gid))
5053  return st->st_mode & S_IWGRP ? Qtrue : Qfalse;
5054 #endif
5055 #ifdef S_IWOTH
5056  if (!(st->st_mode & S_IWOTH)) return Qfalse;
5057 #endif
5058  return Qtrue;
5059 }
5060 
5061 /*
5062  * call-seq:
5063  * stat.world_writable? -> fixnum or nil
5064  *
5065  * If <i>stat</i> is writable by others, returns an integer
5066  * representing the file permission bits of <i>stat</i>. Returns
5067  * <code>nil</code> otherwise. The meaning of the bits is platform
5068  * dependent; on Unix systems, see <code>stat(2)</code>.
5069  *
5070  * m = File.stat("/tmp").world_writable? #=> 511
5071  * sprintf("%o", m) #=> "777"
5072  */
5073 
5074 static VALUE
5076 {
5077 #ifdef S_IROTH
5078  if ((get_stat(obj)->st_mode & (S_IWOTH)) == S_IWOTH) {
5079  return UINT2NUM(get_stat(obj)->st_mode & (S_IRUGO|S_IWUGO|S_IXUGO));
5080  }
5081  else {
5082  return Qnil;
5083  }
5084 #endif
5085 }
5086 
5087 /*
5088  * call-seq:
5089  * stat.executable? -> true or false
5090  *
5091  * Returns <code>true</code> if <i>stat</i> is executable or if the
5092  * operating system doesn't distinguish executable files from
5093  * nonexecutable files. The tests are made using the effective owner of
5094  * the process.
5095  *
5096  * File.stat("testfile").executable? #=> false
5097  *
5098  */
5099 
5100 static VALUE
5102 {
5103  struct stat *st = get_stat(obj);
5104 
5105 #ifdef USE_GETEUID
5106  if (geteuid() == 0) {
5107  return st->st_mode & S_IXUGO ? Qtrue : Qfalse;
5108  }
5109 #endif
5110 #ifdef S_IXUSR
5111  if (rb_stat_owned(obj))
5112  return st->st_mode & S_IXUSR ? Qtrue : Qfalse;
5113 #endif
5114 #ifdef S_IXGRP
5115  if (rb_stat_grpowned(obj))
5116  return st->st_mode & S_IXGRP ? Qtrue : Qfalse;
5117 #endif
5118 #ifdef S_IXOTH
5119  if (!(st->st_mode & S_IXOTH)) return Qfalse;
5120 #endif
5121  return Qtrue;
5122 }
5123 
5124 /*
5125  * call-seq:
5126  * stat.executable_real? -> true or false
5127  *
5128  * Same as <code>executable?</code>, but tests using the real owner of
5129  * the process.
5130  */
5131 
5132 static VALUE
5134 {
5135  struct stat *st = get_stat(obj);
5136 
5137 #ifdef USE_GETEUID
5138  if (getuid() == 0) {
5139  return st->st_mode & S_IXUGO ? Qtrue : Qfalse;
5140  }
5141 #endif
5142 #ifdef S_IXUSR
5143  if (rb_stat_rowned(obj))
5144  return st->st_mode & S_IXUSR ? Qtrue : Qfalse;
5145 #endif
5146 #ifdef S_IXGRP
5147  if (rb_group_member(get_stat(obj)->st_gid))
5148  return st->st_mode & S_IXGRP ? Qtrue : Qfalse;
5149 #endif
5150 #ifdef S_IXOTH
5151  if (!(st->st_mode & S_IXOTH)) return Qfalse;
5152 #endif
5153  return Qtrue;
5154 }
5155 
5156 /*
5157  * call-seq:
5158  * stat.file? -> true or false
5159  *
5160  * Returns <code>true</code> if <i>stat</i> is a regular file (not
5161  * a device file, pipe, socket, etc.).
5162  *
5163  * File.stat("testfile").file? #=> true
5164  *
5165  */
5166 
5167 static VALUE
5169 {
5170  if (S_ISREG(get_stat(obj)->st_mode)) return Qtrue;
5171  return Qfalse;
5172 }
5173 
5174 /*
5175  * call-seq:
5176  * stat.zero? -> true or false
5177  *
5178  * Returns <code>true</code> if <i>stat</i> is a zero-length file;
5179  * <code>false</code> otherwise.
5180  *
5181  * File.stat("testfile").zero? #=> false
5182  *
5183  */
5184 
5185 static VALUE
5187 {
5188  if (get_stat(obj)->st_size == 0) return Qtrue;
5189  return Qfalse;
5190 }
5191 
5192 /*
5193  * call-seq:
5194  * state.size -> integer
5195  *
5196  * Returns the size of <i>stat</i> in bytes.
5197  *
5198  * File.stat("testfile").size #=> 66
5199  *
5200  */
5201 
5202 static VALUE
5204 {
5205  off_t size = get_stat(obj)->st_size;
5206 
5207  if (size == 0) return Qnil;
5208  return OFFT2NUM(size);
5209 }
5210 
5211 /*
5212  * call-seq:
5213  * stat.setuid? -> true or false
5214  *
5215  * Returns <code>true</code> if <i>stat</i> has the set-user-id
5216  * permission bit set, <code>false</code> if it doesn't or if the
5217  * operating system doesn't support this feature.
5218  *
5219  * File.stat("/bin/su").setuid? #=> true
5220  */
5221 
5222 static VALUE
5224 {
5225 #ifdef S_ISUID
5226  if (get_stat(obj)->st_mode & S_ISUID) return Qtrue;
5227 #endif
5228  return Qfalse;
5229 }
5230 
5231 /*
5232  * call-seq:
5233  * stat.setgid? -> true or false
5234  *
5235  * Returns <code>true</code> if <i>stat</i> has the set-group-id
5236  * permission bit set, <code>false</code> if it doesn't or if the
5237  * operating system doesn't support this feature.
5238  *
5239  * File.stat("/usr/sbin/lpc").setgid? #=> true
5240  *
5241  */
5242 
5243 static VALUE
5245 {
5246 #ifdef S_ISGID
5247  if (get_stat(obj)->st_mode & S_ISGID) return Qtrue;
5248 #endif
5249  return Qfalse;
5250 }
5251 
5252 /*
5253  * call-seq:
5254  * stat.sticky? -> true or false
5255  *
5256  * Returns <code>true</code> if <i>stat</i> has its sticky bit set,
5257  * <code>false</code> if it doesn't or if the operating system doesn't
5258  * support this feature.
5259  *
5260  * File.stat("testfile").sticky? #=> false
5261  *
5262  */
5263 
5264 static VALUE
5266 {
5267 #ifdef S_ISVTX
5268  if (get_stat(obj)->st_mode & S_ISVTX) return Qtrue;
5269 #endif
5270  return Qfalse;
5271 }
5272 
5274 
5275 void
5276 rb_file_const(const char *name, VALUE value)
5277 {
5278  rb_define_const(rb_mFConst, name, value);
5279 }
5280 
5281 int
5282 rb_is_absolute_path(const char *path)
5283 {
5284 #ifdef DOSISH_DRIVE_LETTER
5285  if (has_drive_letter(path) && isdirsep(path[2])) return 1;
5286 #endif
5287 #ifdef DOSISH_UNC
5288  if (isdirsep(path[0]) && isdirsep(path[1])) return 1;
5289 #endif
5290 #ifndef DOSISH
5291  if (path[0] == '/') return 1;
5292 #endif
5293  return 0;
5294 }
5295 
5296 #ifndef ENABLE_PATH_CHECK
5297 # if defined DOSISH || defined __CYGWIN__
5298 # define ENABLE_PATH_CHECK 0
5299 # else
5300 # define ENABLE_PATH_CHECK 1
5301 # endif
5302 #endif
5303 
5304 #if ENABLE_PATH_CHECK
5305 static int
5306 path_check_0(VALUE path, int execpath)
5307 {
5308  struct stat st;
5309  const char *p0 = StringValueCStr(path);
5310  const char *e0;
5311  rb_encoding *enc;
5312  char *p = 0, *s;
5313 
5314  if (!rb_is_absolute_path(p0)) {
5315  char *buf = my_getcwd();
5316  VALUE newpath;
5317 
5318  newpath = rb_str_new2(buf);
5319  xfree(buf);
5320 
5321  rb_str_cat2(newpath, "/");
5322  rb_str_cat2(newpath, p0);
5323  path = newpath;
5324  p0 = RSTRING_PTR(path);
5325  }
5326  e0 = p0 + RSTRING_LEN(path);
5327  enc = rb_enc_get(path);
5328  for (;;) {
5329 #ifndef S_IWOTH
5330 # define S_IWOTH 002
5331 #endif
5332  if (STAT(p0, &st) == 0 && S_ISDIR(st.st_mode) && (st.st_mode & S_IWOTH)
5333 #ifdef S_ISVTX
5334  && !(p && execpath && (st.st_mode & S_ISVTX))
5335 #endif
5336  && !access(p0, W_OK)) {
5337  rb_warn("Insecure world writable dir %s in %sPATH, mode 0%"
5338  PRI_MODET_PREFIX"o",
5339  p0, (execpath ? "" : "LOAD_"), st.st_mode);
5340  if (p) *p = '/';
5341  RB_GC_GUARD(path);
5342  return 0;
5343  }
5344  s = strrdirsep(p0, e0, enc);
5345  if (p) *p = '/';
5346  if (!s || s == p0) return 1;
5347  p = s;
5348  e0 = p;
5349  *p = '\0';
5350  }
5351 }
5352 #endif
5353 
5354 #if ENABLE_PATH_CHECK
5355 #define fpath_check(path) path_check_0((path), FALSE)
5356 #else
5357 #define fpath_check(path) 1
5358 #endif
5359 
5360 int
5361 rb_path_check(const char *path)
5362 {
5363 #if ENABLE_PATH_CHECK
5364  const char *p0, *p, *pend;
5365  const char sep = PATH_SEP_CHAR;
5366 
5367  if (!path) return 1;
5368 
5369  pend = path + strlen(path);
5370  p0 = path;
5371  p = strchr(path, sep);
5372  if (!p) p = pend;
5373 
5374  for (;;) {
5375  if (!path_check_0(rb_str_new(p0, p - p0), TRUE)) {
5376  return 0; /* not safe */
5377  }
5378  p0 = p + 1;
5379  if (p0 > pend) break;
5380  p = strchr(p0, sep);
5381  if (!p) p = pend;
5382  }
5383 #endif
5384  return 1;
5385 }
5386 
5387 #ifndef _WIN32
5388 static void *
5389 loadopen_func(void *arg)
5390 {
5391  return (void *)(VALUE)rb_cloexec_open((const char *)arg, O_RDONLY, 0);
5392 }
5393 
5394 #ifdef __native_client__
5395 __attribute__((noinline))
5396 #endif
5397 int
5398 rb_file_load_ok(const char *path)
5399 {
5400  int ret = 1;
5401  int fd;
5402 
5403  fd = (int)(VALUE)rb_thread_call_without_gvl(loadopen_func, (void *)path, RUBY_UBF_IO, 0);
5404  if (fd == -1) return 0;
5405  rb_update_max_fd(fd);
5406 #if !defined DOSISH
5407  {
5408  struct stat st;
5409  if (fstat(fd, &st) || !S_ISREG(st.st_mode)) {
5410  ret = 0;
5411  }
5412  }
5413 #endif
5414  (void)close(fd);
5415  return ret;
5416 }
5417 #endif
5418 
5419 static int
5420 is_explicit_relative(const char *path)
5421 {
5422  if (*path++ != '.') return 0;
5423  if (*path == '.') path++;
5424  return isdirsep(*path);
5425 }
5426 
5427 static VALUE
5429 {
5430  str_shrink(path);
5431  RBASIC_SET_CLASS(path, rb_obj_class(orig));
5432  OBJ_FREEZE(path);
5433  return path;
5434 }
5435 
5436 int
5437 rb_find_file_ext(VALUE *filep, const char *const *ext)
5438 {
5439  return rb_find_file_ext_safe(filep, ext, rb_safe_level());
5440 }
5441 
5442 int
5443 rb_find_file_ext_safe(VALUE *filep, const char *const *ext, int safe_level)
5444 {
5445  const char *f = StringValueCStr(*filep);
5446  VALUE fname = *filep, load_path, tmp;
5447  long i, j, fnlen;
5448  int expanded = 0;
5449 
5450  if (!ext[0]) return 0;
5451 
5452  if (f[0] == '~') {
5453  fname = file_expand_path_1(fname);
5454  if (safe_level >= 1 && OBJ_TAINTED(fname)) {
5455  rb_raise(rb_eSecurityError, "loading from unsafe file %s", f);
5456  }
5457  f = RSTRING_PTR(fname);
5458  *filep = fname;
5459  expanded = 1;
5460  }
5461 
5462  if (expanded || rb_is_absolute_path(f) || is_explicit_relative(f)) {
5463  if (safe_level >= 1 && !fpath_check(fname)) {
5464  rb_raise(rb_eSecurityError, "loading from unsafe path %s", f);
5465  }
5466  if (!expanded) fname = file_expand_path_1(fname);
5467  fnlen = RSTRING_LEN(fname);
5468  for (i=0; ext[i]; i++) {
5469  rb_str_cat2(fname, ext[i]);
5470  if (rb_file_load_ok(RSTRING_PTR(fname))) {
5471  *filep = copy_path_class(fname, *filep);
5472  return (int)(i+1);
5473  }
5474  rb_str_set_len(fname, fnlen);
5475  }
5476  return 0;
5477  }
5478 
5479  RB_GC_GUARD(load_path) = rb_get_expanded_load_path();
5480  if (!load_path) return 0;
5481 
5482  fname = rb_str_dup(*filep);
5483  RBASIC_CLEAR_CLASS(fname);
5484  fnlen = RSTRING_LEN(fname);
5485  tmp = rb_str_tmp_new(MAXPATHLEN + 2);
5487  for (j=0; ext[j]; j++) {
5488  rb_str_cat2(fname, ext[j]);
5489  for (i = 0; i < RARRAY_LEN(load_path); i++) {
5490  VALUE str = RARRAY_AREF(load_path, i);
5491 
5492  RB_GC_GUARD(str) = rb_get_path_check(str, safe_level);
5493  if (RSTRING_LEN(str) == 0) continue;
5494  rb_file_expand_path_internal(fname, str, 0, 0, tmp);
5495  if (rb_file_load_ok(RSTRING_PTR(tmp))) {
5496  *filep = copy_path_class(tmp, *filep);
5497  return (int)(j+1);
5498  }
5499  FL_UNSET(tmp, FL_TAINT);
5500  }
5501  rb_str_set_len(fname, fnlen);
5502  }
5503  RB_GC_GUARD(load_path);
5504  return 0;
5505 }
5506 
5507 VALUE
5509 {
5510  return rb_find_file_safe(path, rb_safe_level());
5511 }
5512 
5513 VALUE
5514 rb_find_file_safe(VALUE path, int safe_level)
5515 {
5516  VALUE tmp, load_path;
5517  const char *f = StringValueCStr(path);
5518  int expanded = 0;
5519 
5520  if (f[0] == '~') {
5521  tmp = file_expand_path_1(path);
5522  if (safe_level >= 1 && OBJ_TAINTED(tmp)) {
5523  rb_raise(rb_eSecurityError, "loading from unsafe file %s", f);
5524  }
5525  path = copy_path_class(tmp, path);
5526  f = RSTRING_PTR(path);
5527  expanded = 1;
5528  }
5529 
5530  if (expanded || rb_is_absolute_path(f) || is_explicit_relative(f)) {
5531  if (safe_level >= 1 && !fpath_check(path)) {
5532  rb_raise(rb_eSecurityError, "loading from unsafe path %s", f);
5533  }
5534  if (!rb_file_load_ok(f)) return 0;
5535  if (!expanded)
5536  path = copy_path_class(file_expand_path_1(path), path);
5537  return path;
5538  }
5539 
5540  RB_GC_GUARD(load_path) = rb_get_expanded_load_path();
5541  if (load_path) {
5542  long i;
5543 
5544  tmp = rb_str_tmp_new(MAXPATHLEN + 2);
5546  for (i = 0; i < RARRAY_LEN(load_path); i++) {
5547  VALUE str = RARRAY_AREF(load_path, i);
5548  RB_GC_GUARD(str) = rb_get_path_check(str, safe_level);
5549  if (RSTRING_LEN(str) > 0) {
5550  rb_file_expand_path_internal(path, str, 0, 0, tmp);
5551  f = RSTRING_PTR(tmp);
5552  if (rb_file_load_ok(f)) goto found;
5553  }
5554  }
5555  return 0;
5556  }
5557  else {
5558  return 0; /* no path, no load */
5559  }
5560 
5561  found:
5562  if (safe_level >= 1 && !fpath_check(tmp)) {
5563  rb_raise(rb_eSecurityError, "loading from unsafe file %s", f);
5564  }
5565 
5566  return copy_path_class(tmp, path);
5567 }
5568 
5569 static void
5571 {
5574 }
5575 
5576 static const char null_device[] =
5577 #if defined DOSISH
5578  "NUL"
5579 #elif defined AMIGA || defined __amigaos__
5580  "NIL"
5581 #elif defined __VMS
5582  "NL:"
5583 #else
5584  "/dev/null"
5585 #endif
5586  ;
5587 
5588 /*
5589  * A <code>File</code> is an abstraction of any file object accessible
5590  * by the program and is closely associated with class <code>IO</code>
5591  * <code>File</code> includes the methods of module
5592  * <code>FileTest</code> as class methods, allowing you to write (for
5593  * example) <code>File.exist?("foo")</code>.
5594  *
5595  * In the description of File methods,
5596  * <em>permission bits</em> are a platform-specific
5597  * set of bits that indicate permissions of a file. On Unix-based
5598  * systems, permissions are viewed as a set of three octets, for the
5599  * owner, the group, and the rest of the world. For each of these
5600  * entities, permissions may be set to read, write, or execute the
5601  * file:
5602  *
5603  * The permission bits <code>0644</code> (in octal) would thus be
5604  * interpreted as read/write for owner, and read-only for group and
5605  * other. Higher-order bits may also be used to indicate the type of
5606  * file (plain, directory, pipe, socket, and so on) and various other
5607  * special features. If the permissions are for a directory, the
5608  * meaning of the execute bit changes; when set the directory can be
5609  * searched.
5610  *
5611  * On non-Posix operating systems, there may be only the ability to
5612  * make a file read-only or read-write. In this case, the remaining
5613  * permission bits will be synthesized to resemble typical values. For
5614  * instance, on Windows NT the default permission bits are
5615  * <code>0644</code>, which means read/write for owner, read-only for
5616  * all others. The only change that can be made is to make the file
5617  * read-only, which is reported as <code>0444</code>.
5618  *
5619  * Various constants for the methods in File can be found in File::Constants.
5620  */
5621 
5622 void
5624 {
5625  rb_mFileTest = rb_define_module("FileTest");
5626  rb_cFile = rb_define_class("File", rb_cIO);
5627 
5632  define_filetest_function("readable_real?", rb_file_readable_real_p, 1);
5633  define_filetest_function("world_readable?", rb_file_world_readable_p, 1);
5635  define_filetest_function("writable_real?", rb_file_writable_real_p, 1);
5636  define_filetest_function("world_writable?", rb_file_world_writable_p, 1);
5638  define_filetest_function("executable_real?", rb_file_executable_real_p, 1);
5645 
5649 
5652 
5656 
5658 
5662 
5666 
5672 
5676 
5690 
5692  /* separates directory parts in path */
5693  rb_define_const(rb_cFile, "Separator", separator);
5694  rb_define_const(rb_cFile, "SEPARATOR", separator);
5697 
5698 #ifdef DOSISH
5699  /* platform specific alternative separator */
5700  rb_define_const(rb_cFile, "ALT_SEPARATOR", rb_obj_freeze(rb_usascii_str_new2(file_alt_separator)));
5701 #else
5702  rb_define_const(rb_cFile, "ALT_SEPARATOR", Qnil);
5703 #endif
5704  /* path list separator */
5706 
5707  rb_define_method(rb_cIO, "stat", rb_io_stat, 0); /* this is IO's method */
5708  rb_define_method(rb_cFile, "lstat", rb_file_lstat, 0);
5709 
5710  rb_define_method(rb_cFile, "atime", rb_file_atime, 0);
5711  rb_define_method(rb_cFile, "mtime", rb_file_mtime, 0);
5712  rb_define_method(rb_cFile, "ctime", rb_file_ctime, 0);
5713  rb_define_method(rb_cFile, "size", rb_file_size, 0);
5714 
5715  rb_define_method(rb_cFile, "chmod", rb_file_chmod, 1);
5716  rb_define_method(rb_cFile, "chown", rb_file_chown, 2);
5717  rb_define_method(rb_cFile, "truncate", rb_file_truncate, 1);
5718 
5719  rb_define_method(rb_cFile, "flock", rb_file_flock, 1);
5720 
5721  /*
5722  * Document-module: File::Constants
5723  *
5724  * File::Constants provides file-related constants. All possible
5725  * file constants are listed in the documentation but they may not all
5726  * be present on your platform.
5727  *
5728  * If the underlying platform doesn't define a constant the corresponding
5729  * Ruby constant is not defined.
5730  *
5731  * Your platform documentations (e.g. man open(2)) may describe more
5732  * detailed information.
5733  */
5734  rb_mFConst = rb_define_module_under(rb_cFile, "Constants");
5736 
5737  /* open for reading only */
5738  rb_define_const(rb_mFConst, "RDONLY", INT2FIX(O_RDONLY));
5739  /* open for writing only */
5740  rb_define_const(rb_mFConst, "WRONLY", INT2FIX(O_WRONLY));
5741  /* open for reading and writing */
5742  rb_define_const(rb_mFConst, "RDWR", INT2FIX(O_RDWR));
5743  /* append on each write */
5744  rb_define_const(rb_mFConst, "APPEND", INT2FIX(O_APPEND));
5745  /* create file if it does not exist */
5746  rb_define_const(rb_mFConst, "CREAT", INT2FIX(O_CREAT));
5747  /* error if CREAT and the file exists */
5748  rb_define_const(rb_mFConst, "EXCL", INT2FIX(O_EXCL));
5749 #if defined(O_NDELAY) || defined(O_NONBLOCK)
5750 # ifndef O_NONBLOCK
5751 # define O_NONBLOCK O_NDELAY
5752 # endif
5753  /* do not block on open or for data to become available */
5755 #endif
5756  /* truncate size to 0 */
5757  rb_define_const(rb_mFConst, "TRUNC", INT2FIX(O_TRUNC));
5758 #ifdef O_NOCTTY
5759  /* not to make opened IO the controlling terminal device */
5760  rb_define_const(rb_mFConst, "NOCTTY", INT2FIX(O_NOCTTY));
5761 #endif
5762 #ifndef O_BINARY
5763 # define O_BINARY 0
5764 #endif
5765  /* disable line code conversion */
5767 #ifdef O_SYNC
5768  /* any write operation perform synchronously */
5769  rb_define_const(rb_mFConst, "SYNC", INT2FIX(O_SYNC));
5770 #endif
5771 #ifdef O_DSYNC
5772  /* any write operation perform synchronously except some meta data */
5773  rb_define_const(rb_mFConst, "DSYNC", INT2FIX(O_DSYNC));
5774 #endif
5775 #ifdef O_RSYNC
5776  /* any read operation perform synchronously. used with SYNC or DSYNC. */
5777  rb_define_const(rb_mFConst, "RSYNC", INT2FIX(O_RSYNC));
5778 #endif
5779 #ifdef O_NOFOLLOW
5780  /* do not follow symlinks */
5781  rb_define_const(rb_mFConst, "NOFOLLOW", INT2FIX(O_NOFOLLOW)); /* FreeBSD, Linux */
5782 #endif
5783 #ifdef O_NOATIME
5784  /* do not change atime */
5785  rb_define_const(rb_mFConst, "NOATIME", INT2FIX(O_NOATIME)); /* Linux */
5786 #endif
5787 #ifdef O_DIRECT
5788  /* Try to minimize cache effects of the I/O to and from this file. */
5789  rb_define_const(rb_mFConst, "DIRECT", INT2FIX(O_DIRECT));
5790 #endif
5791 
5792  /* shared lock. see File#flock */
5793  rb_define_const(rb_mFConst, "LOCK_SH", INT2FIX(LOCK_SH));
5794  /* exclusive lock. see File#flock */
5795  rb_define_const(rb_mFConst, "LOCK_EX", INT2FIX(LOCK_EX));
5796  /* unlock. see File#flock */
5797  rb_define_const(rb_mFConst, "LOCK_UN", INT2FIX(LOCK_UN));
5798  /* non-blocking lock. used with LOCK_SH or LOCK_EX. see File#flock */
5799  rb_define_const(rb_mFConst, "LOCK_NB", INT2FIX(LOCK_NB));
5800 
5801  /* Name of the null device */
5803 
5804  rb_define_method(rb_cFile, "path", rb_file_path, 0);
5805  rb_define_method(rb_cFile, "to_path", rb_file_path, 0);
5806  rb_define_global_function("test", rb_f_test, -1);
5807 
5810  rb_define_method(rb_cStat, "initialize", rb_stat_init, 1);
5811  rb_define_method(rb_cStat, "initialize_copy", rb_stat_init_copy, 1);
5812 
5814 
5816 
5818  rb_define_method(rb_cStat, "dev_major", rb_stat_dev_major, 0);
5819  rb_define_method(rb_cStat, "dev_minor", rb_stat_dev_minor, 0);
5821  rb_define_method(rb_cStat, "mode", rb_stat_mode, 0);
5822  rb_define_method(rb_cStat, "nlink", rb_stat_nlink, 0);
5825  rb_define_method(rb_cStat, "rdev", rb_stat_rdev, 0);
5826  rb_define_method(rb_cStat, "rdev_major", rb_stat_rdev_major, 0);
5827  rb_define_method(rb_cStat, "rdev_minor", rb_stat_rdev_minor, 0);
5828  rb_define_method(rb_cStat, "size", rb_stat_size, 0);
5829  rb_define_method(rb_cStat, "blksize", rb_stat_blksize, 0);
5830  rb_define_method(rb_cStat, "blocks", rb_stat_blocks, 0);
5831  rb_define_method(rb_cStat, "atime", rb_stat_atime, 0);
5832  rb_define_method(rb_cStat, "mtime", rb_stat_mtime, 0);
5833  rb_define_method(rb_cStat, "ctime", rb_stat_ctime, 0);
5834 
5835  rb_define_method(rb_cStat, "inspect", rb_stat_inspect, 0);
5836 
5837  rb_define_method(rb_cStat, "ftype", rb_stat_ftype, 0);
5838 
5839  rb_define_method(rb_cStat, "directory?", rb_stat_d, 0);
5840  rb_define_method(rb_cStat, "readable?", rb_stat_r, 0);
5841  rb_define_method(rb_cStat, "readable_real?", rb_stat_R, 0);
5842  rb_define_method(rb_cStat, "world_readable?", rb_stat_wr, 0);
5843  rb_define_method(rb_cStat, "writable?", rb_stat_w, 0);
5844  rb_define_method(rb_cStat, "writable_real?", rb_stat_W, 0);
5845  rb_define_method(rb_cStat, "world_writable?", rb_stat_ww, 0);
5846  rb_define_method(rb_cStat, "executable?", rb_stat_x, 0);
5847  rb_define_method(rb_cStat, "executable_real?", rb_stat_X, 0);
5848  rb_define_method(rb_cStat, "file?", rb_stat_f, 0);
5849  rb_define_method(rb_cStat, "zero?", rb_stat_z, 0);
5850  rb_define_method(rb_cStat, "size?", rb_stat_s, 0);
5851  rb_define_method(rb_cStat, "owned?", rb_stat_owned, 0);
5852  rb_define_method(rb_cStat, "grpowned?", rb_stat_grpowned, 0);
5853 
5854  rb_define_method(rb_cStat, "pipe?", rb_stat_p, 0);
5855  rb_define_method(rb_cStat, "symlink?", rb_stat_l, 0);
5856  rb_define_method(rb_cStat, "socket?", rb_stat_S, 0);
5857 
5858  rb_define_method(rb_cStat, "blockdev?", rb_stat_b, 0);
5859  rb_define_method(rb_cStat, "chardev?", rb_stat_c, 0);
5860 
5861  rb_define_method(rb_cStat, "setuid?", rb_stat_suid, 0);
5862  rb_define_method(rb_cStat, "setgid?", rb_stat_sgid, 0);
5863  rb_define_method(rb_cStat, "sticky?", rb_stat_sticky, 0);
5864 }
RUBY_EXTERN VALUE rb_cString
Definition: ruby.h:1591
static VALUE rb_file_exists_p(VALUE obj, VALUE fname)
Definition: file.c:1403
#define RBASIC_CLEAR_CLASS(obj)
Definition: internal.h:609
static VALUE rb_stat_ino(VALUE self)
Definition: file.c:511
VALUE rb_get_path_check_convert(VALUE obj, VALUE tmp, int level)
Definition: file.c:199
#define NUM2UIDT(v)
Definition: ruby.h:330
VALUE rb_get_path(VALUE obj)
Definition: file.c:226
#define O_BINARY
#define isdirsep(x)
Definition: file.c:2754
#define MBCLEN_CHARFOUND_P(ret)
Definition: encoding.h:139
rb_encoding * rb_enc_check(VALUE str1, VALUE str2)
Definition: encoding.c:838
#define rb_str_new4
Definition: intern.h:842
static VALUE rb_file_socket_p(VALUE obj, VALUE fname)
Definition: file.c:1302
#define X_OK
Definition: file.h:18
#define MBCLEN_CHARFOUND_LEN(ret)
Definition: encoding.h:140
static VALUE rb_file_s_mtime(VALUE klass, VALUE fname)
Definition: file.c:1998
#define rb_file_s_lchown
Definition: file.c:2364
#define RARRAY_LEN(a)
Definition: ruby.h:878
#define S_IRGRP
Definition: win32.h:416
#define rb_enc_mbc_to_codepoint(p, e, enc)
Definition: encoding.h:156
static VALUE stat_mtime(struct stat *st)
Definition: file.c:756
void rb_enc_copy(VALUE obj1, VALUE obj2)
Definition: encoding.c:916
#define FALSE
Definition: nkf.h:174
#define RUBY_TYPED_FREE_IMMEDIATELY
Definition: ruby.h:1015
#define tail
Definition: st.c:108
static VALUE rb_file_sgid_p(VALUE obj, VALUE fname)
Definition: file.c:1752
static struct timespec stat_atimespec(struct stat *st)
Definition: file.c:715
size_t strlen(const char *)
#define INT2NUM(x)
Definition: ruby.h:1296
static VALUE rb_get_path_check(VALUE obj, int level)
Definition: file.c:213
static VALUE rb_stat_z(VALUE obj)
Definition: file.c:5186
void rb_update_max_fd(int fd)
Definition: io.c:183
#define rb_file_s_link
Definition: file.c:2550
static VALUE rb_stat_init(VALUE obj, VALUE fname)
Definition: file.c:4668
VALUE rb_time_nano_new(time_t, long)
Definition: time.c:2305
static VALUE rb_file_executable_p(VALUE obj, VALUE fname)
Definition: file.c:1567
int minor
Definition: tcltklib.c:111
static VALUE rb_stat_rdev(VALUE self)
Definition: file.c:602
#define DEVT2NUM(v)
Definition: file.c:436
static VALUE rb_stat_cmp(VALUE self, VALUE other)
Definition: file.c:414
#define NUM2INT(x)
Definition: ruby.h:630
int rb_is_absolute_path(const char *path)
Definition: file.c:5282
static VALUE rb_stat_init_copy(VALUE copy, VALUE orig)
Definition: file.c:4691
rb_uid_t getuid(void)
Definition: win32.c:2498
static VALUE rb_file_grpowned_p(VALUE obj, VALUE fname)
Definition: file.c:1701
void rb_define_singleton_method(VALUE obj, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a singleton method for obj.
Definition: class.c:1646
#define skipprefix(path, end, enc)
Definition: file.c:2858
#define access(path, mode)
Definition: win32.h:218
static VALUE rb_file_size_p(VALUE obj, VALUE fname)
Definition: file.c:1649
#define expand_path(fname, dname, abs_mode, long_name, result)
Definition: file.c:3408
static void * loadopen_func(void *arg)
Definition: file.c:5389
#define FilePathValue(v)
Definition: ruby.h:560
static VALUE rb_file_s_size(VALUE klass, VALUE fname)
Definition: file.c:1855
#define rb_usascii_str_new2
Definition: intern.h:846
#define FL_TAINT
Definition: ruby.h:1137
int rb_cloexec_open(const char *pathname, int flags, mode_t mode)
Definition: io.c:228
void rb_file_const(const char *name, VALUE value)
Definition: file.c:5276
VALUE rb_str_cat(VALUE, const char *, long)
Definition: string.c:2139
static VALUE rb_f_test(int argc, VALUE *argv)
Definition: file.c:4500
static VALUE rb_stat_mode(VALUE self)
Definition: file.c:534
int rb_find_file_ext(VALUE *filep, const char *const *ext)
Definition: file.c:5437
#define Qtrue
Definition: ruby.h:426
static VALUE rb_file_world_writable_p(VALUE obj, VALUE fname)
Definition: file.c:1545
static VALUE rb_file_readable_p(VALUE obj, VALUE fname)
Definition: file.c:1427
static VALUE rb_stat_f(VALUE obj)
Definition: file.c:5168
Definition: io.h:61
#define TypedData_Wrap_Struct(klass, data_type, sval)
Definition: ruby.h:1027
#define OBJ_INIT_COPY(obj, orig)
Definition: intern.h:287
void rb_io_check_initialized(rb_io_t *)
Definition: io.c:609
#define TypedData_Get_Struct(obj, type, data_type, sval)
Definition: ruby.h:1041
#define FMODE_WRITABLE
Definition: io.h:102
VALUE rb_get_path_check_to_string(VALUE obj, int level)
Definition: file.c:177
const struct timespec * tsp
Definition: file.c:2368
#define ENC_CODERANGE_CLEAR(obj)
Definition: encoding.h:56
long tv_sec
Definition: ossl_asn1.c:17
VALUE rb_enc_from_encoding(rb_encoding *encoding)
Definition: encoding.c:102
SOCKET rb_w32_get_osfhandle(int)
Definition: win32.c:988
VALUE rb_eTypeError
Definition: error.c:548
#define rb_check_arity
Definition: intern.h:296
int eaccess(const char *path, int mode)
Definition: file.c:1147
#define ULONG2NUM(x)
Definition: ruby.h:1327
rb_encoding * rb_default_internal_encoding(void)
Definition: encoding.c:1451
VALUE rb_cFile
Definition: file.c:140
VALUE rb_str_buf_new2(const char *)
SSL_METHOD *(* func)(void)
Definition: ossl_ssl.c:113
static VALUE rb_file_flock(VALUE obj, VALUE operation)
Definition: file.c:4381
#define STAT(p, s)
Definition: file.c:110
const char * ruby_enc_find_basename(const char *name, long *baselen, long *alllen, rb_encoding *enc)
Definition: file.c:3773
VALUE rb_str_plus(VALUE, VALUE)
Definition: string.c:1352
rb_encoding * rb_enc_compatible(VALUE str1, VALUE str2)
Definition: encoding.c:849
VALUE rb_file_s_expand_path(int argc, VALUE *argv)
Definition: file.c:3463
#define FilePathStringValue(v)
Definition: ruby.h:563
VALUE path
Definition: zlib.c:2209
static VALUE rb_stat_blocks(VALUE self)
Definition: file.c:701
void rb_str_set_len(VALUE, long)
Definition: string.c:2007
static VALUE copy_path_class(VALUE path, VALUE orig)
Definition: file.c:5428
#define RBASIC_SET_CLASS(obj, cls)
Definition: internal.h:611
int rb_enc_str_coderange(VALUE)
Definition: string.c:435
unsigned int rb_enc_codepoint_len(const char *p, const char *e, int *len_p, rb_encoding *enc)
Definition: encoding.c:993
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition: class.c:657
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:1857
static long apply2files(void(*func)(const char *, VALUE, void *), VALUE vargs, void *arg)
Definition: file.c:317
static struct timespec stat_mtimespec(struct stat *st)
Definition: file.c:739
#define RSTRING_GETMEM(str, ptrvar, lenvar)
Definition: ruby.h:854
VALUE rb_enc_associate(VALUE obj, rb_encoding *enc)
Definition: encoding.c:826
VALUE rb_mFileTest
Definition: file.c:141
static VALUE rb_stat_w(VALUE obj)
Definition: file.c:5007
VALUE rb_io_taint_check(VALUE)
Definition: io.c:602
VALUE rb_exec_recursive(VALUE(*)(VALUE, VALUE, int), VALUE, VALUE)
Definition: thread.c:4992
#define RB_GC_GUARD(v)
Definition: ruby.h:523
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
VALUE rb_obj_is_kind_of(VALUE, VALUE)
Definition: object.c:646
static VALUE rb_file_zero_p(VALUE obj, VALUE fname)
Definition: file.c:1629
static VALUE rb_stat_d(VALUE obj)
Definition: file.c:4741
static VALUE file_inspect_join(VALUE ary, VALUE argp, int recur)
Definition: file.c:4098
VALUE rb_thread_io_blocking_region(rb_blocking_function_t *func, void *data1, int fd)
Definition: thread.c:1384
VALUE rb_eSecurityError
Definition: error.c:557
#define DATA_PTR(dta)
Definition: ruby.h:992
static VALUE rb_file_size(VALUE obj)
Definition: file.c:2097
void rb_include_module(VALUE klass, VALUE module)
Definition: class.c:808
static VALUE file_path_convert(VALUE name)
Definition: file.c:147
static VALUE rb_file_lstat(VALUE obj)
Definition: file.c:1070
static VALUE rb_stat_dev_minor(VALUE self)
Definition: file.c:491
#define T_ARRAY
Definition: ruby.h:484
static VALUE rb_file_suid_p(VALUE obj, VALUE fname)
Definition: file.c:1735
#define LOCK_NB
Definition: file.c:4309
#define RFILE(obj)
Definition: ruby.h:1129
static VALUE rb_file_s_basename(int argc, VALUE *argv)
Definition: file.c:3851
int rb_str_cmp(VALUE, VALUE)
Definition: string.c:2485
static VALUE rb_stat_S(VALUE obj)
Definition: file.c:4804
static VALUE file_expand_path_1(VALUE fname)
Definition: file.c:3416
void rb_define_global_function(const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a global function.
Definition: class.c:1675
static VALUE rb_file_s_utime(int argc, VALUE *argv)
Definition: file.c:2482
static VALUE rb_stat_s(VALUE obj)
Definition: file.c:5203
unsigned int last
Definition: nkf.c:4310
#define lstat
Definition: file.c:87
static VALUE rb_stat_dev(VALUE self)
Definition: file.c:453
rb_encoding * rb_utf8_encoding(void)
Definition: encoding.c:1257
static void realpath_rec(long *prefixlenp, VALUE *resolvedp, const char *unresolved, VALUE loopcheck, int strict, int last)
Definition: file.c:3509
#define ELOOP
Definition: win32.h:590
static void sys_fail2(VALUE s1, VALUE s2)
Definition: file.c:2505
VALUE rb_str_dup_frozen(VALUE)
static VALUE rb_file_ctime(VALUE obj)
Definition: file.c:2074
static VALUE rb_stat_uid(VALUE self)
Definition: file.c:568
#define strncasecmp
Definition: win32.h:221
VALUE rb_str_tmp_new(long)
Definition: string.c:919
VALUE rb_str_buf_append(VALUE, VALUE)
Definition: string.c:2281
VALUE mtime
Definition: file.c:2369
#define GetOpenFile(obj, fp)
Definition: io.h:118
static VALUE rb_stat_r(VALUE obj)
Definition: file.c:4915
static VALUE rb_stat_grpowned(VALUE obj)
Definition: file.c:4895
int truncate(const char *path, off_t new_size)
#define OBJ_TAINTED(x)
Definition: ruby.h:1182
#define ENC_CODERANGE_7BIT
Definition: encoding.h:49
const char * rb_obj_classname(VALUE)
Definition: variable.c:406
struct timespec rb_time_timespec(VALUE time)
Definition: time.c:2434
static VALUE rb_stat_x(VALUE obj)
Definition: file.c:5101
time_t tv_sec
Definition: missing.h:51
VALUE rb_str_buf_cat(VALUE, const char *, long)
Definition: string.c:2123
int mode
Definition: io.h:64
static char * chompdirsep(const char *path, const char *end, rb_encoding *enc)
Definition: file.c:2913
#define rb_file_s_readlink
Definition: file.c:2633
#define ISALPHA(c)
Definition: ruby.h:1782
void rb_exc_raise(VALUE mesg)
Definition: eval.c:567
static VALUE rb_file_blockdev_p(VALUE obj, VALUE fname)
Definition: file.c:1338
char * rb_enc_path_skip_prefix(const char *path, const char *end, rb_encoding *enc)
Definition: file.c:2861
static VALUE rb_file_world_readable_p(VALUE obj, VALUE fname)
Definition: file.c:1479
#define RBASIC_SET_CLASS_RAW(obj, cls)
Definition: internal.h:610
rb_gid_t getegid(void)
Definition: win32.c:2519
static VALUE rb_stat_s_alloc(VALUE klass)
Definition: file.c:4653
#define RB_TYPE_P(obj, type)
Definition: ruby.h:1672
int utimes(const char *filename, const struct timeval times[2])
static VALUE rb_file_ftype(const struct stat *st)
Definition: file.c:1867
static VALUE rb_thread_flock(void *data)
Definition: file.c:4320
Definition: file.c:2449
static int path_check_0(VALUE path, int execpath)
Definition: file.c:5306
static VALUE stat_ctime(struct stat *st)
Definition: file.c:780
static rb_encoding * check_path_encoding(VALUE str)
Definition: file.c:166
static VALUE rb_stat_size(VALUE self)
Definition: file.c:663
#define LOCK_EX
Definition: file.c:4306
#define LOCK_UN
Definition: file.c:4312
static VALUE rb_file_s_split(VALUE klass, VALUE path)
Definition: file.c:4087
static VALUE stat_new_0(VALUE klass, const struct stat *st)
Definition: file.c:370
VALUE rb_mComparable
Definition: compar.c:14
static VALUE rb_file_pipe_p(VALUE obj, VALUE fname)
Definition: file.c:1239
int t(void)
Definition: conftest.c:13
VALUE rb_find_file(VALUE path)
Definition: file.c:5508
VALUE rb_class_new_instance(int, VALUE *, VALUE)
Definition: object.c:1857
#define S_IROTH
Definition: win32.h:419
#define S_IWUGO
Definition: file.c:1459
static VALUE rb_file_s_chmod(int argc, VALUE *argv)
Definition: file.c:2133
VALUE rb_hash_aset(VALUE hash, VALUE key, VALUE val)
Definition: hash.c:1402
static VALUE rb_file_s_lstat(VALUE klass, VALUE fname)
Definition: file.c:1038
VALUE rb_str_new_shared(VALUE)
Definition: string.c:799
VALUE rb_obj_taint(VALUE)
Definition: object.c:967
#define NUM2DEVT(v)
Definition: file.c:433
void Init_File(void)
Definition: file.c:5623
VALUE rb_str_encode_ospath(VALUE path)
Definition: file.c:232
static VALUE rb_file_readable_real_p(VALUE obj, VALUE fname)
Definition: file.c:1445
#define rb_file_s_symlink
Definition: file.c:2581
#define level
long tv_usec
Definition: ossl_asn1.c:18
RUBY_EXTERN VALUE rb_cObject
Definition: ruby.h:1561
VALUE rb_home_dir_of(VALUE user, VALUE result)
Definition: file.c:3002
static VALUE rb_file_s_stat(VALUE klass, VALUE fname)
Definition: file.c:984
static VALUE rb_file_mtime(VALUE obj)
Definition: file.c:2020
static VALUE rb_file_s_chown(int argc, VALUE *argv)
Definition: file.c:2252
static VALUE rb_file_s_realpath(int argc, VALUE *argv, VALUE klass)
Definition: file.c:3709
static VALUE rb_stat_owned(VALUE obj)
Definition: file.c:4869
VALUE rb_str_cat2(VALUE, const char *)
Definition: string.c:2158
VALUE rb_mFConst
Definition: file.c:5273
VALUE rb_str_buf_cat2(VALUE, const char *)
Definition: string.c:2133
#define UINT2NUM(x)
Definition: ruby.h:1306
static int is_explicit_relative(const char *path)
Definition: file.c:5420
#define NIL_P(v)
Definition: ruby.h:438
long tv_nsec
Definition: missing.h:52
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition: class.c:611
static VALUE rb_file_exist_p(VALUE obj, VALUE fname)
Definition: file.c:1394
int chown(const char *, int, int)
Definition: win32.c:4431
int fd
Definition: io.h:62
static VALUE str_shrink(VALUE str)
Definition: file.c:3402
void rb_define_const(VALUE, const char *, VALUE)
Definition: variable.c:2228
static char * skiproot(const char *path, const char *end, rb_encoding *enc)
Definition: file.c:2836
VALUE rb_class_inherited_p(VALUE, VALUE)
Definition: object.c:1560
#define TYPE(x)
Definition: ruby.h:505
char * rb_enc_path_next(const char *s, const char *e, rb_encoding *enc)
Definition: file.c:2847
int argc
Definition: ruby.c:131
VALUE rb_str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to)
Definition: string.c:680
VALUE rb_io_flush_raw(VALUE, int)
Definition: io.c:1466
#define insecure_obj_p(obj, level)
Definition: file.c:144
#define Qfalse
Definition: ruby.h:425
static VALUE rb_file_sticky_p(VALUE obj, VALUE fname)
Definition: file.c:1769
static VALUE rb_file_s_join(VALUE klass, VALUE args)
Definition: file.c:4193
static VALUE rb_file_atime(VALUE obj)
Definition: file.c:1973
#define ALLOCV_N(type, v, n)
Definition: ruby.h:1356
static size_t stat_memsize(const void *p)
Definition: file.c:358
#define S_IWGRP
Definition: win32.h:426
mode_t umask(mode_t mask)
static VALUE rb_stat_b(VALUE obj)
Definition: file.c:4827
#define ALLOCA_N(type, n)
Definition: ruby.h:1345
long modtime
Definition: file.c:2451
#define S_ISCHR(m)
#define LOCK_SH
Definition: file.c:4303
#define fpath_check(path)
Definition: file.c:5355
void rb_enc_raise(rb_encoding *enc, VALUE exc, const char *fmt,...)
Definition: error.c:1844
VALUE rb_enc_associate_index(VALUE obj, int idx)
Definition: encoding.c:798
VALUE rb_eEncCompatError
Definition: error.c:555
#define rb_str_new2
Definition: intern.h:840
#define BUFCHECK(cond)
Definition: file.c:2960
static void chmod_internal(const char *path, VALUE pathv, void *mode)
Definition: file.c:2113
#define OBJ_FREEZE(x)
Definition: ruby.h:1194
VALUE rb_find_file_safe(VALUE path, int safe_level)
Definition: file.c:5514
static VALUE rb_stat_suid(VALUE obj)
Definition: file.c:5223
int link(const char *, const char *)
Definition: win32.c:4601
#define ALLOCV_END(v)
Definition: ruby.h:1357
#define BUFINIT()
Definition: file.c:2971
static VALUE rb_file_writable_real_p(VALUE obj, VALUE fname)
Definition: file.c:1519
void * rb_thread_call_without_gvl(void *(*func)(void *), void *data1, rb_unblock_function_t *ubf, void *data2)
static VALUE rb_stat_sticky(VALUE obj)
Definition: file.c:5265
#define ALLOC(type)
Definition: ruby.h:1342
static VALUE rb_stat_ftype(VALUE obj)
Definition: file.c:4724
static char * append_fspath(VALUE result, VALUE fname, char *dir, rb_encoding **enc, rb_encoding *fsenc)
Definition: file.c:3030
VALUE rb_file_absolute_path(VALUE fname, VALUE dname)
Definition: file.c:3476
VALUE rb_str_resize(VALUE, long)
Definition: string.c:2024
size_t rb_str_capacity(VALUE)
Definition: string.c:468
int rb_enc_ascget(const char *p, const char *e, int *len, rb_encoding *enc)
Definition: encoding.c:970
VALUE rb_str_subseq(VALUE, long, long)
Definition: string.c:1838
RUBY_EXTERN VALUE rb_cIO
Definition: ruby.h:1577
static VALUE rb_stat_blksize(VALUE self)
Definition: file.c:680
static VALUE rb_file_identical_p(VALUE obj, VALUE fname1, VALUE fname2)
Definition: file.c:1798
#define RSTRING_LEN(str)
Definition: ruby.h:841
void rb_define_module_function(VALUE module, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a module function for module.
Definition: class.c:1661
int errno
#define TRUE
Definition: nkf.h:175
#define off_t
Definition: io.c:65
VALUE rb_file_s_absolute_path(int argc, VALUE *argv)
Definition: file.c:3496
VALUE rb_sprintf(const char *format,...)
Definition: sprintf.c:1250
int rb_enc_precise_mbclen(const char *p, const char *e, rb_encoding *enc)
Definition: encoding.c:958
#define const
Definition: strftime.c:102
#define rb_enc_name(enc)
Definition: encoding.h:125
VALUE rb_eSystemCallError
Definition: error.c:566
static VALUE rb_file_s_path(VALUE klass, VALUE fname)
Definition: file.c:4070
static VALUE rb_stat_dev_major(VALUE self)
Definition: file.c:470
VALUE rb_file_dirname(VALUE fname)
Definition: file.c:3911
VALUE rb_hash_new(void)
Definition: hash.c:307
#define NUM2CHR(x)
Definition: ruby.h:1337
#define PRI_DEVT_PREFIX
Definition: file.c:439
#define strdup(s)
Definition: util.h:67
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:1719
static char * skipprefixroot(const char *path, const char *end, rb_encoding *enc)
Definition: file.c:2882
void rb_str_modify_expand(VALUE, long)
Definition: string.c:1491
#define fncomp
#define S_IXUSR
Definition: win32.h:433
static VALUE rb_stat_ctime(VALUE self)
Definition: file.c:834
unsigned char buf[MIME_BUF_SIZE]
Definition: nkf.c:4308
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Definition: array.c:620
#define PRIsVALUE
Definition: ruby.h:137
unsigned long ID
Definition: ruby.h:89
rb_encoding * rb_usascii_encoding(void)
Definition: encoding.c:1272
VALUE rb_file_directory_p(VALUE obj, VALUE fname)
Definition: file.c:1216
#define Qnil
Definition: ruby.h:427
static int rb_group_member(GETGROUPS_T gid)
Definition: file.c:1091
int ftruncate(int fd, off_t new_size)
#define EXPAND_PATH_BUFFER()
Definition: file.c:3399
#define check_expand_path_args(fname, dname)
Definition: file.c:3411
#define OBJ_TAINT(x)
Definition: ruby.h:1184
unsigned long VALUE
Definition: ruby.h:88
#define S_ISDIR(m)
rb_uid_t geteuid(void)
Definition: win32.c:2505
static VALUE result
Definition: nkf.c:40
static VALUE rb_stat_sgid(VALUE obj)
Definition: file.c:5244
char * strchr(char *, char)
static VALUE rb_stat_inspect(VALUE self)
Definition: file.c:854
#define rb_usascii_encindex()
Definition: internal.h:404
#define NUM2GIDT(v)
Definition: ruby.h:336
VALUE rb_check_funcall(VALUE, ID, int, const VALUE *)
Definition: vm_eval.c:410
#define rb_enc_asciicompat(enc)
Definition: encoding.h:188
static VALUE rb_file_writable_p(VALUE obj, VALUE fname)
Definition: file.c:1501
VALUE rb_str_ellipsize(VALUE, long)
Shortens str and adds three dots, an ellipsis, if it is longer than len characters.
Definition: string.c:7969
VALUE rb_str_new_cstr(const char *)
Definition: string.c:560
static void utime_internal(const char *path, VALUE pathv, void *arg)
Definition: file.c:2456
static VALUE copy_home_path(VALUE result, const char *dir)
Definition: file.c:2977
#define CHECK(n)
Definition: file.c:4439
static struct timespec stat_ctimespec(struct stat *st)
Definition: file.c:763
#define strrdirsep
Definition: file.c:2893
static void chown_internal(const char *path, VALUE pathv, void *arg)
Definition: file.c:2229
VALUE rb_str_dup(VALUE)
Definition: string.c:1062
#define S_IXOTH
Definition: win32.h:439
static void test_check(int n, int argc, VALUE *argv)
Definition: file.c:4425
VALUE rb_stat_new(const struct stat *st)
Definition: file.c:382
#define FL_UNSET(x, f)
Definition: ruby.h:1177
#define my_getcwd()
Definition: util.h:70
VALUE rb_define_module_under(VALUE outer, const char *name)
Definition: class.c:747
#define StringValueCStr(v)
Definition: ruby.h:541
#define getenv(name)
Definition: win32.c:66
static VALUE rb_stat_wr(VALUE obj)
Definition: file.c:4983
#define recur(fmt)
static VALUE rb_stat_mtime(VALUE self)
Definition: file.c:814
#define S_ISREG(m)
Definition: file.c:1595
#define RSTRING_PTR(str)
Definition: ruby.h:845
unsigned int top
Definition: nkf.c:4309
void rb_thread_wait_for(struct timeval)
Definition: thread.c:1119
#define ENCODING_GET(obj)
Definition: encoding.h:38
VALUE rb_equal(VALUE, VALUE)
Definition: object.c:89
rb_encoding * rb_enc_get(VALUE obj)
Definition: encoding.c:832
#define utime_failed(path, tsp, atime, mtime)
Definition: file.c:2407
void rb_insecure_operation(void)
Definition: safe.c:109
int size
Definition: encoding.c:49
#define f
#define INT2FIX(i)
Definition: ruby.h:231
static const char null_device[]
Definition: file.c:5576
#define ST2UINT(val)
Definition: file.c:430
int utime(const char *filename, const struct utimbuf *times)
static VALUE rb_file_s_ftype(VALUE klass, VALUE fname)
Definition: file.c:1923
#define RARRAY_AREF(a, i)
Definition: ruby.h:901
int rb_path_check(const char *path)
Definition: file.c:5361
VALUE rb_check_convert_type(VALUE, int, const char *, const char *)
Definition: object.c:2652
NORETURN(static void sys_fail2(VALUE, VALUE))
VALUE rb_file_expand_path(VALUE fname, VALUE dname)
Definition: file.c:3422
static const rb_data_type_t stat_data_type
Definition: file.c:363
static VALUE rb_file_chown(VALUE obj, VALUE owner, VALUE group)
Definition: file.c:2293
#define S_ISBLK(m)
static VALUE rb_stat_rowned(VALUE obj)
Definition: file.c:4876
#define NUM2ULONG(x)
Definition: ruby.h:609
#define ANYARGS
Definition: defines.h:98
#define PATH_SEP_CHAR
Definition: defines.h:278
static VALUE rb_stat_c(VALUE obj)
Definition: file.c:4849
static VALUE rb_file_s_extname(VALUE klass, VALUE fname)
Definition: file.c:4041
#define Inc(p, e, enc)
Definition: file.c:2772
VALUE rb_hash_aref(VALUE hash, VALUE key)
Definition: hash.c:706
VALUE atime
Definition: file.c:2369
static VALUE rb_file_chmod(VALUE obj, VALUE vmode)
Definition: file.c:2162
VALUE rb_str_catf(VALUE str, const char *format,...)
Definition: sprintf.c:1290
#define GIDT2NUM(v)
Definition: ruby.h:333
static VALUE rb_file_chardev_p(VALUE obj, VALUE fname)
Definition: file.c:1367
#define LONG2FIX(i)
Definition: ruby.h:232
VALUE pathv
Definition: io.h:67
#define O_NONBLOCK
Definition: win32.h:626
#define RTEST(v)
Definition: ruby.h:437
#define T_STRING
Definition: ruby.h:482
static VALUE stat_atime(struct stat *st)
Definition: file.c:732
#define S_IWOTH
static VALUE rb_file_s_dirname(VALUE klass, VALUE fname)
Definition: file.c:3905
#define OBJ_INFECT(x, s)
Definition: ruby.h:1188
static VALUE rb_file_owned_p(VALUE obj, VALUE fname)
Definition: file.c:1670
VALUE rb_default_home_dir(VALUE result)
Definition: file.c:3019
int flock(int, int)
Definition: flock.c:125
static void unlink_internal(const char *path, VALUE pathv, void *arg)
Definition: file.c:2637
rb_encoding * rb_filesystem_encoding(void)
Definition: encoding.c:1324
static VALUE rb_stat_atime(VALUE self)
Definition: file.c:798
#define EWOULDBLOCK
Definition: rubysocket.h:126
#define T_FILE
Definition: ruby.h:488
rb_uid_t owner
Definition: file.c:2224
static VALUE rb_stat_gid(VALUE self)
Definition: file.c:584
rb_gid_t group
Definition: file.c:2225
static VALUE rb_file_rowned_p(VALUE obj, VALUE fname)
Definition: file.c:1680
static size_t rmext(const char *p, long l0, long l1, const char *e, long l2, rb_encoding *enc)
Definition: file.c:3737
#define ISPRINT(c)
Definition: ruby.h:1776
#define rb_enc_left_char_head(s, p, e, enc)
Definition: encoding.h:170
VALUE rb_str_inspect(VALUE)
Definition: string.c:4795
static VALUE rb_file_s_rename(VALUE klass, VALUE from, VALUE to)
Definition: file.c:2674
static VALUE rb_stat_p(VALUE obj)
Definition: file.c:4756
#define TOLOWER(c)
Definition: ruby.h:1787
VALUE rb_get_expanded_load_path(void)
Definition: load.c:109
static VALUE rb_stat_rdev_major(VALUE self)
Definition: file.c:623
char * rb_enc_path_end(const char *path, const char *end, rb_encoding *enc)
Definition: file.c:2929
#define T_CLASS
Definition: ruby.h:478
#define rb_file_s_lchmod
Definition: file.c:2220
static struct stat * get_stat(VALUE self)
Definition: file.c:388
VALUE rb_enc_str_new(const char *, long, rb_encoding *)
Definition: string.c:548
static int rb_stat(VALUE file, struct stat *st)
Definition: file.c:913
#define rb_safe_level()
Definition: tcltklib.c:95
#define S_IXGRP
Definition: win32.h:436
#define rb_sys_fail_path(path)
Definition: internal.h:450
#define OFFT2NUM(v)
Definition: ruby.h:252
static VALUE rb_stat_X(VALUE obj)
Definition: file.c:5133
VALUE rb_realpath_internal(VALUE basedir, VALUE path, int strict)
Definition: file.c:3621
#define istrailinggarbage(x)
Definition: file.c:2768
char * rb_enc_path_last_separator(const char *path, const char *end, rb_encoding *enc)
Definition: file.c:2895
const char * name
Definition: nkf.c:208
RUBY_EXTERN VALUE rb_eIOError
Definition: ruby.h:1611
#define ID2SYM(x)
Definition: ruby.h:355
#define MAXPATHLEN
Definition: file.c:47
static VALUE rb_file_executable_real_p(VALUE obj, VALUE fname)
Definition: file.c:1585
int rb_find_file_ext_safe(VALUE *filep, const char *const *ext, int safe_level)
Definition: file.c:5443
#define S_IRUGO
Definition: file.c:1455
int rb_file_load_ok(const char *path)
Definition: file.c:5398
static VALUE rb_stat_ww(VALUE obj)
Definition: file.c:5075
RUBY_EXTERN size_t strlcat(char *, const char *, size_t)
Definition: strlcat.c:46
static VALUE rb_file_s_ctime(VALUE klass, VALUE fname)
Definition: file.c:2049
static VALUE rb_file_path(VALUE obj)
Definition: file.c:347
static VALUE rb_io_stat(VALUE obj)
Definition: file.c:1011
#define StringValuePtr(v)
Definition: ruby.h:540
#define STRCASECMP(s1, s2)
Definition: ruby.h:1791
#define RB_MAX_GROUPS
Definition: internal.h:637
VALUE rb_inspect(VALUE)
Definition: object.c:470
#define UIDT2NUM(v)
Definition: ruby.h:327
#define PATH_SEP
Definition: defines.h:276
rb_encoding * rb_ascii8bit_encoding(void)
Definition: encoding.c:1242
#define S_IRUSR
Definition: win32.h:413
rb_gid_t getgid(void)
Definition: win32.c:2512
void rb_warning(const char *fmt,...)
Definition: error.c:236
void rb_secure(int)
Definition: safe.c:88
#define S_IWUSR
Definition: win32.h:423
#define rb_file_truncate
Definition: file.c:4299
static VALUE separator
Definition: file.c:4093
#define CONST_ID(var, str)
Definition: ruby.h:1436
#define RUBY_TYPED_DEFAULT_FREE
Definition: ruby.h:1011
static VALUE rb_stat_nlink(VALUE self)
Definition: file.c:552
VALUE rb_obj_freeze(VALUE)
Definition: object.c:1070
int major
Definition: tcltklib.c:110
VALUE rb_str_encode(VALUE str, VALUE to, int ecflags, VALUE ecopts)
Definition: transcode.c:2884
void void xfree(void *)
VALUE rb_cStat
Definition: file.c:142
#define R_OK
Definition: file.h:16
#define W_OK
Definition: file.h:17
VALUE rb_define_module(const char *name)
Definition: class.c:727
int rb_enc_str_asciionly_p(VALUE)
Definition: string.c:448
const char * ruby_enc_find_extname(const char *name, long *len, rb_encoding *enc)
Definition: file.c:3966
VALUE rb_str_buf_new(long)
Definition: string.c:891
static VALUE rb_file_s_umask(int argc, VALUE *argv)
Definition: file.c:2724
#define fstat(fd, st)
Definition: win32.h:214
#define stat(path, st)
Definition: win32.h:213
VALUE rb_get_path_no_checksafe(VALUE obj)
Definition: file.c:220
#define NULL
Definition: _sdbm.c:102
#define Qundef
Definition: ruby.h:428
#define nextdirsep
Definition: file.c:2845
#define rb_file_s_truncate
Definition: file.c:4251
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1479
VALUE rb_str_append(VALUE, VALUE)
Definition: string.c:2297
static VALUE rb_stat_rdev_minor(VALUE self)
Definition: file.c:644
static VALUE rb_stat_l(VALUE obj)
Definition: file.c:4783
static VALUE rb_file_s_realdirpath(int argc, VALUE *argv, VALUE klass)
Definition: file.c:3729
static VALUE rb_file_s_unlink(VALUE klass, VALUE args)
Definition: file.c:2654
static VALUE rb_file_join(VALUE ary, VALUE sep)
Definition: file.c:4106
int rb_memcicmp(const void *, const void *, long)
Definition: re.c:80
void rb_warn(const char *fmt,...)
Definition: error.c:223
void rb_io_check_closed(rb_io_t *)
Definition: io.c:617
VALUE rb_eArgError
Definition: error.c:549
static VALUE rb_stat_W(VALUE obj)
Definition: file.c:5040
static VALUE rb_file_s_atime(VALUE klass, VALUE fname)
Definition: file.c:1950
#define has_unc(buf)
Definition: file.c:2777
VALUE rb_dir_getwd(void)
Definition: dir.c:886
long actime
Definition: file.c:2450
VALUE rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_name, VALUE result)
Definition: file.c:3055
static VALUE rb_stat_R(VALUE obj)
Definition: file.c:4948
#define S_ISLNK(m)
Definition: dir.c:1294
char ** argv
Definition: ruby.c:132
#define StringValue(v)
Definition: ruby.h:539
#define RUBY_UBF_IO
Definition: intern.h:872
VALUE rb_file_expand_path_fast(VALUE fname, VALUE dname)
Definition: file.c:3429
static void define_filetest_function(const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: file.c:5570
#define S_IXUGO
Definition: file.c:1138
rb_encoding * rb_enc_from_index(int index)
Definition: encoding.c:590
VALUE rb_str_new(const char *, long)
Definition: string.c:534
VALUE rb_obj_class(VALUE)
Definition: object.c:226
static VALUE rb_file_file_p(VALUE obj, VALUE fname)
Definition: file.c:1609
static VALUE rb_file_symlink_p(VALUE obj, VALUE fname)
Definition: file.c:1263