Ruby 2.7.0p0(2019-12-25revision647ee6f091eafcce70ffb75ddf7e121e192ab217)

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