Ruby 2.1.5p273(2014-11-13revision48405)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

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