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