file.c
DEFINITIONS
This source file includes following functions.
- apply2files
- rb_file_path
- stat_new_0
- stat_new
- get_stat
- rb_stat_cmp
- rb_stat_dev
- rb_stat_ino
- rb_stat_mode
- rb_stat_nlink
- rb_stat_uid
- rb_stat_gid
- rb_stat_rdev
- rb_stat_rdev_major
- rb_stat_rdev_minor
- rb_stat_size
- rb_stat_blksize
- rb_stat_blocks
- rb_stat_atime
- rb_stat_mtime
- rb_stat_ctime
- rb_stat_inspect
- rb_stat
- rb_file_s_stat
- rb_io_stat
- rb_file_s_lstat
- rb_file_lstat
- group_member
- eaccess
- test_d
- S_ISDIR
- test_p
- S_ISFIFO
- test_l
- S_ISLNK
- S_ISLNK
- S_ISLNK
- S_ISLNK
- S_ISLNK
- test_S
- S_ISSOCK
- S_ISSOCK
- S_ISSOCK
- S_ISSOCK
- S_ISSOCK
- test_b
- S_ISBLK
- S_ISBLK
- test_c
- S_ISCHR
- test_e
- test_r
- test_R
- test_w
- test_W
- test_x
- test_X
- S_ISREG
- test_f
- test_z
- test_s
- test_owned
- test_rowned
- test_grpowned
- check3rdbyte
- test_suid
- test_sgid
- test_sticky
- rb_file_s_size
- rb_file_ftype
- rb_file_s_ftype
- rb_file_s_atime
- rb_file_atime
- rb_file_s_mtime
- rb_file_mtime
- rb_file_s_ctime
- rb_file_ctime
- chmod_internal
- rb_file_s_chmod
- rb_file_chmod
- lchmod_internal
- rb_file_s_lchmod
- rb_file_s_lchmod
- chown_internal
- rb_file_s_chown
- rb_file_chown
- lchown_internal
- rb_file_s_lchown
- rb_file_s_lchown
- utime_internal
- rb_file_s_utime
- utime_internal
- rb_file_s_utime
- rb_file_s_link
- rb_file_s_symlink
- rb_file_s_readlink
- unlink_internal
- rb_file_s_unlink
- rb_file_s_rename
- rb_file_s_umask
- CharNext
- CharNext
- strrdirsep
- rb_file_s_expand_path
- rmext
- rb_file_s_basename
- rb_file_s_dirname
- rb_file_s_extname
- rb_file_s_split
- rb_file_s_join
- rb_file_s_truncate
- rb_file_truncate
- rb_thread_flock
- rb_file_flock
- test_check
- rb_f_test
- rb_stat_s_alloc
- rb_stat_init
- rb_stat_become
- rb_stat_ftype
- rb_stat_d
- rb_stat_p
- rb_stat_l
- rb_stat_S
- rb_stat_b
- rb_stat_c
- rb_stat_owned
- rb_stat_rowned
- rb_stat_grpowned
- rb_stat_r
- rb_stat_R
- rb_stat_w
- rb_stat_W
- rb_stat_x
- rb_stat_X
- rb_stat_f
- rb_stat_z
- rb_stat_s
- rb_stat_suid
- rb_stat_sgid
- rb_stat_sticky
- rb_file_const
- is_absolute_path
- path_check_1
- rb_path_check
- is_macos_native_path
- file_load_ok
- rb_find_file_ext
- rb_find_file
- define_filetest_function
- Init_File
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 #ifdef NT
16 #include "missing/file.h"
17 #endif
18
19 #include "ruby.h"
20 #include "rubyio.h"
21 #include "rubysig.h"
22 #include "util.h"
23 #include "dln.h"
24
25 #ifdef HAVE_UNISTD_H
26 #include <unistd.h>
27 #endif
28
29 #ifdef HAVE_SYS_FILE_H
30 # include <sys/file.h>
31 #else
32 int flock _((int, int));
33 #endif
34
35 #ifdef HAVE_SYS_PARAM_H
36 # include <sys/param.h>
37 #else
38 # define MAXPATHLEN 1024
39 #endif
40
41 #include <time.h>
42 #ifdef HAVE_SYS_TIME_H
43 # include <sys/time.h>
44 #else
45 #ifndef NT
46 struct timeval {
47 long tv_sec;
48 long tv_usec;
49 };
50 #endif
51 #endif
52
53 VALUE rb_time_new _((time_t, time_t));
54
55 #ifdef HAVE_UTIME_H
56 #include <utime.h>
57 #endif
58
59 #ifdef HAVE_PWD_H
60 #include <pwd.h>
61 #endif
62
63 #ifndef HAVE_STRING_H
64 char *strrchr _((const char*,const char));
65 #endif
66
67 #include <sys/types.h>
68 #include <sys/stat.h>
69
70 #ifdef HAVE_SYS_MKDEV_H
71 #include <sys/mkdev.h>
72 #endif
73
74 #ifndef HAVE_LSTAT
75 #define lstat(path,st) stat(path,st)
76 #endif
77
78 VALUE rb_cFile;
79 VALUE rb_mFileTest;
80 static VALUE rb_cStat;
81
82 static long
83 apply2files(func, vargs, arg)
84 void (*func)();
85 VALUE vargs;
86 void *arg;
87 {
88 long i;
89 VALUE path;
90 struct RArray *args = RARRAY(vargs);
91
92 for (i=0; i<args->len; i++) {
93 path = args->ptr[i];
94 SafeStringValue(path);
95 (*func)(RSTRING(path)->ptr, arg);
96 }
97
98 return args->len;
99 }
100
101 static VALUE
102 rb_file_path(obj)
103 VALUE obj;
104 {
105 OpenFile *fptr;
106
107 GetOpenFile(obj, fptr);
108 if (!fptr->path) return Qnil;
109 return rb_str_new2(fptr->path);
110 }
111
112 #ifdef NT
113 #include "missing/file.h"
114 #endif
115
116 static VALUE
117 stat_new_0(klass, st)
118 VALUE klass;
119 struct stat *st;
120 {
121 struct stat *nst = 0;
122
123 if (st) {
124 nst = ALLOC(struct stat);
125 *nst = *st;
126 }
127 return Data_Wrap_Struct(klass, NULL, free, nst);
128 }
129
130 static VALUE
131 stat_new(st)
132 struct stat *st;
133 {
134 return stat_new_0(rb_cStat, st);
135 }
136
137 static struct stat*
138 get_stat(self)
139 VALUE self;
140 {
141 struct stat* st;
142 Data_Get_Struct(self, struct stat, st);
143 if (!st) rb_raise(rb_eTypeError, "uninitialized File::Stat");
144 return st;
145 }
146
147 static VALUE
148 rb_stat_cmp(self, other)
149 VALUE self, other;
150 {
151 if (rb_obj_is_kind_of(other, rb_obj_class(self))) {
152 time_t t1 = get_stat(self)->st_mtime;
153 time_t t2 = get_stat(other)->st_mtime;
154 if (t1 == t2)
155 return INT2FIX(0);
156 else if (t1 < t2)
157 return INT2FIX(-1);
158 else
159 return INT2FIX(1);
160 }
161 rb_raise(rb_eTypeError, "operand is not File::Stat");
162 }
163
164 static VALUE
165 rb_stat_dev(self)
166 VALUE self;
167 {
168 return INT2NUM(get_stat(self)->st_dev);
169 }
170
171 static VALUE
172 rb_stat_ino(self)
173 VALUE self;
174 {
175 return ULONG2NUM(get_stat(self)->st_ino);
176 }
177
178 static VALUE
179 rb_stat_mode(self)
180 VALUE self;
181 {
182 #ifdef __BORLANDC__
183 return UINT2NUM((unsigned short)(get_stat(self)->st_mode));
184 #else
185 return UINT2NUM(get_stat(self)->st_mode);
186 #endif
187 }
188
189 static VALUE
190 rb_stat_nlink(self)
191 VALUE self;
192 {
193 return UINT2NUM(get_stat(self)->st_nlink);
194 }
195
196 static VALUE
197 rb_stat_uid(self)
198 VALUE self;
199 {
200 return UINT2NUM(get_stat(self)->st_uid);
201 }
202
203 static VALUE
204 rb_stat_gid(self)
205 VALUE self;
206 {
207 return UINT2NUM(get_stat(self)->st_gid);
208 }
209
210 static VALUE
211 rb_stat_rdev(self)
212 VALUE self;
213 {
214 #ifdef HAVE_ST_RDEV
215 return ULONG2NUM(get_stat(self)->st_rdev);
216 #else
217 return Qnil;
218 #endif
219 }
220
221 static VALUE
222 rb_stat_rdev_major(self)
223 VALUE self;
224 {
225 #if defined(HAVE_ST_RDEV) && defined(major)
226 long rdev = get_stat(self)->st_rdev;
227 return ULONG2NUM(major(rdev));
228 #else
229 return Qnil;
230 #endif
231 }
232
233 static VALUE
234 rb_stat_rdev_minor(self)
235 VALUE self;
236 {
237 #if defined(HAVE_ST_RDEV) && defined(minor)
238 long rdev = get_stat(self)->st_rdev;
239 return ULONG2NUM(minor(rdev));
240 #else
241 return Qnil;
242 #endif
243 }
244
245 static VALUE
246 rb_stat_size(self)
247 VALUE self;
248 {
249 return OFFT2NUM(get_stat(self)->st_size);
250 }
251
252 static VALUE
253 rb_stat_blksize(self)
254 VALUE self;
255 {
256 #ifdef HAVE_ST_BLKSIZE
257 return ULONG2NUM(get_stat(self)->st_blksize);
258 #else
259 return Qnil;
260 #endif
261 }
262
263 static VALUE
264 rb_stat_blocks(self)
265 VALUE self;
266 {
267 #ifdef HAVE_ST_BLOCKS
268 return ULONG2NUM(get_stat(self)->st_blocks);
269 #else
270 return Qnil;
271 #endif
272 }
273
274 static VALUE
275 rb_stat_atime(self)
276 VALUE self;
277 {
278 return rb_time_new(get_stat(self)->st_atime, 0);
279 }
280
281 static VALUE
282 rb_stat_mtime(self)
283 VALUE self;
284 {
285 return rb_time_new(get_stat(self)->st_mtime, 0);
286 }
287
288 static VALUE
289 rb_stat_ctime(self)
290 VALUE self;
291 {
292 return rb_time_new(get_stat(self)->st_ctime, 0);
293 }
294
295 static VALUE
296 rb_stat_inspect(self)
297 VALUE self;
298 {
299 VALUE str;
300 int i;
301 static struct {
302 char *name;
303 VALUE (*func)();
304 } member[] = {
305 {"dev", rb_stat_dev},
306 {"ino", rb_stat_ino},
307 {"mode", rb_stat_mode},
308 {"nlink", rb_stat_nlink},
309 {"uid", rb_stat_uid},
310 {"gid", rb_stat_gid},
311 {"rdev", rb_stat_rdev},
312 {"size", rb_stat_size},
313 {"blksize", rb_stat_blksize},
314 {"blocks", rb_stat_blocks},
315 {"atime", rb_stat_atime},
316 {"mtime", rb_stat_mtime},
317 {"ctime", rb_stat_ctime},
318 };
319
320 str = rb_str_buf_new2("#<");
321 rb_str_buf_cat2(str, rb_class2name(CLASS_OF(self)));
322 rb_str_buf_cat2(str, " ");
323
324 for (i = 0; i < sizeof(member)/sizeof(member[0]); i++) {
325 VALUE v;
326
327 if (i > 0) {
328 rb_str_buf_cat2(str, ", ");
329 }
330 rb_str_buf_cat2(str, member[i].name);
331 rb_str_buf_cat2(str, "=");
332 v = (*member[i].func)(self);
333 if (i == 2) {
334 char buf[32];
335
336 sprintf(buf, "0%lo", NUM2INT(v));
337 rb_str_buf_cat2(str, buf);
338 }
339 else if (i == 0 || i == 6) {
340 char buf[32];
341
342 sprintf(buf, "0x%lx", NUM2ULONG(v));
343 rb_str_buf_cat2(str, buf);
344 }
345 else {
346 rb_str_append(str, rb_inspect(v));
347 }
348 }
349 rb_str_buf_cat2(str, ">");
350 OBJ_INFECT(str, self);
351
352 return str;
353 }
354
355 static int
356 rb_stat(file, st)
357 VALUE file;
358 struct stat *st;
359 {
360 if (TYPE(file) == T_FILE) {
361 OpenFile *fptr;
362
363 rb_secure(2);
364 GetOpenFile(file, fptr);
365 return fstat(fileno(fptr->f), st);
366 }
367 SafeStringValue(file);
368 #if defined DJGPP
369 if (RSTRING(file)->len == 0) return -1;
370 #endif
371 return stat(RSTRING(file)->ptr, st);
372 }
373
374 static VALUE
375 rb_file_s_stat(klass, fname)
376 VALUE klass, fname;
377 {
378 struct stat st;
379
380 SafeStringValue(fname);
381 if (stat(RSTRING(fname)->ptr, &st) == -1) {
382 rb_sys_fail(RSTRING(fname)->ptr);
383 }
384 return stat_new(&st);
385 }
386
387 static VALUE
388 rb_io_stat(obj)
389 VALUE obj;
390 {
391 OpenFile *fptr;
392 struct stat st;
393
394 GetOpenFile(obj, fptr);
395 if (fstat(fileno(fptr->f), &st) == -1) {
396 rb_sys_fail(fptr->path);
397 }
398 return stat_new(&st);
399 }
400
401 static VALUE
402 rb_file_s_lstat(klass, fname)
403 VALUE klass, fname;
404 {
405 #ifdef HAVE_LSTAT
406 struct stat st;
407
408 SafeStringValue(fname);
409 if (lstat(RSTRING(fname)->ptr, &st) == -1) {
410 rb_sys_fail(RSTRING(fname)->ptr);
411 }
412 return stat_new(&st);
413 #else
414 return rb_file_s_stat(klass, fname);
415 #endif
416 }
417
418 static VALUE
419 rb_file_lstat(obj)
420 VALUE obj;
421 {
422 #ifdef HAVE_LSTAT
423 OpenFile *fptr;
424 struct stat st;
425
426 rb_secure(2);
427 GetOpenFile(obj, fptr);
428 if (!fptr->path) return Qnil;
429 if (lstat(fptr->path, &st) == -1) {
430 rb_sys_fail(fptr->path);
431 }
432 return stat_new(&st);
433 #else
434 return rb_io_stat(obj);
435 #endif
436 }
437
438 static int
439 group_member(gid)
440 GETGROUPS_T gid;
441 {
442 #if !defined(NT)
443 if (getgid() == gid)
444 return Qtrue;
445
446 # ifdef HAVE_GETGROUPS
447 # ifndef NGROUPS
448 # ifdef NGROUPS_MAX
449 # define NGROUPS NGROUPS_MAX
450 # else
451 # define NGROUPS 32
452 # endif
453 # endif
454 {
455 GETGROUPS_T gary[NGROUPS];
456 int anum;
457
458 anum = getgroups(NGROUPS, gary);
459 while (--anum >= 0)
460 if (gary[anum] == gid)
461 return Qtrue;
462 }
463 # endif
464 #endif
465 return Qfalse;
466 }
467
468 #ifndef S_IXUGO
469 # define S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH)
470 #endif
471
472 int
473 eaccess(path, mode)
474 const char *path;
475 int mode;
476 {
477 #ifdef S_IXGRP
478 struct stat st;
479 int euid;
480
481 if (stat(path, &st) < 0) return -1;
482
483 euid = geteuid();
484
485 if (euid == 0) {
486
487 if (!(mode & X_OK))
488 return 0;
489
490
491
492 if (st.st_mode & S_IXUGO)
493 return 0;
494
495 return -1;
496 }
497
498 if (st.st_uid == euid)
499 mode <<= 6;
500 else if (getegid() == st.st_gid || group_member(st.st_gid))
501 mode <<= 3;
502
503 if ((st.st_mode & mode) == mode) return 0;
504
505 return -1;
506 #else
507 return access(path, mode);
508 #endif
509 }
510
511 static VALUE
512 test_d(obj, fname)
513 VALUE obj, fname;
514 {
515 #ifndef S_ISDIR
516 # define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR)
517 #endif
518
519 struct stat st;
520
521 if (rb_stat(fname, &st) < 0) return Qfalse;
522 if (S_ISDIR(st.st_mode)) return Qtrue;
523 return Qfalse;
524 }
525
526 static VALUE
527 test_p(obj, fname)
528 VALUE obj, fname;
529 {
530 #ifdef S_IFIFO
531 # ifndef S_ISFIFO
532 # define S_ISFIFO(m) ((m & S_IFMT) == S_IFIFO)
533 # endif
534
535 struct stat st;
536
537 if (rb_stat(fname, &st) < 0) return Qfalse;
538 if (S_ISFIFO(st.st_mode)) return Qtrue;
539
540 #endif
541 return Qfalse;
542 }
543
544 static VALUE
545 test_l(obj, fname)
546 VALUE obj, fname;
547 {
548 #ifndef S_ISLNK
549 # ifdef _S_ISLNK
550 # define S_ISLNK(m) _S_ISLNK(m)
551 # elif defined __BORLANDC__
552 # ifdef _S_IFLNK
553 # define S_ISLNK(m) (((unsigned short)(m) & S_IFMT) == _S_IFLNK)
554 # else
555 # ifdef S_IFLNK
556 # define S_ISLNK(m) (((unsigned short)(m) & S_IFMT) == S_IFLNK)
557 # endif
558 # endif
559 # else
560 # ifdef _S_IFLNK
561 # define S_ISLNK(m) ((m & S_IFMT) == _S_IFLNK)
562 # else
563 # ifdef S_IFLNK
564 # define S_ISLNK(m) ((m & S_IFMT) == S_IFLNK)
565 # endif
566 # endif
567 # endif
568 #endif
569
570 #ifdef S_ISLNK
571 struct stat st;
572
573 SafeStringValue(fname);
574 if (lstat(RSTRING(fname)->ptr, &st) < 0) return Qfalse;
575 if (S_ISLNK(st.st_mode)) return Qtrue;
576 #endif
577
578 return Qfalse;
579 }
580
581 static VALUE
582 test_S(obj, fname)
583 VALUE obj, fname;
584 {
585 #ifndef S_ISSOCK
586 # ifdef _S_ISSOCK
587 # define S_ISSOCK(m) _S_ISSOCK(m)
588 # elif defined __BORLANDC__
589 # ifdef _S_IFSOCK
590 # define S_ISSOCK(m) (((unsigned short)(m) & S_IFMT) == _S_IFSOCK)
591 # else
592 # ifdef S_IFSOCK
593 # define S_ISSOCK(m) (((unsigned short)(m) & S_IFMT) == S_IFSOCK)
594 # endif
595 # endif
596 # else
597 # ifdef _S_IFSOCK
598 # define S_ISSOCK(m) ((m & S_IFMT) == _S_IFSOCK)
599 # else
600 # ifdef S_IFSOCK
601 # define S_ISSOCK(m) ((m & S_IFMT) == S_IFSOCK)
602 # endif
603 # endif
604 # endif
605 #endif
606
607 #ifdef S_ISSOCK
608 struct stat st;
609
610 if (rb_stat(fname, &st) < 0) return Qfalse;
611 if (S_ISSOCK(st.st_mode)) return Qtrue;
612
613 #endif
614 return Qfalse;
615 }
616
617 static VALUE
618 test_b(obj, fname)
619 VALUE obj, fname;
620 {
621 #ifndef S_ISBLK
622 # ifdef S_IFBLK
623 # define S_ISBLK(m) ((m & S_IFMT) == S_IFBLK)
624 # else
625 # define S_ISBLK(m) (0)
626 # endif
627 #endif
628
629 #ifdef S_ISBLK
630 struct stat st;
631
632 if (rb_stat(fname, &st) < 0) return Qfalse;
633 if (S_ISBLK(st.st_mode)) return Qtrue;
634
635 #endif
636 return Qfalse;
637 }
638
639 static VALUE
640 test_c(obj, fname)
641 VALUE obj, fname;
642 {
643 #ifndef S_ISCHR
644 # define S_ISCHR(m) ((m & S_IFMT) == S_IFCHR)
645 #endif
646
647 struct stat st;
648
649 if (rb_stat(fname, &st) < 0) return Qfalse;
650 if (S_ISCHR(st.st_mode)) return Qtrue;
651
652 return Qfalse;
653 }
654
655 static VALUE
656 test_e(obj, fname)
657 VALUE obj, fname;
658 {
659 struct stat st;
660
661 if (rb_stat(fname, &st) < 0) return Qfalse;
662 return Qtrue;
663 }
664
665 static VALUE
666 test_r(obj, fname)
667 VALUE obj, fname;
668 {
669 SafeStringValue(fname);
670 if (eaccess(RSTRING(fname)->ptr, R_OK) < 0) return Qfalse;
671 return Qtrue;
672 }
673
674 static VALUE
675 test_R(obj, fname)
676 VALUE obj, fname;
677 {
678 SafeStringValue(fname);
679 if (access(RSTRING(fname)->ptr, R_OK) < 0) return Qfalse;
680 return Qtrue;
681 }
682
683 static VALUE
684 test_w(obj, fname)
685 VALUE obj, fname;
686 {
687 SafeStringValue(fname);
688 if (eaccess(RSTRING(fname)->ptr, W_OK) < 0) return Qfalse;
689 return Qtrue;
690 }
691
692 static VALUE
693 test_W(obj, fname)
694 VALUE obj, fname;
695 {
696 SafeStringValue(fname);
697 if (access(RSTRING(fname)->ptr, W_OK) < 0) return Qfalse;
698 return Qtrue;
699 }
700
701 static VALUE
702 test_x(obj, fname)
703 VALUE obj, fname;
704 {
705 SafeStringValue(fname);
706 if (eaccess(RSTRING(fname)->ptr, X_OK) < 0) return Qfalse;
707 return Qtrue;
708 }
709
710 static VALUE
711 test_X(obj, fname)
712 VALUE obj, fname;
713 {
714 SafeStringValue(fname);
715 if (access(RSTRING(fname)->ptr, X_OK) < 0) return Qfalse;
716 return Qtrue;
717 }
718
719 #ifndef S_ISREG
720 # define S_ISREG(m) ((m & S_IFMT) == S_IFREG)
721 #endif
722
723 static VALUE
724 test_f(obj, fname)
725 VALUE obj, fname;
726 {
727 struct stat st;
728
729 if (rb_stat(fname, &st) < 0) return Qfalse;
730 if (S_ISREG(st.st_mode)) return Qtrue;
731 return Qfalse;
732 }
733
734 static VALUE
735 test_z(obj, fname)
736 VALUE obj, fname;
737 {
738 struct stat st;
739
740 if (rb_stat(fname, &st) < 0) return Qfalse;
741 if (st.st_size == 0) return Qtrue;
742 return Qfalse;
743 }
744
745 static VALUE
746 test_s(obj, fname)
747 VALUE obj, fname;
748 {
749 struct stat st;
750
751 if (rb_stat(fname, &st) < 0) return Qnil;
752 if (st.st_size == 0) return Qnil;
753 return OFFT2NUM(st.st_size);
754 }
755
756 static VALUE
757 test_owned(obj, fname)
758 VALUE obj, fname;
759 {
760 struct stat st;
761
762 if (rb_stat(fname, &st) < 0) return Qfalse;
763 if (st.st_uid == geteuid()) return Qtrue;
764 return Qfalse;
765 }
766
767 static VALUE
768 test_rowned(obj, fname)
769 VALUE obj, fname;
770 {
771 struct stat st;
772
773 if (rb_stat(fname, &st) < 0) return Qfalse;
774 if (st.st_uid == getuid()) return Qtrue;
775 return Qfalse;
776 }
777
778 static VALUE
779 test_grpowned(obj, fname)
780 VALUE obj, fname;
781 {
782 #ifndef NT
783 struct stat st;
784
785 if (rb_stat(fname, &st) < 0) return Qfalse;
786 if (st.st_gid == getegid()) return Qtrue;
787 #endif
788 return Qfalse;
789 }
790
791 #if defined(S_ISUID) || defined(S_ISGID) || defined(S_ISVTX)
792 static VALUE
793 check3rdbyte(fname, mode)
794 VALUE fname;
795 int mode;
796 {
797 struct stat st;
798
799 SafeStringValue(fname);
800 if (stat(RSTRING(fname)->ptr, &st) < 0) return Qfalse;
801 if (st.st_mode & mode) return Qtrue;
802 return Qfalse;
803 }
804 #endif
805
806 static VALUE
807 test_suid(obj, fname)
808 VALUE obj, fname;
809 {
810 #ifdef S_ISUID
811 return check3rdbyte(fname, S_ISUID);
812 #else
813 return Qfalse;
814 #endif
815 }
816
817 static VALUE
818 test_sgid(obj, fname)
819 VALUE obj, fname;
820 {
821 #ifdef S_ISGID
822 return check3rdbyte(fname, S_ISGID);
823 #else
824 return Qfalse;
825 #endif
826 }
827
828 static VALUE
829 test_sticky(obj, fname)
830 VALUE obj, fname;
831 {
832 #ifdef S_ISVTX
833 return check3rdbyte(fname, S_ISVTX);
834 #else
835 return Qnil;
836 #endif
837 }
838
839 static VALUE
840 rb_file_s_size(klass, fname)
841 VALUE klass, fname;
842 {
843 struct stat st;
844
845 if (rb_stat(fname, &st) < 0)
846 rb_sys_fail(RSTRING(fname)->ptr);
847 return OFFT2NUM(st.st_size);
848 }
849
850 static VALUE
851 rb_file_ftype(st)
852 struct stat *st;
853 {
854 char *t;
855
856 if (S_ISREG(st->st_mode)) {
857 t = "file";
858 }
859 else if (S_ISDIR(st->st_mode)) {
860 t = "directory";
861 }
862 else if (S_ISCHR(st->st_mode)) {
863 t = "characterSpecial";
864 }
865 #ifdef S_ISBLK
866 else if (S_ISBLK(st->st_mode)) {
867 t = "blockSpecial";
868 }
869 #endif
870 #ifdef S_ISFIFO
871 else if (S_ISFIFO(st->st_mode)) {
872 t = "fifo";
873 }
874 #endif
875 #ifdef S_ISLNK
876 else if (S_ISLNK(st->st_mode)) {
877 t = "link";
878 }
879 #endif
880 #ifdef S_ISSOCK
881 else if (S_ISSOCK(st->st_mode)) {
882 t = "socket";
883 }
884 #endif
885 else {
886 t = "unknown";
887 }
888
889 return rb_str_new2(t);
890 }
891
892 static VALUE
893 rb_file_s_ftype(klass, fname)
894 VALUE klass, fname;
895 {
896 struct stat st;
897
898 SafeStringValue(fname);
899 if (lstat(RSTRING(fname)->ptr, &st) == -1) {
900 rb_sys_fail(RSTRING(fname)->ptr);
901 }
902
903 return rb_file_ftype(&st);
904 }
905
906 static VALUE
907 rb_file_s_atime(klass, fname)
908 VALUE klass, fname;
909 {
910 struct stat st;
911
912 if (rb_stat(fname, &st) < 0)
913 rb_sys_fail(RSTRING(fname)->ptr);
914 return rb_time_new(st.st_atime, 0);
915 }
916
917 static VALUE
918 rb_file_atime(obj)
919 VALUE obj;
920 {
921 OpenFile *fptr;
922 struct stat st;
923
924 GetOpenFile(obj, fptr);
925 if (fstat(fileno(fptr->f), &st) == -1) {
926 rb_sys_fail(fptr->path);
927 }
928 return rb_time_new(st.st_atime, 0);
929 }
930
931 static VALUE
932 rb_file_s_mtime(klass, fname)
933 VALUE klass, fname;
934 {
935 struct stat st;
936
937 if (rb_stat(fname, &st) < 0)
938 rb_sys_fail(RSTRING(fname)->ptr);
939 return rb_time_new(st.st_mtime, 0);
940 }
941
942 static VALUE
943 rb_file_mtime(obj)
944 VALUE obj;
945 {
946 OpenFile *fptr;
947 struct stat st;
948
949 GetOpenFile(obj, fptr);
950 if (fstat(fileno(fptr->f), &st) == -1) {
951 rb_sys_fail(fptr->path);
952 }
953 return rb_time_new(st.st_mtime, 0);
954 }
955
956 static VALUE
957 rb_file_s_ctime(klass, fname)
958 VALUE klass, fname;
959 {
960 struct stat st;
961
962 if (rb_stat(fname, &st) < 0)
963 rb_sys_fail(RSTRING(fname)->ptr);
964 return rb_time_new(st.st_ctime, 0);
965 }
966
967 static VALUE
968 rb_file_ctime(obj)
969 VALUE obj;
970 {
971 OpenFile *fptr;
972 struct stat st;
973
974 GetOpenFile(obj, fptr);
975 if (fstat(fileno(fptr->f), &st) == -1) {
976 rb_sys_fail(fptr->path);
977 }
978 return rb_time_new(st.st_ctime, 0);
979 }
980
981 static void
982 chmod_internal(path, mode)
983 const char *path;
984 int mode;
985 {
986 if (chmod(path, mode) < 0)
987 rb_sys_fail(path);
988 }
989
990 static VALUE
991 rb_file_s_chmod(argc, argv)
992 int argc;
993 VALUE *argv;
994 {
995 VALUE vmode;
996 VALUE rest;
997 int mode;
998 long n;
999
1000 rb_secure(2);
1001 rb_scan_args(argc, argv, "1*", &vmode, &rest);
1002 mode = NUM2INT(vmode);
1003
1004 n = apply2files(chmod_internal, rest, mode);
1005 return LONG2FIX(n);
1006 }
1007
1008 static VALUE
1009 rb_file_chmod(obj, vmode)
1010 VALUE obj, vmode;
1011 {
1012 OpenFile *fptr;
1013 int mode;
1014
1015 rb_secure(2);
1016 mode = NUM2INT(vmode);
1017
1018 GetOpenFile(obj, fptr);
1019 #ifdef HAVE_FCHMOD
1020 if (fchmod(fileno(fptr->f), mode) == -1)
1021 rb_sys_fail(fptr->path);
1022 #else
1023 if (!fptr->path) return Qnil;
1024 if (chmod(fptr->path, mode) == -1)
1025 rb_sys_fail(fptr->path);
1026 #endif
1027
1028 return INT2FIX(0);
1029 }
1030
1031 #if defined(HAVE_LCHMOD)
1032 static void
1033 lchmod_internal(path, mode)
1034 const char *path;
1035 int mode;
1036 {
1037 if (lchmod(path, mode) < 0)
1038 rb_sys_fail(path);
1039 }
1040
1041 static VALUE
1042 rb_file_s_lchmod(argc, argv)
1043 int argc;
1044 VALUE *argv;
1045 {
1046 VALUE vmode;
1047 VALUE rest;
1048 int mode;
1049 long n;
1050
1051 rb_secure(2);
1052 rb_scan_args(argc, argv, "1*", &vmode, &rest);
1053 mode = NUM2INT(vmode);
1054
1055 n = apply2files(lchmod_internal, rest, mode);
1056 return LONG2FIX(n);
1057 }
1058 #else
1059 static VALUE
1060 rb_file_s_lchmod(argc, argv)
1061 int argc;
1062 VALUE *argv;
1063 {
1064 rb_notimplement();
1065 }
1066 #endif
1067
1068 struct chown_args {
1069 int owner, group;
1070 };
1071
1072 static void
1073 chown_internal(path, args)
1074 const char *path;
1075 struct chown_args *args;
1076 {
1077 if (chown(path, args->owner, args->group) < 0)
1078 rb_sys_fail(path);
1079 }
1080
1081 static VALUE
1082 rb_file_s_chown(argc, argv)
1083 int argc;
1084 VALUE *argv;
1085 {
1086 VALUE o, g, rest;
1087 struct chown_args arg;
1088 long n;
1089
1090 rb_secure(2);
1091 rb_scan_args(argc, argv, "2*", &o, &g, &rest);
1092 if (NIL_P(o)) {
1093 arg.owner = -1;
1094 }
1095 else {
1096 arg.owner = NUM2INT(o);
1097 }
1098 if (NIL_P(g)) {
1099 arg.group = -1;
1100 }
1101 else {
1102 arg.group = NUM2INT(g);
1103 }
1104
1105 n = apply2files(chown_internal, rest, &arg);
1106 return LONG2FIX(n);
1107 }
1108
1109 static VALUE
1110 rb_file_chown(obj, owner, group)
1111 VALUE obj, owner, group;
1112 {
1113 OpenFile *fptr;
1114
1115 rb_secure(2);
1116 GetOpenFile(obj, fptr);
1117 #if defined(DJGPP) || defined(__CYGWIN32__) || defined(NT) || defined(__EMX__)
1118 if (!fptr->path) return Qnil;
1119 if (chown(fptr->path, NUM2INT(owner), NUM2INT(group)) == -1)
1120 rb_sys_fail(fptr->path);
1121 #else
1122 if (fchown(fileno(fptr->f), NUM2INT(owner), NUM2INT(group)) == -1)
1123 rb_sys_fail(fptr->path);
1124 #endif
1125
1126 return INT2FIX(0);
1127 }
1128
1129 #if defined(HAVE_LCHOWN) && !defined(__CHECKER__)
1130 static void
1131 lchown_internal(path, args)
1132 const char *path;
1133 struct chown_args *args;
1134 {
1135 if (lchown(path, args->owner, args->group) < 0)
1136 rb_sys_fail(path);
1137 }
1138
1139 static VALUE
1140 rb_file_s_lchown(argc, argv)
1141 int argc;
1142 VALUE *argv;
1143 {
1144 VALUE o, g, rest;
1145 struct chown_args arg;
1146 long n;
1147
1148 rb_secure(2);
1149 rb_scan_args(argc, argv, "2*", &o, &g, &rest);
1150 if (NIL_P(o)) {
1151 arg.owner = -1;
1152 }
1153 else {
1154 arg.owner = NUM2INT(o);
1155 }
1156 if (NIL_P(g)) {
1157 arg.group = -1;
1158 }
1159 else {
1160 arg.group = NUM2INT(g);
1161 }
1162
1163 n = apply2files(lchown_internal, rest, &arg);
1164 return LONG2FIX(n);
1165 }
1166 #else
1167 static VALUE
1168 rb_file_s_lchown(argc, argv)
1169 int argc;
1170 VALUE *argv;
1171 {
1172 rb_notimplement();
1173 }
1174 #endif
1175
1176 struct timeval rb_time_timeval();
1177
1178 #if defined(HAVE_UTIMES) && !defined(__CHECKER__)
1179
1180 static void
1181 utime_internal(path, tvp)
1182 char *path;
1183 struct timeval tvp[];
1184 {
1185 if (utimes(path, tvp) < 0)
1186 rb_sys_fail(path);
1187 }
1188
1189 static VALUE
1190 rb_file_s_utime(argc, argv)
1191 int argc;
1192 VALUE *argv;
1193 {
1194 VALUE atime, mtime, rest;
1195 struct timeval tvp[2];
1196 long n;
1197
1198 rb_scan_args(argc, argv, "2*", &atime, &mtime, &rest);
1199
1200 tvp[0] = rb_time_timeval(atime);
1201 tvp[1] = rb_time_timeval(mtime);
1202
1203 n = apply2files(utime_internal, rest, tvp);
1204 return LONG2FIX(n);
1205 }
1206
1207 #else
1208
1209 #ifndef HAVE_UTIME_H
1210 # ifdef NT
1211 # if defined(__BORLANDC__)
1212 # include <utime.h>
1213 # else
1214 # include <sys/utime.h>
1215 # endif
1216 # if defined(_MSC_VER) || defined __MINGW32__
1217 # define utimbuf _utimbuf
1218 # endif
1219 # else
1220 struct utimbuf {
1221 long actime;
1222 long modtime;
1223 };
1224 # endif
1225 #endif
1226
1227 static void
1228 utime_internal(path, utp)
1229 const char *path;
1230 struct utimbuf *utp;
1231 {
1232 if (utime(path, utp) < 0)
1233 rb_sys_fail(path);
1234 }
1235
1236 static VALUE
1237 rb_file_s_utime(argc, argv)
1238 int argc;
1239 VALUE *argv;
1240 {
1241 VALUE atime, mtime, rest;
1242 long n;
1243 struct timeval tv;
1244 struct utimbuf utbuf;
1245
1246 rb_scan_args(argc, argv, "2*", &atime, &mtime, &rest);
1247
1248 tv = rb_time_timeval(atime);
1249 utbuf.actime = tv.tv_sec;
1250 tv = rb_time_timeval(mtime);
1251 utbuf.modtime = tv.tv_sec;
1252
1253 n = apply2files(utime_internal, rest, &utbuf);
1254 return LONG2FIX(n);
1255 }
1256
1257 #endif
1258
1259 static VALUE
1260 rb_file_s_link(klass, from, to)
1261 VALUE klass, from, to;
1262 {
1263 SafeStringValue(from);
1264 SafeStringValue(to);
1265
1266 if (link(RSTRING(from)->ptr, RSTRING(to)->ptr) < 0)
1267 rb_sys_fail(RSTRING(from)->ptr);
1268 return INT2FIX(0);
1269 }
1270
1271 static VALUE
1272 rb_file_s_symlink(klass, from, to)
1273 VALUE klass, from, to;
1274 {
1275 #ifdef HAVE_SYMLINK
1276 SafeStringValue(from);
1277 SafeStringValue(to);
1278
1279 if (symlink(RSTRING(from)->ptr, RSTRING(to)->ptr) < 0)
1280 rb_sys_fail(RSTRING(from)->ptr);
1281 return INT2FIX(0);
1282 #else
1283 rb_notimplement();
1284 return Qnil;
1285 #endif
1286 }
1287
1288 static VALUE
1289 rb_file_s_readlink(klass, path)
1290 VALUE klass, path;
1291 {
1292 #ifdef HAVE_READLINK
1293 char *buf;
1294 int size = 100;
1295 int rv;
1296 VALUE v;
1297
1298 SafeStringValue(path);
1299 buf = xmalloc(size);
1300 if ((rv = readlink(RSTRING(path)->ptr, buf, size)) == size) {
1301 size *= 2;
1302 buf = xrealloc(buf, size);
1303 }
1304 if (rv < 0) {
1305 free(buf);
1306 rb_sys_fail(RSTRING(path)->ptr);
1307 }
1308 v = rb_tainted_str_new(buf, rv);
1309 free(buf);
1310
1311 return v;
1312 #else
1313 rb_notimplement();
1314 return Qnil;
1315 #endif
1316 }
1317
1318 static void
1319 unlink_internal(path)
1320 const char *path;
1321 {
1322 if (unlink(path) < 0)
1323 rb_sys_fail(path);
1324 }
1325
1326 static VALUE
1327 rb_file_s_unlink(klass, args)
1328 VALUE klass, args;
1329 {
1330 long n;
1331
1332 rb_secure(2);
1333 n = apply2files(unlink_internal, args, 0);
1334 return LONG2FIX(n);
1335 }
1336
1337 static VALUE
1338 rb_file_s_rename(klass, from, to)
1339 VALUE klass, from, to;
1340 {
1341 SafeStringValue(from);
1342 SafeStringValue(to);
1343
1344 if (rename(RSTRING(from)->ptr, RSTRING(to)->ptr) < 0) {
1345 #if defined __CYGWIN__
1346 extern unsigned long __attribute__((stdcall)) GetLastError();
1347 errno = GetLastError();
1348 #endif
1349 rb_sys_fail(RSTRING(from)->ptr);
1350 }
1351
1352 return INT2FIX(0);
1353 }
1354
1355 static VALUE
1356 rb_file_s_umask(argc, argv)
1357 int argc;
1358 VALUE *argv;
1359 {
1360 int omask = 0;
1361
1362 rb_secure(2);
1363 if (argc == 0) {
1364 omask = umask(0);
1365 umask(omask);
1366 }
1367 else if (argc == 1) {
1368 omask = umask(NUM2INT(argv[0]));
1369 }
1370 else {
1371 rb_raise(rb_eArgError, "wrong number of argument");
1372 }
1373 return INT2FIX(omask);
1374 }
1375
1376 #if defined DOSISH
1377 #define isdirsep(x) ((x) == '/' || (x) == '\\')
1378 #else
1379 #define isdirsep(x) ((x) == '/')
1380 #endif
1381 #ifndef CharNext
1382 # if defined(DJGPP)
1383 # define CharNext(p) ((p) + mblen(p, MB_CUR_MAX))
1384 # else
1385 # define CharNext(p) ((p) + 1)
1386 # endif
1387 #endif
1388
1389 static char *
1390 strrdirsep(path)
1391 char *path;
1392 {
1393 char *last = NULL;
1394 while (*path) {
1395 if (isdirsep(*path)) {
1396 last = path++;
1397 }
1398 else {
1399 path = CharNext(path);
1400 }
1401 }
1402 return last;
1403 }
1404
1405 #define BUFCHECK(cond) while (cond) {\
1406 long bdiff = p - buf;\
1407 buflen *= 2;\
1408 rb_str_resize(result, buflen);\
1409 buf = RSTRING(result)->ptr;\
1410 p = buf + bdiff;\
1411 pend = buf + buflen;\
1412 }
1413
1414 VALUE
1415 rb_file_s_expand_path(argc, argv)
1416 int argc;
1417 VALUE *argv;
1418 {
1419 VALUE fname, dname, result;
1420 char *s, *buf, *b, *p, *pend;
1421 long buflen = MAXPATHLEN;
1422 int tainted;
1423
1424 rb_scan_args(argc, argv, "11", &fname, &dname);
1425 result = rb_str_new(0, buflen + 2);
1426
1427 s = StringValuePtr(fname);
1428 p = buf = RSTRING(result)->ptr;
1429 pend = p + buflen;
1430 tainted = OBJ_TAINTED(fname);
1431
1432 if (s[0] == '~') {
1433 if (isdirsep(s[1]) || s[1] == '\0') {
1434 char *dir = getenv("HOME");
1435
1436 if (!dir) {
1437 rb_raise(rb_eArgError, "couldn't find HOME environment -- expanding `%s'", s);
1438 }
1439 BUFCHECK (strlen(dir) > buflen);
1440 strcpy(buf, dir);
1441 p = buf + strlen(dir);
1442 s++;
1443 tainted = 1;
1444 }
1445 else {
1446 #ifdef HAVE_PWD_H
1447 struct passwd *pwPtr;
1448 s++;
1449 #endif
1450 b = s;
1451 while (*s && !isdirsep(*s)) {
1452 s = CharNext(s);
1453 }
1454 BUFCHECK (p + (s-b) >= pend);
1455 memcpy(p, b, s-b);
1456 p += s-b;
1457 *p = '\0';
1458 #ifdef HAVE_PWD_H
1459 pwPtr = getpwnam(buf);
1460 if (!pwPtr) {
1461 endpwent();
1462 rb_raise(rb_eArgError, "user %s doesn't exist", buf);
1463 }
1464 BUFCHECK (strlen(pwPtr->pw_dir) > buflen);
1465 strcpy(buf, pwPtr->pw_dir);
1466 p = buf + strlen(pwPtr->pw_dir);
1467 endpwent();
1468 #endif
1469 }
1470 }
1471 #if defined DOSISH || defined __CYGWIN__
1472
1473 else if (ISALPHA(s[0]) && s[1] == ':' && isdirsep(s[2])) {
1474 b = s;
1475 while (*s && !isdirsep(*s)) {
1476 s = CharNext(s);
1477 }
1478 BUFCHECK (p + (s-b) >= pend);
1479 memcpy(p, b, s-b);
1480 p += s-b;
1481 }
1482 #endif
1483 else if (!isdirsep(*s)) {
1484 if (!NIL_P(dname)) {
1485 dname = rb_file_s_expand_path(1, &dname);
1486 if (OBJ_TAINTED(dname)) tainted = 1;
1487 BUFCHECK (RSTRING(dname)->len > buflen);
1488 memcpy(buf, RSTRING(dname)->ptr, RSTRING(dname)->len);
1489 p += RSTRING(dname)->len;
1490 }
1491 else {
1492 char *dir = my_getcwd();
1493
1494 tainted = 1;
1495 BUFCHECK (strlen(dir) > buflen);
1496 strcpy(buf, dir);
1497 free(dir);
1498 p = &buf[strlen(buf)];
1499 }
1500 while (p > buf && *(p - 1) == '/') p--;
1501 }
1502 else {
1503 while (*s && isdirsep(*s)) {
1504 *p++ = '/';
1505 BUFCHECK (p >= pend);
1506 s++;
1507 }
1508 if (p > buf && *s) p--;
1509 }
1510 *p = '/';
1511
1512 b = s;
1513 while (*s) {
1514 switch (*s) {
1515 case '.':
1516 if (b == s++) {
1517 switch (*s) {
1518 case '\0':
1519 b = s;
1520 break;
1521 case '.':
1522 if (*(s+1) == '\0' || isdirsep(*(s+1))) {
1523
1524 *p = '\0';
1525 if (!(b = strrdirsep(buf))) {
1526 *p = '/';
1527 }
1528 else {
1529 p = b;
1530 }
1531 b = ++s;
1532 }
1533 break;
1534 case '/':
1535 #if defined DOSISH
1536 case '\\':
1537 #endif
1538 b = ++s;
1539 break;
1540 default:
1541
1542 break;
1543 }
1544 }
1545 break;
1546 case '/':
1547 #if defined DOSISH
1548 case '\\':
1549 #endif
1550 if (s > b) {
1551 BUFCHECK (p + (s-b+1) >= pend);
1552 memcpy(++p, b, s-b);
1553 p += s-b;
1554 *p = '/';
1555 }
1556 b = ++s;
1557 break;
1558 default:
1559 s = CharNext(s);
1560 break;
1561 }
1562 }
1563
1564 if (s > b) {
1565 BUFCHECK (p + (s-b) >= pend);
1566 memcpy(++p, b, s-b);
1567 p += s-b;
1568 }
1569 #if defined DOSISH || defined __CYGWIN__
1570 else if (ISALPHA(buf[0]) && (buf[1] == ':') && isdirsep(buf[2])) {
1571
1572
1573 if (p == (buf+2)) p++;
1574 }
1575 else if (isdirsep(buf[0]) && isdirsep(buf[1])) {
1576 if (p == (buf+1)) p++;
1577 }
1578 #endif
1579
1580 if (tainted) OBJ_TAINT(result);
1581 RSTRING(result)->len = p - buf;
1582 *p = '\0';
1583 return result;
1584 }
1585
1586 static int
1587 rmext(p, e)
1588 const char *p, *e;
1589 {
1590 int l1, l2;
1591
1592 if (!e) return 0;
1593
1594 l1 = strlen(p);
1595 l2 = strlen(e);
1596 if (l2 == 2 && e[1] == '*') {
1597 e = strrchr(p, *e);
1598 if (!e) return 0;
1599 return e - p;
1600 }
1601 if (l1 < l2) return l1;
1602
1603 if (strcmp(p+l1-l2, e) == 0) {
1604 return l1-l2;
1605 }
1606 return 0;
1607 }
1608
1609 static VALUE
1610 rb_file_s_basename(argc, argv)
1611 int argc;
1612 VALUE *argv;
1613 {
1614 VALUE fname, fext, basename;
1615 char *name, *p, *ext = NULL;
1616 int f;
1617
1618 if (rb_scan_args(argc, argv, "11", &fname, &fext) == 2) {
1619 ext = StringValuePtr(fext);
1620 }
1621 name = StringValuePtr(fname);
1622 p = strrdirsep(name);
1623 if (!p) {
1624 if (NIL_P(fext) || !(f = rmext(name, ext)))
1625 return fname;
1626 basename = rb_str_new(name, f);
1627 }
1628 else {
1629 p++;
1630 if (NIL_P(fext) || !(f = rmext(p, ext))) {
1631 basename = rb_str_new2(p);
1632 }
1633 else {
1634 basename = rb_str_new(p, f);
1635 }
1636 }
1637 OBJ_INFECT(basename, fname);
1638 return basename;
1639 }
1640
1641 static VALUE
1642 rb_file_s_dirname(klass, fname)
1643 VALUE klass, fname;
1644 {
1645 char *name, *p;
1646 VALUE dirname;
1647
1648 name = StringValuePtr(fname);
1649 p = strrdirsep(name);
1650 if (!p) {
1651 return rb_str_new2(".");
1652 }
1653 if (p == name)
1654 p++;
1655 dirname = rb_str_new(name, p - name);
1656 OBJ_INFECT(dirname, fname);
1657 return dirname;
1658 }
1659
1660 static VALUE
1661 rb_file_s_extname(klass, fname)
1662 VALUE klass, fname;
1663 {
1664 char *name, *p, *e;
1665 VALUE extname;
1666
1667 name = StringValuePtr(fname);
1668 p = strrdirsep(name);
1669 if (!p)
1670 p = name;
1671 else
1672 p++;
1673
1674 e = strrchr(p, '.');
1675 if (!e || e == p)
1676 return rb_str_new2("");
1677 extname = rb_str_new2(e);
1678 OBJ_INFECT(extname, fname);
1679 return extname;
1680 }
1681
1682 static VALUE
1683 rb_file_s_split(klass, path)
1684 VALUE klass, path;
1685 {
1686 return rb_assoc_new(rb_file_s_dirname(Qnil, path), rb_file_s_basename(1,&path));
1687 }
1688
1689 static VALUE separator;
1690
1691 static VALUE
1692 rb_file_s_join(klass, args)
1693 VALUE klass, args;
1694 {
1695 return rb_ary_join(args, separator);
1696 }
1697
1698 static VALUE
1699 rb_file_s_truncate(klass, path, len)
1700 VALUE klass, path, len;
1701 {
1702 rb_secure(2);
1703 SafeStringValue(path);
1704
1705 #ifdef HAVE_TRUNCATE
1706 if (truncate(RSTRING(path)->ptr, NUM2OFFT(len)) < 0)
1707 rb_sys_fail(RSTRING(path)->ptr);
1708 #else
1709 # ifdef HAVE_CHSIZE
1710 {
1711 int tmpfd;
1712
1713 # if defined(NT)
1714 if ((tmpfd = open(RSTRING(path)->ptr, O_RDWR)) < 0) {
1715 rb_sys_fail(RSTRING(path)->ptr);
1716 }
1717 # else
1718 if ((tmpfd = open(RSTRING(path)->ptr, 0)) < 0) {
1719 rb_sys_fail(RSTRING(path)->ptr);
1720 }
1721 # endif
1722 if (chsize(tmpfd, NUM2OFFT(len)) < 0) {
1723 close(tmpfd);
1724 rb_sys_fail(RSTRING(path)->ptr);
1725 }
1726 close(tmpfd);
1727 }
1728 # else
1729 rb_notimplement();
1730 # endif
1731 #endif
1732 return INT2FIX(0);
1733 }
1734
1735 static VALUE
1736 rb_file_truncate(obj, len)
1737 VALUE obj, len;
1738 {
1739 OpenFile *fptr;
1740
1741 rb_secure(2);
1742 GetOpenFile(obj, fptr);
1743 if (!(fptr->mode & FMODE_WRITABLE)) {
1744 rb_raise(rb_eIOError, "not opened for writing");
1745 }
1746 #ifdef HAVE_TRUNCATE
1747 if (ftruncate(fileno(fptr->f), NUM2OFFT(len)) < 0)
1748 rb_sys_fail(fptr->path);
1749 #else
1750 # ifdef HAVE_CHSIZE
1751 if (chsize(fileno(fptr->f), NUM2OFFT(len)) < 0)
1752 rb_sys_fail(fptr->path);
1753 # else
1754 rb_notimplement();
1755 # endif
1756 #endif
1757 return INT2FIX(0);
1758 }
1759
1760 # ifndef LOCK_SH
1761 # define LOCK_SH 1
1762 # endif
1763 # ifndef LOCK_EX
1764 # define LOCK_EX 2
1765 # endif
1766 # ifndef LOCK_NB
1767 # define LOCK_NB 4
1768 # endif
1769 # ifndef LOCK_UN
1770 # define LOCK_UN 8
1771 # endif
1772
1773 #if 0
1774 static int
1775 rb_thread_flock(fd, op, fptr)
1776 int fd, op;
1777 OpenFile *fptr;
1778 {
1779 if (rb_thread_alone() || (op & LOCK_NB)) {
1780 return flock(fd, op);
1781 }
1782 op |= LOCK_NB;
1783 while (flock(fd, op) < 0) {
1784 switch (errno) {
1785 case EAGAIN:
1786 case EACCES:
1787 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
1788 case EWOULDBLOCK:
1789 #endif
1790 rb_thread_polling();
1791 rb_io_check_closed(fptr);
1792 continue;
1793 default:
1794 return -1;
1795 }
1796 }
1797 return 0;
1798 }
1799 #define flock(fd, op) rb_thread_flock(fd, op, fptr)
1800 #endif
1801
1802 static VALUE
1803 rb_file_flock(obj, operation)
1804 VALUE obj;
1805 VALUE operation;
1806 {
1807 #ifndef __CHECKER__
1808 OpenFile *fptr;
1809 int ret;
1810
1811 rb_secure(2);
1812 GetOpenFile(obj, fptr);
1813
1814 if (fptr->mode & FMODE_WRITABLE) {
1815 fflush(GetWriteFile(fptr));
1816 }
1817 TRAP_BEG;
1818 ret = flock(fileno(fptr->f), NUM2INT(operation));
1819 TRAP_END;
1820 if (ret < 0) {
1821 switch (errno) {
1822 case EAGAIN:
1823 case EACCES:
1824 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
1825 case EWOULDBLOCK:
1826 #endif
1827 return Qfalse;
1828 }
1829 rb_sys_fail(fptr->path);
1830 }
1831 #endif
1832 return INT2FIX(0);
1833 }
1834 #undef flock
1835
1836 static void
1837 test_check(n, argc, argv)
1838 int n, argc;
1839 VALUE *argv;
1840 {
1841 int i;
1842
1843 n+=1;
1844 if (n != argc) rb_raise(rb_eArgError, "wrong number of arguments(%d for %d)", argc, n);
1845 for (i=1; i<n; i++) {
1846 switch (TYPE(argv[i])) {
1847 case T_STRING:
1848 SafeStringValue(argv[i]);
1849 break;
1850 case T_FILE:
1851 break;
1852 default:
1853 Check_Type(argv[i], T_STRING);
1854 break;
1855 }
1856 }
1857 }
1858
1859 #define CHECK(n) test_check((n), argc, argv)
1860
1861 static VALUE
1862 rb_f_test(argc, argv)
1863 int argc;
1864 VALUE *argv;
1865 {
1866 int cmd;
1867
1868 if (argc == 0) rb_raise(rb_eArgError, "wrong number of arguments");
1869 #if 0
1870 if (argc == 1) {
1871 return RTEST(argv[0]) ? Qtrue : Qfalse;
1872 }
1873 #endif
1874 cmd = NUM2CHR(argv[0]);
1875 if (cmd == 0) return Qfalse;
1876 if (strchr("bcdefgGkloOprRsSuwWxXz", cmd)) {
1877 CHECK(1);
1878 switch (cmd) {
1879 case 'b':
1880 return test_b(0, argv[1]);
1881
1882 case 'c':
1883 return test_c(0, argv[1]);
1884
1885 case 'd':
1886 return test_d(0, argv[1]);
1887
1888 case 'a':
1889 case 'e':
1890 return test_e(0, argv[1]);
1891
1892 case 'f':
1893 return test_f(0, argv[1]);
1894
1895 case 'g':
1896 return test_sgid(0, argv[1]);
1897
1898 case 'G':
1899 return test_grpowned(0, argv[1]);
1900
1901 case 'k':
1902 return test_sticky(0, argv[1]);
1903
1904 case 'l':
1905 return test_l(0, argv[1]);
1906
1907 case 'o':
1908 return test_owned(0, argv[1]);
1909
1910 case 'O':
1911 return test_rowned(0, argv[1]);
1912
1913 case 'p':
1914 return test_p(0, argv[1]);
1915
1916 case 'r':
1917 return test_r(0, argv[1]);
1918
1919 case 'R':
1920 return test_R(0, argv[1]);
1921
1922 case 's':
1923 return test_s(0, argv[1]);
1924
1925 case 'S':
1926 return test_S(0, argv[1]);
1927
1928 case 'u':
1929 return test_suid(0, argv[1]);
1930
1931 case 'w':
1932 return test_w(0, argv[1]);
1933
1934 case 'W':
1935 return test_W(0, argv[1]);
1936
1937 case 'x':
1938 return test_x(0, argv[1]);
1939
1940 case 'X':
1941 return test_X(0, argv[1]);
1942
1943 case 'z':
1944 return test_z(0, argv[1]);
1945 }
1946 }
1947
1948 if (strchr("MAC", cmd)) {
1949 struct stat st;
1950
1951 CHECK(1);
1952 if (rb_stat(argv[1], &st) == -1) {
1953 rb_sys_fail(RSTRING(argv[1])->ptr);
1954 }
1955
1956 switch (cmd) {
1957 case 'A':
1958 return rb_time_new(st.st_atime, 0);
1959 case 'M':
1960 return rb_time_new(st.st_mtime, 0);
1961 case 'C':
1962 return rb_time_new(st.st_ctime, 0);
1963 }
1964 }
1965
1966 if (strchr("-=<>", cmd)) {
1967 struct stat st1, st2;
1968
1969 CHECK(2);
1970 if (rb_stat(argv[1], &st1) < 0) return Qfalse;
1971 if (rb_stat(argv[2], &st2) < 0) return Qfalse;
1972
1973 switch (cmd) {
1974 case '-':
1975 if (st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino)
1976 return Qtrue;
1977 return Qfalse;
1978
1979 case '=':
1980 if (st1.st_mtime == st2.st_mtime) return Qtrue;
1981 return Qfalse;
1982
1983 case '>':
1984 if (st1.st_mtime > st2.st_mtime) return Qtrue;
1985 return Qfalse;
1986
1987 case '<':
1988 if (st1.st_mtime < st2.st_mtime) return Qtrue;
1989 return Qfalse;
1990 }
1991 }
1992
1993 rb_raise(rb_eArgError, "unknown command ?%c", cmd);
1994 return Qnil;
1995 }
1996
1997 static VALUE
1998 rb_stat_s_alloc(klass)
1999 VALUE klass;
2000 {
2001 return stat_new_0(klass, 0);
2002 }
2003
2004 static VALUE
2005 rb_stat_init(obj, fname)
2006 VALUE obj, fname;
2007 {
2008 struct stat st, *nst;
2009
2010 SafeStringValue(fname);
2011
2012 if (stat(RSTRING(fname)->ptr, &st) == -1) {
2013 rb_sys_fail(RSTRING(fname)->ptr);
2014 }
2015 if (DATA_PTR(obj)) {
2016 free(DATA_PTR(obj));
2017 DATA_PTR(obj) = NULL;
2018 }
2019 nst = ALLOC(struct stat);
2020 *nst = st;
2021 DATA_PTR(obj) = nst;
2022
2023 return Qnil;
2024 }
2025
2026 static VALUE
2027 rb_stat_become(copy, orig)
2028 VALUE copy, orig;
2029 {
2030 struct stat *nst;
2031
2032 if (copy == orig) return orig;
2033 rb_check_frozen(copy);
2034
2035 if (!rb_obj_is_instance_of(orig, rb_obj_class(copy))) {
2036 rb_raise(rb_eTypeError, "wrong argument class");
2037 }
2038 if (DATA_PTR(copy)) {
2039 free(DATA_PTR(copy));
2040 DATA_PTR(copy) = 0;
2041 }
2042 if (DATA_PTR(orig)) {
2043 nst = ALLOC(struct stat);
2044 *nst = *(struct stat*)DATA_PTR(orig);
2045 DATA_PTR(copy) = nst;
2046 }
2047
2048 return copy;
2049 }
2050
2051 static VALUE
2052 rb_stat_ftype(obj)
2053 VALUE obj;
2054 {
2055 return rb_file_ftype(get_stat(obj));
2056 }
2057
2058 static VALUE
2059 rb_stat_d(obj)
2060 VALUE obj;
2061 {
2062 if (S_ISDIR(get_stat(obj)->st_mode)) return Qtrue;
2063 return Qfalse;
2064 }
2065
2066 static VALUE
2067 rb_stat_p(obj)
2068 VALUE obj;
2069 {
2070 #ifdef S_IFIFO
2071 if (S_ISFIFO(get_stat(obj)->st_mode)) return Qtrue;
2072
2073 #endif
2074 return Qfalse;
2075 }
2076
2077 static VALUE
2078 rb_stat_l(obj)
2079 VALUE obj;
2080 {
2081 #ifdef S_ISLNK
2082 if (S_ISLNK(get_stat(obj)->st_mode)) return Qtrue;
2083 #endif
2084 return Qfalse;
2085 }
2086
2087 static VALUE
2088 rb_stat_S(obj)
2089 VALUE obj;
2090 {
2091 #ifdef S_ISSOCK
2092 if (S_ISSOCK(get_stat(obj)->st_mode)) return Qtrue;
2093
2094 #endif
2095 return Qfalse;
2096 }
2097
2098 static VALUE
2099 rb_stat_b(obj)
2100 VALUE obj;
2101 {
2102 #ifdef S_ISBLK
2103 if (S_ISBLK(get_stat(obj)->st_mode)) return Qtrue;
2104
2105 #endif
2106 return Qfalse;
2107 }
2108
2109 static VALUE
2110 rb_stat_c(obj)
2111 VALUE obj;
2112 {
2113 if (S_ISCHR(get_stat(obj)->st_mode)) return Qtrue;
2114
2115 return Qfalse;
2116 }
2117
2118 static VALUE
2119 rb_stat_owned(obj)
2120 VALUE obj;
2121 {
2122 if (get_stat(obj)->st_uid == geteuid()) return Qtrue;
2123 return Qfalse;
2124 }
2125
2126 static VALUE
2127 rb_stat_rowned(obj)
2128 VALUE obj;
2129 {
2130 if (get_stat(obj)->st_uid == getuid()) return Qtrue;
2131 return Qfalse;
2132 }
2133
2134 static VALUE
2135 rb_stat_grpowned(obj)
2136 VALUE obj;
2137 {
2138 #ifndef NT
2139 if (get_stat(obj)->st_gid == getegid()) return Qtrue;
2140 #endif
2141 return Qfalse;
2142 }
2143
2144 static VALUE
2145 rb_stat_r(obj)
2146 VALUE obj;
2147 {
2148 struct stat *st = get_stat(obj);
2149
2150 #ifdef S_IRUSR
2151 if (rb_stat_owned(obj))
2152 return st->st_mode & S_IRUSR ? Qtrue : Qfalse;
2153 #endif
2154 #ifdef S_IRGRP
2155 if (rb_stat_grpowned(obj))
2156 return st->st_mode & S_IRGRP ? Qtrue : Qfalse;
2157 #endif
2158 #ifdef S_IROTH
2159 if (!(st->st_mode & S_IROTH)) return Qfalse;
2160 #endif
2161 return Qtrue;
2162 }
2163
2164 static VALUE
2165 rb_stat_R(obj)
2166 VALUE obj;
2167 {
2168 struct stat *st = get_stat(obj);
2169
2170 #ifdef S_IRUSR
2171 if (rb_stat_rowned(obj))
2172 return st->st_mode & S_IRUSR ? Qtrue : Qfalse;
2173 #endif
2174 #ifdef S_IRGRP
2175 if (group_member(get_stat(obj)->st_gid))
2176 return st->st_mode & S_IRGRP ? Qtrue : Qfalse;
2177 #endif
2178 #ifdef S_IROTH
2179 if (!(st->st_mode & S_IROTH)) return Qfalse;
2180 #endif
2181 return Qtrue;
2182 }
2183
2184 static VALUE
2185 rb_stat_w(obj)
2186 VALUE obj;
2187 {
2188 struct stat *st = get_stat(obj);
2189
2190 #ifdef S_IWUSR
2191 if (rb_stat_owned(obj))
2192 return st->st_mode & S_IWUSR ? Qtrue : Qfalse;
2193 #endif
2194 #ifdef S_IWGRP
2195 if (rb_stat_grpowned(obj))
2196 return st->st_mode & S_IWGRP ? Qtrue : Qfalse;
2197 #endif
2198 #ifdef S_IWOTH
2199 if (!(st->st_mode & S_IWOTH)) return Qfalse;
2200 #endif
2201 return Qtrue;
2202 }
2203
2204 static VALUE
2205 rb_stat_W(obj)
2206 VALUE obj;
2207 {
2208 struct stat *st = get_stat(obj);
2209
2210 #ifdef S_IWUSR
2211 if (rb_stat_rowned(obj))
2212 return st->st_mode & S_IWUSR ? Qtrue : Qfalse;
2213 #endif
2214 #ifdef S_IWGRP
2215 if (group_member(get_stat(obj)->st_gid))
2216 return st->st_mode & S_IWGRP ? Qtrue : Qfalse;
2217 #endif
2218 #ifdef S_IWOTH
2219 if (!(st->st_mode & S_IWOTH)) return Qfalse;
2220 #endif
2221 return Qtrue;
2222 }
2223
2224 static VALUE
2225 rb_stat_x(obj)
2226 VALUE obj;
2227 {
2228 struct stat *st = get_stat(obj);
2229
2230 #ifdef S_IXUSR
2231 if (rb_stat_owned(obj))
2232 return st->st_mode & S_IXUSR ? Qtrue : Qfalse;
2233 #endif
2234 #ifdef S_IXGRP
2235 if (rb_stat_grpowned(obj))
2236 return st->st_mode & S_IXGRP ? Qtrue : Qfalse;
2237 #endif
2238 #ifdef S_IXOTH
2239 if (!(st->st_mode & S_IXOTH)) return Qfalse;
2240 #endif
2241 return Qtrue;
2242 }
2243
2244 static VALUE
2245 rb_stat_X(obj)
2246 VALUE obj;
2247 {
2248 struct stat *st = get_stat(obj);
2249
2250 #ifdef S_IXUSR
2251 if (rb_stat_rowned(obj))
2252 return st->st_mode & S_IXUSR ? Qtrue : Qfalse;
2253 #endif
2254 #ifdef S_IXGRP
2255 if (group_member(get_stat(obj)->st_gid))
2256 return st->st_mode & S_IXGRP ? Qtrue : Qfalse;
2257 #endif
2258 #ifdef S_IXOTH
2259 if (!(st->st_mode & S_IXOTH)) return Qfalse;
2260 #endif
2261 return Qtrue;
2262 }
2263
2264 static VALUE
2265 rb_stat_f(obj)
2266 VALUE obj;
2267 {
2268 if (S_ISREG(get_stat(obj)->st_mode)) return Qtrue;
2269 return Qfalse;
2270 }
2271
2272 static VALUE
2273 rb_stat_z(obj)
2274 VALUE obj;
2275 {
2276 if (get_stat(obj)->st_size == 0) return Qtrue;
2277 return Qfalse;
2278 }
2279
2280 static VALUE
2281 rb_stat_s(obj)
2282 VALUE obj;
2283 {
2284 off_t size = get_stat(obj)->st_size;
2285
2286 if (size == 0) return Qnil;
2287 return OFFT2NUM(size);
2288 }
2289
2290 static VALUE
2291 rb_stat_suid(obj)
2292 VALUE obj;
2293 {
2294 #ifdef S_ISUID
2295 if (get_stat(obj)->st_mode & S_ISUID) return Qtrue;
2296 #endif
2297 return Qfalse;
2298 }
2299
2300 static VALUE
2301 rb_stat_sgid(obj)
2302 VALUE obj;
2303 {
2304 #ifdef S_ISGID
2305 if (get_stat(obj)->st_mode & S_ISGID) return Qtrue;
2306 #endif
2307 return Qfalse;
2308 }
2309
2310 static VALUE
2311 rb_stat_sticky(obj)
2312 VALUE obj;
2313 {
2314 #ifdef S_ISVTX
2315 if (get_stat(obj)->st_mode & S_ISVTX) return Qtrue;
2316 #endif
2317 return Qfalse;
2318 }
2319
2320 static VALUE rb_mFConst;
2321
2322 void
2323 rb_file_const(name, value)
2324 const char *name;
2325 VALUE value;
2326 {
2327 rb_define_const(rb_mFConst, name, value);
2328 rb_define_const(rb_cIO, name, value);
2329 rb_define_const(rb_cFile, name, value);
2330 }
2331
2332 static int
2333 is_absolute_path(path)
2334 const char *path;
2335 {
2336 #if defined DOSISH || defined __CYGWIN__
2337 if (ISALPHA(path[0]) && path[1] == ':' && isdirsep(path[2])) return 1;
2338 if (isdirsep(path[0]) && isdirsep(path[1])) return 1;
2339 #endif
2340 #ifndef DOSISH
2341 if (path[0] == '/') return 1;
2342 #endif
2343 return 0;
2344 }
2345
2346 #ifndef DOSISH
2347 static int
2348 path_check_1(path)
2349 VALUE path;
2350 {
2351 struct stat st;
2352 char *p0 = RSTRING(path)->ptr;
2353 char *p = 0, *s;
2354
2355 if (!is_absolute_path(p0)) {
2356 char *buf = my_getcwd();
2357 VALUE newpath;
2358
2359 newpath = rb_str_new2(buf);
2360 free(buf);
2361
2362 rb_str_cat2(newpath, "/");
2363 rb_str_cat2(newpath, p0);
2364 return path_check_1(newpath);
2365 }
2366 for (;;) {
2367 #ifndef S_IWOTH
2368 # define S_IWOTH 002
2369 #endif
2370 if (stat(p0, &st) == 0 && S_ISDIR(st.st_mode) && (st.st_mode & S_IWOTH)
2371 #ifdef S_ISVTX
2372 && (!p || !(st.st_mode & S_ISVTX))
2373 #endif
2374 ) {
2375 rb_warn("Insecure world writable dir %s, mode 0%o", p0, st.st_mode);
2376 if (p) *p = '/';
2377 return 0;
2378 }
2379 s = strrdirsep(p0);
2380 if (p) *p = '/';
2381 if (!s || s == p0) return 1;
2382 p = s;
2383 *p = '\0';
2384 }
2385 }
2386 #endif
2387
2388 int
2389 rb_path_check(path)
2390 char *path;
2391 {
2392 #ifndef DOSISH
2393 char *p0, *p, *pend;
2394 const char sep = PATH_SEP_CHAR;
2395
2396 if (!path) return 1;
2397
2398 pend = path + strlen(path);
2399 p0 = path;
2400 p = strchr(path, sep);
2401 if (!p) p = pend;
2402
2403 for (;;) {
2404 if (!path_check_1(rb_str_new(p0, p - p0))) {
2405 return 0;
2406 }
2407 p0 = p + 1;
2408 if (p0 > pend) break;
2409 p = strchr(p0, sep);
2410 if (!p) p = pend;
2411 }
2412 #endif
2413 return 1;
2414 }
2415
2416 #if defined(__MACOS__) || defined(riscos)
2417 static int
2418 is_macos_native_path(path)
2419 const char *path;
2420 {
2421 if (strchr(path, ':')) return 1;
2422 return 0;
2423 }
2424 #endif
2425
2426 static int
2427 file_load_ok(file)
2428 char *file;
2429 {
2430 FILE *f;
2431
2432 if (!file) return 0;
2433 f = fopen(file, "r");
2434 if (f == NULL) return 0;
2435 fclose(f);
2436 return 1;
2437 }
2438
2439 extern VALUE rb_load_path;
2440
2441 int
2442 rb_find_file_ext(filep, ext)
2443 VALUE *filep;
2444 const char * const *ext;
2445 {
2446 char *path, *found;
2447 char *f = RSTRING(*filep)->ptr;
2448 VALUE fname;
2449 long i, j;
2450
2451 if (f[0] == '~') {
2452 fname = rb_file_s_expand_path(1, filep);
2453 if (rb_safe_level() >= 2 && OBJ_TAINTED(fname)) {
2454 rb_raise(rb_eSecurityError, "loading from unsafe file %s", f);
2455 }
2456 f = StringValuePtr(fname);
2457 *filep = fname;
2458 }
2459
2460 if (is_absolute_path(f)) {
2461 for (i=0; ext[i]; i++) {
2462 fname = rb_str_dup(*filep);
2463 rb_str_cat2(fname, ext[i]);
2464 if (file_load_ok(RSTRING(fname)->ptr)) {
2465 *filep = fname;
2466 return i+1;
2467 }
2468 }
2469 return 0;
2470 }
2471
2472 if (!rb_load_path) return 0;
2473
2474 Check_Type(rb_load_path, T_ARRAY);
2475 for (i=0;i<RARRAY(rb_load_path)->len;i++) {
2476 VALUE str = RARRAY(rb_load_path)->ptr[i];
2477
2478 SafeStringValue(str);
2479 if (RSTRING(str)->len == 0) return 0;
2480 path = RSTRING(str)->ptr;
2481 for (j=0; ext[j]; j++) {
2482 fname = rb_str_dup(*filep);
2483 rb_str_cat2(fname, ext[j]);
2484 found = dln_find_file(RSTRING(fname)->ptr, path);
2485 if (found && file_load_ok(found)) {
2486 *filep = fname;
2487 return j+1;
2488 }
2489 }
2490 }
2491 return 0;
2492 }
2493
2494 VALUE
2495 rb_find_file(path)
2496 VALUE path;
2497 {
2498 VALUE tmp;
2499 char *f = RSTRING(path)->ptr;
2500 char *lpath;
2501
2502 if (f[0] == '~') {
2503 path = rb_file_s_expand_path(1, &path);
2504 if (rb_safe_level() >= 2 && OBJ_TAINTED(path)) {
2505 rb_raise(rb_eSecurityError, "loading from unsafe file %s", f);
2506 }
2507 f = StringValuePtr(path);
2508 }
2509
2510 #if defined(__MACOS__) || defined(riscos)
2511 if (is_macos_native_path(f)) {
2512 if (rb_safe_level() >= 2 && !rb_path_check(f)) {
2513 rb_raise(rb_eSecurityError, "loading from unsafe file %s", f);
2514 }
2515 if (file_load_ok(f)) return path;
2516 }
2517 #endif
2518
2519 if (is_absolute_path(f)) {
2520 if (rb_safe_level() >= 2 && !rb_path_check(f)) {
2521 rb_raise(rb_eSecurityError, "loading from unsafe file %s", f);
2522 }
2523 if (file_load_ok(f)) return path;
2524 }
2525
2526 if (rb_safe_level() >= 4) {
2527 rb_raise(rb_eSecurityError, "loading from non-absolute path %s", f);
2528 }
2529
2530 if (rb_load_path) {
2531 long i;
2532
2533 Check_Type(rb_load_path, T_ARRAY);
2534 tmp = rb_ary_new();
2535 for (i=0;i<RARRAY(rb_load_path)->len;i++) {
2536 VALUE str = RARRAY(rb_load_path)->ptr[i];
2537 SafeStringValue(str);
2538 if (RSTRING(str)->len > 0) {
2539 rb_ary_push(tmp, str);
2540 }
2541 }
2542 tmp = rb_ary_join(tmp, rb_str_new2(PATH_SEP));
2543 if (RSTRING(tmp)->len == 0) {
2544 lpath = 0;
2545 }
2546 else {
2547 lpath = RSTRING(tmp)->ptr;
2548 if (rb_safe_level() >= 2 && !rb_path_check(lpath)) {
2549 rb_raise(rb_eSecurityError, "loading from unsafe path %s", lpath);
2550 }
2551 }
2552 }
2553 else {
2554 lpath = 0;
2555 }
2556
2557 if (!lpath) {
2558 return 0;
2559 }
2560 f = dln_find_file(f, lpath);
2561 if (file_load_ok(f)) {
2562 return rb_str_new2(f);
2563 }
2564 return 0;
2565 }
2566
2567 static void
2568 define_filetest_function(name, func, argc)
2569 const char *name;
2570 VALUE (*func)();
2571 int argc;
2572 {
2573 rb_define_module_function(rb_mFileTest, name, func, argc);
2574 rb_define_singleton_method(rb_cFile, name, func, argc);
2575 }
2576
2577 void
2578 Init_File()
2579 {
2580 rb_mFileTest = rb_define_module("FileTest");
2581 rb_cFile = rb_define_class("File", rb_cIO);
2582
2583 define_filetest_function("directory?", test_d, 1);
2584 define_filetest_function("exist?", test_e, 1);
2585 define_filetest_function("exists?", test_e, 1);
2586 define_filetest_function("readable?", test_r, 1);
2587 define_filetest_function("readable_real?", test_R, 1);
2588 define_filetest_function("writable?", test_w, 1);
2589 define_filetest_function("writable_real?", test_W, 1);
2590 define_filetest_function("executable?", test_x, 1);
2591 define_filetest_function("executable_real?", test_X, 1);
2592 define_filetest_function("file?", test_f, 1);
2593 define_filetest_function("zero?", test_z, 1);
2594 define_filetest_function("size?", test_s, 1);
2595 define_filetest_function("size", rb_file_s_size, 1);
2596 define_filetest_function("owned?", test_owned, 1);
2597 define_filetest_function("grpowned?", test_grpowned, 1);
2598
2599 define_filetest_function("pipe?", test_p, 1);
2600 define_filetest_function("symlink?", test_l, 1);
2601 define_filetest_function("socket?", test_S, 1);
2602
2603 define_filetest_function("blockdev?", test_b, 1);
2604 define_filetest_function("chardev?", test_c, 1);
2605
2606 define_filetest_function("setuid?", test_suid, 1);
2607 define_filetest_function("setgid?", test_sgid, 1);
2608 define_filetest_function("sticky?", test_sticky, 1);
2609
2610 rb_define_singleton_method(rb_cFile, "stat", rb_file_s_stat, 1);
2611 rb_define_singleton_method(rb_cFile, "lstat", rb_file_s_lstat, 1);
2612 rb_define_singleton_method(rb_cFile, "ftype", rb_file_s_ftype, 1);
2613
2614 rb_define_singleton_method(rb_cFile, "atime", rb_file_s_atime, 1);
2615 rb_define_singleton_method(rb_cFile, "mtime", rb_file_s_mtime, 1);
2616 rb_define_singleton_method(rb_cFile, "ctime", rb_file_s_ctime, 1);
2617
2618 rb_define_singleton_method(rb_cFile, "utime", rb_file_s_utime, -1);
2619 rb_define_singleton_method(rb_cFile, "chmod", rb_file_s_chmod, -1);
2620 rb_define_singleton_method(rb_cFile, "chown", rb_file_s_chown, -1);
2621 rb_define_singleton_method(rb_cFile, "lchmod", rb_file_s_lchmod, -1);
2622 rb_define_singleton_method(rb_cFile, "lchown", rb_file_s_lchown, -1);
2623
2624 rb_define_singleton_method(rb_cFile, "link", rb_file_s_link, 2);
2625 rb_define_singleton_method(rb_cFile, "symlink", rb_file_s_symlink, 2);
2626 rb_define_singleton_method(rb_cFile, "readlink", rb_file_s_readlink, 1);
2627
2628 rb_define_singleton_method(rb_cFile, "unlink", rb_file_s_unlink, -2);
2629 rb_define_singleton_method(rb_cFile, "delete", rb_file_s_unlink, -2);
2630 rb_define_singleton_method(rb_cFile, "rename", rb_file_s_rename, 2);
2631 rb_define_singleton_method(rb_cFile, "umask", rb_file_s_umask, -1);
2632 rb_define_singleton_method(rb_cFile, "truncate", rb_file_s_truncate, 2);
2633 rb_define_singleton_method(rb_cFile, "expand_path", rb_file_s_expand_path, -1);
2634 rb_define_singleton_method(rb_cFile, "basename", rb_file_s_basename, -1);
2635 rb_define_singleton_method(rb_cFile, "dirname", rb_file_s_dirname, 1);
2636 rb_define_singleton_method(rb_cFile, "extname", rb_file_s_extname, 1);
2637
2638 separator = rb_obj_freeze(rb_str_new2("/"));
2639 rb_define_const(rb_cFile, "Separator", separator);
2640 rb_define_const(rb_cFile, "SEPARATOR", separator);
2641 rb_define_singleton_method(rb_cFile, "split", rb_file_s_split, 1);
2642 rb_define_singleton_method(rb_cFile, "join", rb_file_s_join, -2);
2643
2644 #if defined DOSISH && !defined __CYGWIN__
2645 rb_define_const(rb_cFile, "ALT_SEPARATOR", rb_obj_freeze(rb_str_new2("\\")));
2646 #else
2647 rb_define_const(rb_cFile, "ALT_SEPARATOR", Qnil);
2648 #endif
2649 rb_define_const(rb_cFile, "PATH_SEPARATOR", rb_obj_freeze(rb_str_new2(PATH_SEP)));
2650
2651 rb_define_method(rb_cIO, "stat", rb_io_stat, 0);
2652 rb_define_method(rb_cFile, "lstat", rb_file_lstat, 0);
2653
2654 rb_define_method(rb_cFile, "atime", rb_file_atime, 0);
2655 rb_define_method(rb_cFile, "mtime", rb_file_mtime, 0);
2656 rb_define_method(rb_cFile, "ctime", rb_file_ctime, 0);
2657
2658 rb_define_method(rb_cFile, "chmod", rb_file_chmod, 1);
2659 rb_define_method(rb_cFile, "chown", rb_file_chown, 2);
2660 rb_define_method(rb_cFile, "truncate", rb_file_truncate, 1);
2661
2662 rb_define_method(rb_cFile, "flock", rb_file_flock, 1);
2663
2664 rb_mFConst = rb_define_module_under(rb_cFile, "Constants");
2665 rb_include_module(rb_cFile, rb_mFConst);
2666 rb_file_const("LOCK_SH", INT2FIX(LOCK_SH));
2667 rb_file_const("LOCK_EX", INT2FIX(LOCK_EX));
2668 rb_file_const("LOCK_UN", INT2FIX(LOCK_UN));
2669 rb_file_const("LOCK_NB", INT2FIX(LOCK_NB));
2670
2671 rb_define_method(rb_cFile, "path", rb_file_path, 0);
2672 rb_define_global_function("test", rb_f_test, -1);
2673
2674 rb_cStat = rb_define_class_under(rb_cFile, "Stat", rb_cObject);
2675 rb_define_singleton_method(rb_cStat, "allocate", rb_stat_s_alloc, 0);
2676 rb_define_method(rb_cStat, "initialize", rb_stat_init, 1);
2677 rb_define_method(rb_cStat, "become", rb_stat_become, 1);
2678
2679 rb_include_module(rb_cStat, rb_mComparable);
2680
2681 rb_define_method(rb_cStat, "<=>", rb_stat_cmp, 1);
2682
2683 rb_define_method(rb_cStat, "dev", rb_stat_dev, 0);
2684 rb_define_method(rb_cStat, "ino", rb_stat_ino, 0);
2685 rb_define_method(rb_cStat, "mode", rb_stat_mode, 0);
2686 rb_define_method(rb_cStat, "nlink", rb_stat_nlink, 0);
2687 rb_define_method(rb_cStat, "uid", rb_stat_uid, 0);
2688 rb_define_method(rb_cStat, "gid", rb_stat_gid, 0);
2689 rb_define_method(rb_cStat, "rdev", rb_stat_rdev, 0);
2690 rb_define_method(rb_cStat, "rdev_major", rb_stat_rdev_major, 0);
2691 rb_define_method(rb_cStat, "rdev_minor", rb_stat_rdev_minor, 0);
2692 rb_define_method(rb_cStat, "size", rb_stat_size, 0);
2693 rb_define_method(rb_cStat, "blksize", rb_stat_blksize, 0);
2694 rb_define_method(rb_cStat, "blocks", rb_stat_blocks, 0);
2695 rb_define_method(rb_cStat, "atime", rb_stat_atime, 0);
2696 rb_define_method(rb_cStat, "mtime", rb_stat_mtime, 0);
2697 rb_define_method(rb_cStat, "ctime", rb_stat_ctime, 0);
2698
2699 rb_define_method(rb_cStat, "inspect", rb_stat_inspect, 0);
2700
2701 rb_define_method(rb_cStat, "ftype", rb_stat_ftype, 0);
2702
2703 rb_define_method(rb_cStat, "directory?", rb_stat_d, 0);
2704 rb_define_method(rb_cStat, "readable?", rb_stat_r, 0);
2705 rb_define_method(rb_cStat, "readable_real?", rb_stat_R, 0);
2706 rb_define_method(rb_cStat, "writable?", rb_stat_w, 0);
2707 rb_define_method(rb_cStat, "writable_real?", rb_stat_W, 0);
2708 rb_define_method(rb_cStat, "executable?", rb_stat_x, 0);
2709 rb_define_method(rb_cStat, "executable_real?", rb_stat_X, 0);
2710 rb_define_method(rb_cStat, "file?", rb_stat_f, 0);
2711 rb_define_method(rb_cStat, "zero?", rb_stat_z, 0);
2712 rb_define_method(rb_cStat, "size?", rb_stat_s, 0);
2713 rb_define_method(rb_cStat, "owned?", rb_stat_owned, 0);
2714 rb_define_method(rb_cStat, "grpowned?", rb_stat_grpowned, 0);
2715
2716 rb_define_method(rb_cStat, "pipe?", rb_stat_p, 0);
2717 rb_define_method(rb_cStat, "symlink?", rb_stat_l, 0);
2718 rb_define_method(rb_cStat, "socket?", rb_stat_S, 0);
2719
2720 rb_define_method(rb_cStat, "blockdev?", rb_stat_b, 0);
2721 rb_define_method(rb_cStat, "chardev?", rb_stat_c, 0);
2722
2723 rb_define_method(rb_cStat, "setuid?", rb_stat_suid, 0);
2724 rb_define_method(rb_cStat, "setgid?", rb_stat_sgid, 0);
2725 rb_define_method(rb_cStat, "sticky?", rb_stat_sticky, 0);
2726 }