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