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