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