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