Ruby 2.0.0p353(2013-11-22revision43784)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

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