1 /**********************************************************************
6 created at: Mon Nov 15 12:24:34 JST 1993
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
12 **********************************************************************/
15 #include "missing/file.h"
19 #include <sys/cygwin.h>
22 #include "ruby/ruby.h"
24 #include "ruby/signal.h"
25 #include "ruby/util.h"
32 #ifdef HAVE_SYS_FILE_H
33 # include <sys/file.h>
38 #ifdef HAVE_SYS_PARAM_H
39 # include <sys/param.h>
42 # define MAXPATHLEN 1024
51 #elif defined HAVE_SYS_UTIME_H
52 #include <sys/utime.h>
59 #include <sys/types.h>
62 #ifdef HAVE_SYS_MKDEV_H
63 #include <sys/mkdev.h>
66 #if !defined HAVE_LSTAT && !defined lstat
70 #ifdef __BEOS__ /* should not change ID if -1 */
72 be_chown(const char *path
, uid_t owner
, gid_t group
)
74 if (owner
== -1 || group
== -1) {
76 if (stat(path
, &st
) < 0) return -1;
77 if (owner
== -1) owner
= st
.st_uid
;
78 if (group
== -1) group
= st
.st_gid
;
80 return chown(path
, owner
, group
);
82 #define chown be_chown
84 be_fchown(int fd
, uid_t owner
, gid_t group
)
86 if (owner
== -1 || group
== -1) {
88 if (fstat(fd
, &st
) < 0) return -1;
89 if (owner
== -1) owner
= st
.st_uid
;
90 if (group
== -1) group
= st
.st_gid
;
92 return fchown(fd
, owner
, group
);
94 #define fchown be_fchown
102 rb_get_path_check(VALUE obj
, int check
)
107 if (check
) rb_check_safe_obj(obj
);
108 tmp
= rb_check_string_type(obj
);
109 if (!NIL_P(tmp
)) goto exit
;
112 CONST_ID(to_path
, "to_path");
113 if (rb_respond_to(obj
, to_path
)) {
114 tmp
= rb_funcall(obj
, to_path
, 0, 0);
120 StringValueCStr(tmp
);
121 if (check
&& obj
!= tmp
) {
122 rb_check_safe_obj(tmp
);
124 return rb_str_new4(tmp
);
128 rb_get_path_no_checksafe(VALUE obj
)
130 return rb_get_path_check(obj
, 0);
134 rb_get_path(VALUE obj
)
136 return rb_get_path_check(obj
, 1);
140 apply2files(void (*func
)(const char *, void *), VALUE vargs
, void *arg
)
146 for (i
=0; i
<RARRAY_LEN(vargs
); i
++) {
147 path
= rb_get_path(RARRAY_PTR(vargs
)[i
]);
148 (*func
)(StringValueCStr(path
), arg
);
151 return RARRAY_LEN(vargs
);
156 * file.path -> filename
158 * Returns the pathname used to create <i>file</i> as a string. Does
159 * not normalize the name.
161 * File.new("testfile").path #=> "testfile"
162 * File.new("/tmp/../tmp/xxx", "w").path #=> "/tmp/../tmp/xxx"
167 rb_file_path(VALUE obj
)
171 fptr
= RFILE(rb_io_taint_check(obj
))->fptr
;
172 rb_io_check_initialized(fptr
);
173 if (!fptr
->path
) return Qnil
;
174 return rb_tainted_str_new2(fptr
->path
);
178 stat_new_0(VALUE klass
, struct stat
*st
)
180 struct stat
*nst
= 0;
183 nst
= ALLOC(struct stat
);
186 return Data_Wrap_Struct(klass
, NULL
, -1, nst
);
190 stat_new(struct stat
*st
)
192 return stat_new_0(rb_cStat
, st
);
199 Data_Get_Struct(self
, struct stat
, st
);
200 if (!st
) rb_raise(rb_eTypeError
, "uninitialized File::Stat");
204 static struct timespec
stat_mtimespec(struct stat
*st
);
208 * stat <=> other_stat => -1, 0, 1
210 * Compares <code>File::Stat</code> objects by comparing their
211 * respective modification times.
213 * f1 = File.new("f1", "w")
215 * f2 = File.new("f2", "w")
216 * f1.stat <=> f2.stat #=> -1
220 rb_stat_cmp(VALUE self
, VALUE other
)
222 if (rb_obj_is_kind_of(other
, rb_obj_class(self
))) {
223 struct timespec ts1
= stat_mtimespec(get_stat(self
));
224 struct timespec ts2
= stat_mtimespec(get_stat(other
));
225 if (ts1
.tv_sec
== ts2
.tv_sec
) {
226 if (ts1
.tv_nsec
== ts2
.tv_nsec
) return INT2FIX(0);
227 if (ts1
.tv_nsec
< ts2
.tv_nsec
) return INT2FIX(-1);
230 if (ts1
.tv_sec
< ts2
.tv_sec
) return INT2FIX(-1);
236 #define ST2UINT(val) ((val) & ~(~1UL << (sizeof(val) * CHAR_BIT - 1)))
242 * Returns an integer representing the device on which <i>stat</i>
245 * File.stat("testfile").dev #=> 774
249 rb_stat_dev(VALUE self
)
251 return INT2NUM(get_stat(self
)->st_dev
);
256 * stat.dev_major => fixnum
258 * Returns the major part of <code>File_Stat#dev</code> or
261 * File.stat("/dev/fd1").dev_major #=> 2
262 * File.stat("/dev/tty").dev_major #=> 5
266 rb_stat_dev_major(VALUE self
)
269 long dev
= get_stat(self
)->st_dev
;
270 return ULONG2NUM(major(dev
));
278 * stat.dev_minor => fixnum
280 * Returns the minor part of <code>File_Stat#dev</code> or
283 * File.stat("/dev/fd1").dev_minor #=> 1
284 * File.stat("/dev/tty").dev_minor #=> 0
288 rb_stat_dev_minor(VALUE self
)
291 long dev
= get_stat(self
)->st_dev
;
292 return ULONG2NUM(minor(dev
));
303 * Returns the inode number for <i>stat</i>.
305 * File.stat("testfile").ino #=> 1083669
310 rb_stat_ino(VALUE self
)
313 return ULL2NUM(get_stat(self
)->st_ino
);
315 return ULONG2NUM(get_stat(self
)->st_ino
);
321 * stat.mode => fixnum
323 * Returns an integer representing the permission bits of
324 * <i>stat</i>. The meaning of the bits is platform dependent; on
325 * Unix systems, see <code>stat(2)</code>.
327 * File.chmod(0644, "testfile") #=> 1
328 * s = File.stat("testfile")
329 * sprintf("%o", s.mode) #=> "100644"
333 rb_stat_mode(VALUE self
)
335 return UINT2NUM(ST2UINT(get_stat(self
)->st_mode
));
340 * stat.nlink => fixnum
342 * Returns the number of hard links to <i>stat</i>.
344 * File.stat("testfile").nlink #=> 1
345 * File.link("testfile", "testfile.bak") #=> 0
346 * File.stat("testfile").nlink #=> 2
351 rb_stat_nlink(VALUE self
)
353 return UINT2NUM(get_stat(self
)->st_nlink
);
361 * Returns the numeric user id of the owner of <i>stat</i>.
363 * File.stat("testfile").uid #=> 501
368 rb_stat_uid(VALUE self
)
370 return UIDT2NUM(get_stat(self
)->st_uid
);
377 * Returns the numeric group id of the owner of <i>stat</i>.
379 * File.stat("testfile").gid #=> 500
384 rb_stat_gid(VALUE self
)
386 return GIDT2NUM(get_stat(self
)->st_gid
);
392 * stat.rdev => fixnum or nil
394 * Returns an integer representing the device type on which
395 * <i>stat</i> resides. Returns <code>nil</code> if the operating
396 * system doesn't support this feature.
398 * File.stat("/dev/fd1").rdev #=> 513
399 * File.stat("/dev/tty").rdev #=> 1280
403 rb_stat_rdev(VALUE self
)
406 return ULONG2NUM(get_stat(self
)->st_rdev
);
414 * stat.rdev_major => fixnum
416 * Returns the major part of <code>File_Stat#rdev</code> or
419 * File.stat("/dev/fd1").rdev_major #=> 2
420 * File.stat("/dev/tty").rdev_major #=> 5
424 rb_stat_rdev_major(VALUE self
)
426 #if defined(HAVE_ST_RDEV) && defined(major)
427 long rdev
= get_stat(self
)->st_rdev
;
428 return ULONG2NUM(major(rdev
));
436 * stat.rdev_minor => fixnum
438 * Returns the minor part of <code>File_Stat#rdev</code> or
441 * File.stat("/dev/fd1").rdev_minor #=> 1
442 * File.stat("/dev/tty").rdev_minor #=> 0
446 rb_stat_rdev_minor(VALUE self
)
448 #if defined(HAVE_ST_RDEV) && defined(minor)
449 long rdev
= get_stat(self
)->st_rdev
;
450 return ULONG2NUM(minor(rdev
));
458 * stat.size => fixnum
460 * Returns the size of <i>stat</i> in bytes.
462 * File.stat("testfile").size #=> 66
466 rb_stat_size(VALUE self
)
468 return OFFT2NUM(get_stat(self
)->st_size
);
473 * stat.blksize => integer or nil
475 * Returns the native file system's block size. Will return <code>nil</code>
476 * on platforms that don't support this information.
478 * File.stat("testfile").blksize #=> 4096
483 rb_stat_blksize(VALUE self
)
485 #ifdef HAVE_ST_BLKSIZE
486 return ULONG2NUM(get_stat(self
)->st_blksize
);
494 * stat.blocks => integer or nil
496 * Returns the number of native file system blocks allocated for this
497 * file, or <code>nil</code> if the operating system doesn't
498 * support this feature.
500 * File.stat("testfile").blocks #=> 2
504 rb_stat_blocks(VALUE self
)
506 #ifdef HAVE_ST_BLOCKS
507 return ULONG2NUM(get_stat(self
)->st_blocks
);
513 static struct timespec
514 stat_atimespec(struct stat
*st
)
517 ts
.tv_sec
= st
->st_atime
;
518 #if defined(HAVE_STRUCT_STAT_ST_ATIM)
519 ts
.tv_nsec
= st
->st_atim
.tv_nsec
;
520 #elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC)
521 ts
.tv_nsec
= st
->st_atimespec
.tv_nsec
;
522 #elif defined(HAVE_STRUCT_STAT_ST_ATIMENSEC)
523 ts
.tv_nsec
= st
->st_atimensec
;
531 stat_atime(struct stat
*st
)
533 struct timespec ts
= stat_atimespec(st
);
534 return rb_time_nano_new(ts
.tv_sec
, ts
.tv_nsec
);
537 static struct timespec
538 stat_mtimespec(struct stat
*st
)
541 ts
.tv_sec
= st
->st_mtime
;
542 #if defined(HAVE_STRUCT_STAT_ST_MTIM)
543 ts
.tv_nsec
= st
->st_mtim
.tv_nsec
;
544 #elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC)
545 ts
.tv_nsec
= st
->st_mtimespec
.tv_nsec
;
546 #elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC)
547 ts
.tv_nsec
= st
->st_mtimensec
;
555 stat_mtime(struct stat
*st
)
557 struct timespec ts
= stat_mtimespec(st
);
558 return rb_time_nano_new(ts
.tv_sec
, ts
.tv_nsec
);
561 static struct timespec
562 stat_ctimespec(struct stat
*st
)
565 ts
.tv_sec
= st
->st_ctime
;
566 #if defined(HAVE_STRUCT_STAT_ST_CTIM)
567 ts
.tv_nsec
= st
->st_ctim
.tv_nsec
;
568 #elif defined(HAVE_STRUCT_STAT_ST_CTIMESPEC)
569 ts
.tv_nsec
= st
->st_ctimespec
.tv_nsec
;
570 #elif defined(HAVE_STRUCT_STAT_ST_CTIMENSEC)
571 ts
.tv_nsec
= st
->st_ctimensec
;
579 stat_ctime(struct stat
*st
)
581 struct timespec ts
= stat_ctimespec(st
);
582 return rb_time_nano_new(ts
.tv_sec
, ts
.tv_nsec
);
589 * Returns the last access time for this file as an object of class
592 * File.stat("testfile").atime #=> Wed Dec 31 18:00:00 CST 1969
597 rb_stat_atime(VALUE self
)
599 return stat_atime(get_stat(self
));
604 * stat.mtime -> aTime
606 * Returns the modification time of <i>stat</i>.
608 * File.stat("testfile").mtime #=> Wed Apr 09 08:53:14 CDT 2003
613 rb_stat_mtime(VALUE self
)
615 return stat_mtime(get_stat(self
));
620 * stat.ctime -> aTime
622 * Returns the change time for <i>stat</i> (that is, the time
623 * directory information about the file was changed, not the file
626 * File.stat("testfile").ctime #=> Wed Apr 09 08:53:14 CDT 2003
631 rb_stat_ctime(VALUE self
)
633 return stat_ctime(get_stat(self
));
638 * stat.inspect => string
640 * Produce a nicely formatted description of <i>stat</i>.
642 * File.stat("/etc/passwd").inspect
643 * #=> "#<File::Stat dev=0xe000005, ino=1078078, mode=0100644,
644 * nlink=1, uid=0, gid=0, rdev=0x0, size=1374, blksize=4096,
645 * blocks=8, atime=Wed Dec 10 10:16:12 CST 2003,
646 * mtime=Fri Sep 12 15:41:41 CDT 2003,
647 * ctime=Mon Oct 27 11:20:27 CST 2003>"
651 rb_stat_inspect(VALUE self
)
655 static const struct {
657 VALUE (*func
)(VALUE
);
659 {"dev", rb_stat_dev
},
660 {"ino", rb_stat_ino
},
661 {"mode", rb_stat_mode
},
662 {"nlink", rb_stat_nlink
},
663 {"uid", rb_stat_uid
},
664 {"gid", rb_stat_gid
},
665 {"rdev", rb_stat_rdev
},
666 {"size", rb_stat_size
},
667 {"blksize", rb_stat_blksize
},
668 {"blocks", rb_stat_blocks
},
669 {"atime", rb_stat_atime
},
670 {"mtime", rb_stat_mtime
},
671 {"ctime", rb_stat_ctime
},
674 str
= rb_str_buf_new2("#<");
675 rb_str_buf_cat2(str
, rb_obj_classname(self
));
676 rb_str_buf_cat2(str
, " ");
678 for (i
= 0; i
< sizeof(member
)/sizeof(member
[0]); i
++) {
682 rb_str_buf_cat2(str
, ", ");
684 rb_str_buf_cat2(str
, member
[i
].name
);
685 rb_str_buf_cat2(str
, "=");
686 v
= (*member
[i
].func
)(self
);
687 if (i
== 2) { /* mode */
688 rb_str_catf(str
, "0%lo", NUM2ULONG(v
));
690 else if (i
== 0 || i
== 6) { /* dev/rdev */
691 rb_str_catf(str
, "0x%lx", NUM2ULONG(v
));
694 rb_str_append(str
, rb_inspect(v
));
697 rb_str_buf_cat2(str
, ">");
698 OBJ_INFECT(str
, self
);
704 rb_stat(VALUE file
, struct stat
*st
)
709 tmp
= rb_check_convert_type(file
, T_FILE
, "IO", "to_io");
713 GetOpenFile(tmp
, fptr
);
714 return fstat(fptr
->fd
, st
);
717 return stat(StringValueCStr(file
), st
);
722 w32_io_info(VALUE
*file
, BY_HANDLE_FILE_INFORMATION
*st
)
727 tmp
= rb_check_convert_type(*file
, T_FILE
, "IO", "to_io");
731 GetOpenFile(tmp
, fptr
);
732 f
= (HANDLE
)rb_w32_get_osfhandle(fptr
->fd
);
733 if (f
== (HANDLE
)-1) return INVALID_HANDLE_VALUE
;
736 FilePathValue(*file
);
737 f
= CreateFile(StringValueCStr(*file
), 0,
738 FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
,
739 rb_w32_iswin95() ? 0 : FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
740 if (f
== INVALID_HANDLE_VALUE
) return f
;
743 if (GetFileType(f
) == FILE_TYPE_DISK
) {
744 ZeroMemory(st
, sizeof(*st
));
745 if (GetFileInformationByHandle(f
, st
)) return ret
;
747 if (ret
) CloseHandle(ret
);
748 return INVALID_HANDLE_VALUE
;
754 * File.stat(file_name) => stat
756 * Returns a <code>File::Stat</code> object for the named file (see
757 * <code>File::Stat</code>).
759 * File.stat("testfile").mtime #=> Tue Apr 08 12:58:04 CDT 2003
764 rb_file_s_stat(VALUE klass
, VALUE fname
)
769 FilePathValue(fname
);
770 if (rb_stat(fname
, &st
) < 0) {
771 rb_sys_fail(StringValueCStr(fname
));
773 return stat_new(&st
);
780 * Returns status information for <em>ios</em> as an object of type
781 * <code>File::Stat</code>.
783 * f = File.new("testfile")
785 * "%o" % s.mode #=> "100644"
787 * s.atime #=> Wed Apr 09 08:53:54 CDT 2003
792 rb_io_stat(VALUE obj
)
797 GetOpenFile(obj
, fptr
);
798 if (fstat(fptr
->fd
, &st
) == -1) {
799 rb_sys_fail(fptr
->path
);
801 return stat_new(&st
);
806 * File.lstat(file_name) => stat
808 * Same as <code>File::stat</code>, but does not follow the last symbolic
809 * link. Instead, reports on the link itself.
811 * File.symlink("testfile", "link2test") #=> 0
812 * File.stat("testfile").size #=> 66
813 * File.lstat("link2test").size #=> 8
814 * File.stat("link2test").size #=> 66
819 rb_file_s_lstat(VALUE klass
, VALUE fname
)
825 FilePathValue(fname
);
826 if (lstat(StringValueCStr(fname
), &st
) == -1) {
827 rb_sys_fail(RSTRING_PTR(fname
));
829 return stat_new(&st
);
831 return rb_file_s_stat(klass
, fname
);
840 * Same as <code>IO#stat</code>, but does not follow the last symbolic
841 * link. Instead, reports on the link itself.
843 * File.symlink("testfile", "link2test") #=> 0
844 * File.stat("testfile").size #=> 66
845 * f = File.new("link2test")
851 rb_file_lstat(VALUE obj
)
858 GetOpenFile(obj
, fptr
);
859 if (!fptr
->path
) return Qnil
;
860 if (lstat(fptr
->path
, &st
) == -1) {
861 rb_sys_fail(fptr
->path
);
863 return stat_new(&st
);
865 return rb_io_stat(obj
);
869 #ifndef HAVE_GROUP_MEMBER
871 group_member(GETGROUPS_T gid
)
874 if (getgid() == gid
|| getegid() == gid
)
877 # ifdef HAVE_GETGROUPS
880 # define NGROUPS NGROUPS_MAX
886 GETGROUPS_T gary
[NGROUPS
];
889 anum
= getgroups(NGROUPS
, gary
);
891 if (gary
[anum
] == gid
)
901 # define S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH)
904 #if defined(S_IXGRP) && !defined(_WIN32) && !defined(__CYGWIN__)
905 #define USE_GETEUID 1
910 eaccess(const char *path
, int mode
)
916 if (stat(path
, &st
) < 0) return -1;
921 /* Root can read or write any file. */
925 /* Root can execute any file that has any one of the execute
927 if (st
.st_mode
& S_IXUGO
)
933 if (st
.st_uid
== euid
) /* owner */
935 else if (group_member(st
.st_gid
))
938 if ((st
.st_mode
& mode
) == mode
) return 0;
942 # if defined(_MSC_VER) || defined(__MINGW32__)
945 return access(path
, mode
);
952 * Document-class: FileTest
954 * <code>FileTest</code> implements file test operations similar to
955 * those used in <code>File::Stat</code>. It exists as a standalone
956 * module, and its methods are also insinuated into the <code>File</code>
957 * class. (Note that this is not done by inclusion: the interpreter cheats).
963 * File.directory?(file_name) => true or false
964 * File.directory?(file_name) => true or false
966 * Returns <code>true</code> if the named file is a directory,
967 * <code>false</code> otherwise.
969 * File.directory?(".")
973 * Document-method: exist?
976 * Dir.exist?(file_name) => true or false
977 * Dir.exists?(file_name) => true or false
979 * Returns <code>true</code> if the named file is a directory,
980 * <code>false</code> otherwise.
985 * Document-method: directory?
988 * File.directory?(file_name) => true or false
990 * Returns <code>true</code> if the named file is a directory,
991 * <code>false</code> otherwise.
993 * File.directory?(".")
997 rb_file_directory_p(VALUE obj
, VALUE fname
)
1000 # define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR)
1005 if (rb_stat(fname
, &st
) < 0) return Qfalse
;
1006 if (S_ISDIR(st
.st_mode
)) return Qtrue
;
1013 * File.pipe?(file_name) => true or false
1015 * Returns <code>true</code> if the named file is a pipe.
1019 rb_file_pipe_p(VALUE obj
, VALUE fname
)
1023 # define S_ISFIFO(m) ((m & S_IFMT) == S_IFIFO)
1028 if (rb_stat(fname
, &st
) < 0) return Qfalse
;
1029 if (S_ISFIFO(st
.st_mode
)) return Qtrue
;
1037 * File.symlink?(file_name) => true or false
1039 * Returns <code>true</code> if the named file is a symbolic link.
1043 rb_file_symlink_p(VALUE obj
, VALUE fname
)
1047 # define S_ISLNK(m) _S_ISLNK(m)
1050 # define S_ISLNK(m) ((m & S_IFMT) == _S_IFLNK)
1053 # define S_ISLNK(m) ((m & S_IFMT) == S_IFLNK)
1063 FilePathValue(fname
);
1064 if (lstat(StringValueCStr(fname
), &st
) < 0) return Qfalse
;
1065 if (S_ISLNK(st
.st_mode
)) return Qtrue
;
1073 * File.socket?(file_name) => true or false
1075 * Returns <code>true</code> if the named file is a socket.
1079 rb_file_socket_p(VALUE obj
, VALUE fname
)
1083 # define S_ISSOCK(m) _S_ISSOCK(m)
1086 # define S_ISSOCK(m) ((m & S_IFMT) == _S_IFSOCK)
1089 # define S_ISSOCK(m) ((m & S_IFMT) == S_IFSOCK)
1098 if (rb_stat(fname
, &st
) < 0) return Qfalse
;
1099 if (S_ISSOCK(st
.st_mode
)) return Qtrue
;
1107 * File.blockdev?(file_name) => true or false
1109 * Returns <code>true</code> if the named file is a block device.
1113 rb_file_blockdev_p(VALUE obj
, VALUE fname
)
1117 # define S_ISBLK(m) ((m & S_IFMT) == S_IFBLK)
1119 # define S_ISBLK(m) (0) /* anytime false */
1126 if (rb_stat(fname
, &st
) < 0) return Qfalse
;
1127 if (S_ISBLK(st
.st_mode
)) return Qtrue
;
1135 * File.chardev?(file_name) => true or false
1137 * Returns <code>true</code> if the named file is a character device.
1140 rb_file_chardev_p(VALUE obj
, VALUE fname
)
1143 # define S_ISCHR(m) ((m & S_IFMT) == S_IFCHR)
1148 if (rb_stat(fname
, &st
) < 0) return Qfalse
;
1149 if (S_ISCHR(st
.st_mode
)) return Qtrue
;
1157 * File.exist?(file_name) => true or false
1158 * File.exists?(file_name) => true or false
1160 * Return <code>true</code> if the named file exists.
1164 rb_file_exist_p(VALUE obj
, VALUE fname
)
1168 if (rb_stat(fname
, &st
) < 0) return Qfalse
;
1174 * File.readable?(file_name) => true or false
1176 * Returns <code>true</code> if the named file is readable by the effective
1177 * user id of this process.
1181 rb_file_readable_p(VALUE obj
, VALUE fname
)
1184 FilePathValue(fname
);
1185 if (eaccess(StringValueCStr(fname
), R_OK
) < 0) return Qfalse
;
1191 * File.readable_real?(file_name) => true or false
1193 * Returns <code>true</code> if the named file is readable by the real
1194 * user id of this process.
1198 rb_file_readable_real_p(VALUE obj
, VALUE fname
)
1201 FilePathValue(fname
);
1202 if (access(StringValueCStr(fname
), R_OK
) < 0) return Qfalse
;
1207 # define S_IRUGO (S_IRUSR | S_IRGRP | S_IROTH)
1211 # define S_IWUGO (S_IWUSR | S_IWGRP | S_IWOTH)
1216 * File.world_readable?(file_name) => fixnum or nil
1218 * If <i>file_name</i> is readable by others, returns an integer
1219 * representing the file permission bits of <i>file_name</i>. Returns
1220 * <code>nil</code> otherwise. The meaning of the bits is platform
1221 * dependent; on Unix systems, see <code>stat(2)</code>.
1223 * File.world_readable?("/etc/passwd") # => 420
1224 * m = File.world_readable?("/etc/passwd")
1225 * sprintf("%o", m) # => "644"
1229 rb_file_world_readable_p(VALUE obj
, VALUE fname
)
1234 if (rb_stat(fname
, &st
) < 0) return Qnil
;
1235 if ((st
.st_mode
& (S_IROTH
)) == S_IROTH
) {
1236 return UINT2NUM(st
.st_mode
& (S_IRUGO
|S_IWUGO
|S_IXUGO
));
1244 * File.writable?(file_name) => true or false
1246 * Returns <code>true</code> if the named file is writable by the effective
1247 * user id of this process.
1251 rb_file_writable_p(VALUE obj
, VALUE fname
)
1254 FilePathValue(fname
);
1255 if (eaccess(StringValueCStr(fname
), W_OK
) < 0) return Qfalse
;
1261 * File.writable_real?(file_name) => true or false
1263 * Returns <code>true</code> if the named file is writable by the real
1264 * user id of this process.
1268 rb_file_writable_real_p(VALUE obj
, VALUE fname
)
1271 FilePathValue(fname
);
1272 if (access(StringValueCStr(fname
), W_OK
) < 0) return Qfalse
;
1278 * File.world_writable?(file_name) => fixnum or nil
1280 * If <i>file_name</i> is writable by others, returns an integer
1281 * representing the file permission bits of <i>file_name</i>. Returns
1282 * <code>nil</code> otherwise. The meaning of the bits is platform
1283 * dependent; on Unix systems, see <code>stat(2)</code>.
1285 * File.world_writable?("/tmp") #=> 511
1286 * m = File.world_writable?("/tmp")
1287 * sprintf("%o", m) #=> "777"
1291 rb_file_world_writable_p(VALUE obj
, VALUE fname
)
1296 if (rb_stat(fname
, &st
) < 0) return Qfalse
;
1297 if ((st
.st_mode
& (S_IWOTH
)) == S_IWOTH
) {
1298 return UINT2NUM(st
.st_mode
& (S_IRUGO
|S_IWUGO
|S_IXUGO
));
1306 * File.executable?(file_name) => true or false
1308 * Returns <code>true</code> if the named file is executable by the effective
1309 * user id of this process.
1313 rb_file_executable_p(VALUE obj
, VALUE fname
)
1316 FilePathValue(fname
);
1317 if (eaccess(StringValueCStr(fname
), X_OK
) < 0) return Qfalse
;
1323 * File.executable_real?(file_name) => true or false
1325 * Returns <code>true</code> if the named file is executable by the real
1326 * user id of this process.
1330 rb_file_executable_real_p(VALUE obj
, VALUE fname
)
1333 FilePathValue(fname
);
1334 if (access(StringValueCStr(fname
), X_OK
) < 0) return Qfalse
;
1339 # define S_ISREG(m) ((m & S_IFMT) == S_IFREG)
1344 * File.file?(file_name) => true or false
1346 * Returns <code>true</code> if the named file exists and is a
1351 rb_file_file_p(VALUE obj
, VALUE fname
)
1355 if (rb_stat(fname
, &st
) < 0) return Qfalse
;
1356 if (S_ISREG(st
.st_mode
)) return Qtrue
;
1362 * File.zero?(file_name) => true or false
1364 * Returns <code>true</code> if the named file exists and has
1369 rb_file_zero_p(VALUE obj
, VALUE fname
)
1373 if (rb_stat(fname
, &st
) < 0) return Qfalse
;
1374 if (st
.st_size
== 0) return Qtrue
;
1380 * File.size?(file_name) => Integer or nil
1382 * Returns +nil+ if +file_name+ doesn't exist or has zero size, the size of the
1387 rb_file_size_p(VALUE obj
, VALUE fname
)
1391 if (rb_stat(fname
, &st
) < 0) return Qnil
;
1392 if (st
.st_size
== 0) return Qnil
;
1393 return OFFT2NUM(st
.st_size
);
1398 * File.owned?(file_name) => true or false
1400 * Returns <code>true</code> if the named file exists and the
1401 * effective used id of the calling process is the owner of
1406 rb_file_owned_p(VALUE obj
, VALUE fname
)
1410 if (rb_stat(fname
, &st
) < 0) return Qfalse
;
1411 if (st
.st_uid
== geteuid()) return Qtrue
;
1416 rb_file_rowned_p(VALUE obj
, VALUE fname
)
1420 if (rb_stat(fname
, &st
) < 0) return Qfalse
;
1421 if (st
.st_uid
== getuid()) return Qtrue
;
1427 * File.grpowned?(file_name) => true or false
1429 * Returns <code>true</code> if the named file exists and the
1430 * effective group id of the calling process is the owner of
1431 * the file. Returns <code>false</code> on Windows.
1435 rb_file_grpowned_p(VALUE obj
, VALUE fname
)
1440 if (rb_stat(fname
, &st
) < 0) return Qfalse
;
1441 if (group_member(st
.st_gid
)) return Qtrue
;
1446 #if defined(S_ISUID) || defined(S_ISGID) || defined(S_ISVTX)
1448 check3rdbyte(VALUE fname
, int mode
)
1453 FilePathValue(fname
);
1454 if (stat(StringValueCStr(fname
), &st
) < 0) return Qfalse
;
1455 if (st
.st_mode
& mode
) return Qtrue
;
1462 * File.setuid?(file_name) => true or false
1464 * Returns <code>true</code> if the named file has the setuid bit set.
1468 rb_file_suid_p(VALUE obj
, VALUE fname
)
1471 return check3rdbyte(fname
, S_ISUID
);
1479 * File.setgid?(file_name) => true or false
1481 * Returns <code>true</code> if the named file has the setgid bit set.
1485 rb_file_sgid_p(VALUE obj
, VALUE fname
)
1488 return check3rdbyte(fname
, S_ISGID
);
1496 * File.sticky?(file_name) => true or false
1498 * Returns <code>true</code> if the named file has the sticky bit set.
1502 rb_file_sticky_p(VALUE obj
, VALUE fname
)
1505 return check3rdbyte(fname
, S_ISVTX
);
1513 * File.identical?(file_1, file_2) => true or false
1515 * Returns <code>true</code> if the named files are identical.
1518 * p File.identical?("a", "a") #=> true
1519 * p File.identical?("a", "./a") #=> true
1520 * File.link("a", "b")
1521 * p File.identical?("a", "b") #=> true
1522 * File.symlink("a", "c")
1523 * p File.identical?("a", "c") #=> true
1525 * p File.identical?("a", "d") #=> false
1529 rb_file_identical_p(VALUE obj
, VALUE fname1
, VALUE fname2
)
1532 struct stat st1
, st2
;
1534 if (rb_stat(fname1
, &st1
) < 0) return Qfalse
;
1535 if (rb_stat(fname2
, &st2
) < 0) return Qfalse
;
1536 if (st1
.st_dev
!= st2
.st_dev
) return Qfalse
;
1537 if (st1
.st_ino
!= st2
.st_ino
) return Qfalse
;
1540 BY_HANDLE_FILE_INFORMATION st1
, st2
;
1541 HANDLE f1
= 0, f2
= 0;
1546 f1
= w32_io_info(&fname1
, &st1
);
1547 if (f1
== INVALID_HANDLE_VALUE
) return Qfalse
;
1548 f2
= w32_io_info(&fname2
, &st2
);
1549 if (f1
) CloseHandle(f1
);
1550 if (f2
== INVALID_HANDLE_VALUE
) return Qfalse
;
1551 if (f2
) CloseHandle(f2
);
1553 if (st1
.dwVolumeSerialNumber
== st2
.dwVolumeSerialNumber
&&
1554 st1
.nFileIndexHigh
== st2
.nFileIndexHigh
&&
1555 st1
.nFileIndexLow
== st2
.nFileIndexLow
)
1557 if (!f1
|| !f2
) return Qfalse
;
1558 if (rb_w32_iswin95()) return Qfalse
;
1560 FilePathValue(fname1
);
1561 fname1
= rb_str_new4(fname1
);
1562 FilePathValue(fname2
);
1563 if (access(RSTRING_PTR(fname1
), 0)) return Qfalse
;
1564 if (access(RSTRING_PTR(fname2
), 0)) return Qfalse
;
1566 fname1
= rb_file_expand_path(fname1
, Qnil
);
1567 fname2
= rb_file_expand_path(fname2
, Qnil
);
1568 if (RSTRING_LEN(fname1
) != RSTRING_LEN(fname2
)) return Qfalse
;
1569 if (rb_memcicmp(RSTRING_PTR(fname1
), RSTRING_PTR(fname2
), RSTRING_LEN(fname1
)))
1577 * File.size(file_name) => integer
1579 * Returns the size of <code>file_name</code>.
1583 rb_file_s_size(VALUE klass
, VALUE fname
)
1587 if (rb_stat(fname
, &st
) < 0)
1588 rb_sys_fail(StringValueCStr(fname
));
1589 return OFFT2NUM(st
.st_size
);
1593 rb_file_ftype(const struct stat
*st
)
1597 if (S_ISREG(st
->st_mode
)) {
1600 else if (S_ISDIR(st
->st_mode
)) {
1603 else if (S_ISCHR(st
->st_mode
)) {
1604 t
= "characterSpecial";
1607 else if (S_ISBLK(st
->st_mode
)) {
1612 else if (S_ISFIFO(st
->st_mode
)) {
1617 else if (S_ISLNK(st
->st_mode
)) {
1622 else if (S_ISSOCK(st
->st_mode
)) {
1630 return rb_usascii_str_new2(t
);
1635 * File.ftype(file_name) => string
1637 * Identifies the type of the named file; the return string is one of
1638 * ``<code>file</code>'', ``<code>directory</code>'',
1639 * ``<code>characterSpecial</code>'', ``<code>blockSpecial</code>'',
1640 * ``<code>fifo</code>'', ``<code>link</code>'',
1641 * ``<code>socket</code>'', or ``<code>unknown</code>''.
1643 * File.ftype("testfile") #=> "file"
1644 * File.ftype("/dev/tty") #=> "characterSpecial"
1645 * File.ftype("/tmp/.X11-unix/X0") #=> "socket"
1649 rb_file_s_ftype(VALUE klass
, VALUE fname
)
1654 FilePathValue(fname
);
1655 if (lstat(StringValueCStr(fname
), &st
) == -1) {
1656 rb_sys_fail(RSTRING_PTR(fname
));
1659 return rb_file_ftype(&st
);
1664 * File.atime(file_name) => time
1666 * Returns the last access time for the named file as a Time object).
1668 * File.atime("testfile") #=> Wed Apr 09 08:51:48 CDT 2003
1673 rb_file_s_atime(VALUE klass
, VALUE fname
)
1677 if (rb_stat(fname
, &st
) < 0)
1678 rb_sys_fail(StringValueCStr(fname
));
1679 return stat_atime(&st
);
1684 * file.atime => time
1686 * Returns the last access time (a <code>Time</code> object)
1687 * for <i>file</i>, or epoch if <i>file</i> has not been accessed.
1689 * File.new("testfile").atime #=> Wed Dec 31 18:00:00 CST 1969
1694 rb_file_atime(VALUE obj
)
1699 GetOpenFile(obj
, fptr
);
1700 if (fstat(fptr
->fd
, &st
) == -1) {
1701 rb_sys_fail(fptr
->path
);
1703 return stat_atime(&st
);
1708 * File.mtime(file_name) => time
1710 * Returns the modification time for the named file as a Time object.
1712 * File.mtime("testfile") #=> Tue Apr 08 12:58:04 CDT 2003
1717 rb_file_s_mtime(VALUE klass
, VALUE fname
)
1721 if (rb_stat(fname
, &st
) < 0)
1722 rb_sys_fail(RSTRING_PTR(fname
));
1723 return stat_mtime(&st
);
1728 * file.mtime -> time
1730 * Returns the modification time for <i>file</i>.
1732 * File.new("testfile").mtime #=> Wed Apr 09 08:53:14 CDT 2003
1737 rb_file_mtime(VALUE obj
)
1742 GetOpenFile(obj
, fptr
);
1743 if (fstat(fptr
->fd
, &st
) == -1) {
1744 rb_sys_fail(fptr
->path
);
1746 return stat_mtime(&st
);
1751 * File.ctime(file_name) => time
1753 * Returns the change time for the named file (the time at which
1754 * directory information about the file was changed, not the file
1757 * File.ctime("testfile") #=> Wed Apr 09 08:53:13 CDT 2003
1762 rb_file_s_ctime(VALUE klass
, VALUE fname
)
1766 if (rb_stat(fname
, &st
) < 0)
1767 rb_sys_fail(RSTRING_PTR(fname
));
1768 return stat_ctime(&st
);
1773 * file.ctime -> time
1775 * Returns the change time for <i>file</i> (that is, the time directory
1776 * information about the file was changed, not the file itself).
1778 * File.new("testfile").ctime #=> Wed Apr 09 08:53:14 CDT 2003
1783 rb_file_ctime(VALUE obj
)
1788 GetOpenFile(obj
, fptr
);
1789 if (fstat(fptr
->fd
, &st
) == -1) {
1790 rb_sys_fail(fptr
->path
);
1792 return stat_ctime(&st
);
1796 chmod_internal(const char *path
, void *mode
)
1798 if (chmod(path
, *(int *)mode
) < 0)
1804 * File.chmod(mode_int, file_name, ... ) -> integer
1806 * Changes permission bits on the named file(s) to the bit pattern
1807 * represented by <i>mode_int</i>. Actual effects are operating system
1808 * dependent (see the beginning of this section). On Unix systems, see
1809 * <code>chmod(2)</code> for details. Returns the number of files
1812 * File.chmod(0644, "testfile", "out") #=> 2
1816 rb_file_s_chmod(int argc
, VALUE
*argv
)
1824 rb_scan_args(argc
, argv
, "1*", &vmode
, &rest
);
1825 mode
= NUM2INT(vmode
);
1827 n
= apply2files(chmod_internal
, rest
, &mode
);
1833 * file.chmod(mode_int) => 0
1835 * Changes permission bits on <i>file</i> to the bit pattern
1836 * represented by <i>mode_int</i>. Actual effects are platform
1837 * dependent; on Unix systems, see <code>chmod(2)</code> for details.
1838 * Follows symbolic links. Also see <code>File#lchmod</code>.
1840 * f = File.new("out", "w");
1841 * f.chmod(0644) #=> 0
1845 rb_file_chmod(VALUE obj
, VALUE vmode
)
1851 mode
= NUM2INT(vmode
);
1853 GetOpenFile(obj
, fptr
);
1855 if (fchmod(fptr
->fd
, mode
) == -1)
1856 rb_sys_fail(fptr
->path
);
1858 if (!fptr
->path
) return Qnil
;
1859 if (chmod(fptr
->path
, mode
) == -1)
1860 rb_sys_fail(fptr
->path
);
1866 #if defined(HAVE_LCHMOD)
1868 lchmod_internal(const char *path
, void *mode
)
1870 if (lchmod(path
, (int)(VALUE
)mode
) < 0)
1876 * File.lchmod(mode_int, file_name, ...) => integer
1878 * Equivalent to <code>File::chmod</code>, but does not follow symbolic
1879 * links (so it will change the permissions associated with the link,
1880 * not the file referenced by the link). Often not available.
1885 rb_file_s_lchmod(int argc
, VALUE
*argv
)
1892 rb_scan_args(argc
, argv
, "1*", &vmode
, &rest
);
1893 mode
= NUM2INT(vmode
);
1895 n
= apply2files(lchmod_internal
, rest
, (void *)(long)mode
);
1900 rb_file_s_lchmod(int argc
, VALUE
*argv
)
1903 return Qnil
; /* not reached */
1913 chown_internal(const char *path
, void *arg
)
1915 struct chown_args
*args
= arg
;
1916 if (chown(path
, args
->owner
, args
->group
) < 0)
1922 * File.chown(owner_int, group_int, file_name,... ) -> integer
1924 * Changes the owner and group of the named file(s) to the given
1925 * numeric owner and group id's. Only a process with superuser
1926 * privileges may change the owner of a file. The current owner of a
1927 * file may change the file's group to any group to which the owner
1928 * belongs. A <code>nil</code> or -1 owner or group id is ignored.
1929 * Returns the number of files processed.
1931 * File.chown(nil, 100, "testfile")
1936 rb_file_s_chown(int argc
, VALUE
*argv
)
1939 struct chown_args arg
;
1943 rb_scan_args(argc
, argv
, "2*", &o
, &g
, &rest
);
1948 arg
.owner
= NUM2UIDT(o
);
1954 arg
.group
= NUM2GIDT(g
);
1957 n
= apply2files(chown_internal
, rest
, &arg
);
1963 * file.chown(owner_int, group_int ) => 0
1965 * Changes the owner and group of <i>file</i> to the given numeric
1966 * owner and group id's. Only a process with superuser privileges may
1967 * change the owner of a file. The current owner of a file may change
1968 * the file's group to any group to which the owner belongs. A
1969 * <code>nil</code> or -1 owner or group id is ignored. Follows
1970 * symbolic links. See also <code>File#lchown</code>.
1972 * File.new("testfile").chown(502, 1000)
1977 rb_file_chown(VALUE obj
, VALUE owner
, VALUE group
)
1983 o
= NIL_P(owner
) ? -1 : NUM2INT(owner
);
1984 g
= NIL_P(group
) ? -1 : NUM2INT(group
);
1985 GetOpenFile(obj
, fptr
);
1986 #if defined(DJGPP) || defined(__CYGWIN32__) || defined(_WIN32) || defined(__EMX__)
1987 if (!fptr
->path
) return Qnil
;
1988 if (chown(fptr
->path
, o
, g
) == -1)
1989 rb_sys_fail(fptr
->path
);
1991 if (fchown(fptr
->fd
, o
, g
) == -1)
1992 rb_sys_fail(fptr
->path
);
1998 #if defined(HAVE_LCHOWN) && !defined(__CHECKER__)
2000 lchown_internal(const char *path
, void *arg
)
2002 struct chown_args
*args
= arg
;
2003 if (lchown(path
, args
->owner
, args
->group
) < 0)
2010 * file.lchown(owner_int, group_int, file_name,..) => integer
2012 * Equivalent to <code>File::chown</code>, but does not follow symbolic
2013 * links (so it will change the owner associated with the link, not the
2014 * file referenced by the link). Often not available. Returns number
2015 * of files in the argument list.
2020 rb_file_s_lchown(int argc
, VALUE
*argv
)
2023 struct chown_args arg
;
2027 rb_scan_args(argc
, argv
, "2*", &o
, &g
, &rest
);
2032 arg
.owner
= NUM2UIDT(o
);
2038 arg
.group
= NUM2GIDT(g
);
2041 n
= apply2files(lchown_internal
, rest
, &arg
);
2046 rb_file_s_lchown(int argc
, VALUE
*argv
)
2052 struct timespec
rb_time_timespec(VALUE time
);
2054 #if defined(HAVE_UTIMES)
2057 utime_internal(const char *path
, void *arg
)
2059 struct timespec
*tsp
= arg
;
2060 struct timeval tvbuf
[2], *tvp
= arg
;
2062 #ifdef HAVE_UTIMENSAT
2063 static int try_utimensat
= 1;
2065 if (try_utimensat
) {
2066 struct timespec
*tsp
= arg
;
2067 if (utimensat(AT_FDCWD
, path
, tsp
, 0) < 0) {
2068 if (errno
== ENOSYS
) {
2080 tvbuf
[0].tv_sec
= tsp
[0].tv_sec
;
2081 tvbuf
[0].tv_usec
= tsp
[0].tv_nsec
/ 1000;
2082 tvbuf
[1].tv_sec
= tsp
[1].tv_sec
;
2083 tvbuf
[1].tv_usec
= tsp
[1].tv_nsec
/ 1000;
2086 if (utimes(path
, tvp
) < 0)
2092 #if !defined HAVE_UTIME_H && !defined HAVE_SYS_UTIME_H
2100 utime_internal(const char *path
, void *arg
)
2102 struct timespec
*tsp
= arg
;
2103 struct utimbuf utbuf
, *utp
= NULL
;
2105 utbuf
.actime
= tsp
[0].tv_sec
;
2106 utbuf
.modtime
= tsp
[1].tv_sec
;
2109 if (utime(path
, utp
) < 0)
2117 * File.utime(atime, mtime, file_name,...) => integer
2119 * Sets the access and modification times of each
2120 * named file to the first two arguments. Returns
2121 * the number of file names in the argument list.
2125 rb_file_s_utime(int argc
, VALUE
*argv
)
2127 VALUE atime
, mtime
, rest
;
2128 struct timespec tss
[2], *tsp
= NULL
;
2132 rb_scan_args(argc
, argv
, "2*", &atime
, &mtime
, &rest
);
2134 if (!NIL_P(atime
) || !NIL_P(mtime
)) {
2136 tsp
[0] = rb_time_timespec(atime
);
2137 tsp
[1] = rb_time_timespec(mtime
);
2140 n
= apply2files(utime_internal
, rest
, tsp
);
2145 NORETURN(static void sys_fail2(VALUE
,VALUE
));
2147 sys_fail2(VALUE s1
, VALUE s2
)
2151 const int max_pathlen
= MAX_PATH
;
2153 const int max_pathlen
= MAXPATHLEN
;
2155 const char *e1
, *e2
;
2157 int l1
= RSTRING_LEN(s1
), l2
= RSTRING_LEN(s2
);
2160 if (l1
> max_pathlen
) {
2161 l1
= max_pathlen
- 3;
2165 if (l2
> max_pathlen
) {
2166 l2
= max_pathlen
- 3;
2171 buf
= ALLOCA_N(char, len
);
2172 snprintf(buf
, len
, "(%.*s%s, %.*s%s)",
2173 l1
, RSTRING_PTR(s1
), e1
,
2174 l2
, RSTRING_PTR(s2
), e2
);
2180 * File.link(old_name, new_name) => 0
2182 * Creates a new name for an existing file using a hard link. Will not
2183 * overwrite <i>new_name</i> if it already exists (raising a subclass
2184 * of <code>SystemCallError</code>). Not available on all platforms.
2186 * File.link("testfile", ".testfile") #=> 0
2187 * IO.readlines(".testfile")[0] #=> "This is line one\n"
2191 rb_file_s_link(VALUE klass
, VALUE from
, VALUE to
)
2195 FilePathValue(from
);
2198 if (link(StringValueCStr(from
), StringValueCStr(to
)) < 0) {
2199 sys_fail2(from
, to
);
2204 return Qnil
; /* not reached */
2210 * File.symlink(old_name, new_name) => 0
2212 * Creates a symbolic link called <i>new_name</i> for the existing file
2213 * <i>old_name</i>. Raises a <code>NotImplemented</code> exception on
2214 * platforms that do not support symbolic links.
2216 * File.symlink("testfile", "link2test") #=> 0
2221 rb_file_s_symlink(VALUE klass
, VALUE from
, VALUE to
)
2225 FilePathValue(from
);
2228 if (symlink(StringValueCStr(from
), StringValueCStr(to
)) < 0) {
2229 sys_fail2(from
, to
);
2234 return Qnil
; /* not reached */
2240 * File.readlink(link_name) -> file_name
2242 * Returns the name of the file referenced by the given link.
2243 * Not available on all platforms.
2245 * File.symlink("testfile", "link2test") #=> 0
2246 * File.readlink("link2test") #=> "testfile"
2250 rb_file_s_readlink(VALUE klass
, VALUE path
)
2252 #ifdef HAVE_READLINK
2259 FilePathValue(path
);
2260 buf
= xmalloc(size
);
2261 while ((rv
= readlink(RSTRING_PTR(path
), buf
, size
)) == size
2263 || (rv
< 0 && errno
== ERANGE
) /* quirky behavior of GPFS */
2267 buf
= xrealloc(buf
, size
);
2271 rb_sys_fail(RSTRING_PTR(path
));
2273 v
= rb_tainted_str_new(buf
, rv
);
2279 return Qnil
; /* not reached */
2284 unlink_internal(const char *path
, void *arg
)
2286 if (unlink(path
) < 0)
2292 * File.delete(file_name, ...) => integer
2293 * File.unlink(file_name, ...) => integer
2295 * Deletes the named files, returning the number of names
2296 * passed as arguments. Raises an exception on any error.
2297 * See also <code>Dir::rmdir</code>.
2301 rb_file_s_unlink(VALUE klass
, VALUE args
)
2306 n
= apply2files(unlink_internal
, args
, 0);
2312 * File.rename(old_name, new_name) => 0
2314 * Renames the given file to the new name. Raises a
2315 * <code>SystemCallError</code> if the file cannot be renamed.
2317 * File.rename("afile", "afile.bak") #=> 0
2321 rb_file_s_rename(VALUE klass
, VALUE from
, VALUE to
)
2323 const char *src
, *dst
;
2326 FilePathValue(from
);
2328 src
= StringValueCStr(from
);
2329 dst
= StringValueCStr(to
);
2330 #if defined __CYGWIN__
2333 if (rename(src
, dst
) < 0) {
2334 #if defined DOSISH && !defined _WIN32
2337 #if defined (__EMX__)
2340 if (chmod(dst
, 0666) == 0 &&
2342 rename(src
, dst
) == 0)
2346 sys_fail2(from
, to
);
2354 * File.umask() => integer
2355 * File.umask(integer) => integer
2357 * Returns the current umask value for this process. If the optional
2358 * argument is given, set the umask to that value and return the
2359 * previous value. Umask values are <em>subtracted</em> from the
2360 * default permissions, so a umask of <code>0222</code> would make a
2361 * file read-only for everyone.
2363 * File.umask(0006) #=> 18
2368 rb_file_s_umask(int argc
, VALUE
*argv
)
2377 else if (argc
== 1) {
2378 omask
= umask(NUM2INT(argv
[0]));
2381 rb_raise(rb_eArgError
, "wrong number of arguments");
2383 return INT2FIX(omask
);
2389 #if defined __CYGWIN__ || defined DOSISH
2391 #define DOSISH_DRIVE_LETTER
2392 #define isdirsep(x) ((x) == '/' || (x) == '\\')
2394 #define isdirsep(x) ((x) == '/')
2397 #if defined _WIN32 || defined __CYGWIN__
2404 #define istrailinggabage(x) ((x) == '.' || (x) == ' ')
2406 #define istrailinggabage(x) 0
2409 #ifndef CharNext /* defined as CharNext[AW] on Windows. */
2411 # define CharNext(p) ((p) + mblen(p, RUBY_MBCHAR_MAXSIZE))
2413 # define CharNext(p) ((p) + 1)
2417 #ifdef DOSISH_DRIVE_LETTER
2419 has_drive_letter(const char *buf
)
2421 if (ISALPHA(buf
[0]) && buf
[1] == ':') {
2430 getcwdofdrv(int drv
)
2433 char *drvcwd
, *oldcwd
;
2439 /* the only way that I know to get the current directory
2440 of a particular drive is to change chdir() to that drive,
2441 so save the old cwd before chdir()
2443 oldcwd
= my_getcwd();
2444 if (chdir(drive
) == 0) {
2445 drvcwd
= my_getcwd();
2450 /* perhaps the drive is not exist. we return only drive letter */
2451 drvcwd
= strdup(drive
);
2457 static inline char *
2458 skiproot(const char *path
)
2460 #ifdef DOSISH_DRIVE_LETTER
2461 if (has_drive_letter(path
)) path
+= 2;
2463 while (isdirsep(*path
)) path
++;
2464 return (char *)path
;
2467 #define nextdirsep rb_path_next
2469 rb_path_next(const char *s
)
2471 while (*s
&& !isdirsep(*s
)) {
2477 #if defined(DOSISH_UNC) || defined(DOSISH_DRIVE_LETTER)
2478 #define skipprefix rb_path_skip_prefix
2480 #define skipprefix(path) (path)
2483 rb_path_skip_prefix(const char *path
)
2485 #if defined(DOSISH_UNC) || defined(DOSISH_DRIVE_LETTER)
2487 if (isdirsep(path
[0]) && isdirsep(path
[1])) {
2489 while (isdirsep(*path
)) path
++;
2490 if (*(path
= nextdirsep(path
)) && path
[1] && !isdirsep(path
[1]))
2491 path
= nextdirsep(path
+ 1);
2492 return (char *)path
;
2495 #ifdef DOSISH_DRIVE_LETTER
2496 if (has_drive_letter(path
))
2497 return (char *)(path
+ 2);
2500 return (char *)path
;
2503 #define strrdirsep rb_path_last_separator
2505 rb_path_last_separator(const char *path
)
2509 if (isdirsep(*path
)) {
2510 const char *tmp
= path
++;
2511 while (isdirsep(*path
)) path
++;
2516 path
= CharNext(path
);
2523 chompdirsep(const char *path
)
2526 if (isdirsep(*path
)) {
2527 const char *last
= path
++;
2528 while (isdirsep(*path
)) path
++;
2529 if (!*path
) return (char *)last
;
2532 path
= CharNext(path
);
2535 return (char *)path
;
2539 rb_path_end(const char *path
)
2541 if (isdirsep(*path
)) path
++;
2542 return chompdirsep(path
);
2547 ntfs_tail(const char *path
)
2549 while (*path
== '.') path
++;
2550 while (*path
&& *path
!= ':') {
2551 if (istrailinggabage(*path
)) {
2552 const char *last
= path
++;
2553 while (istrailinggabage(*path
)) path
++;
2554 if (!*path
|| *path
== ':') return (char *)last
;
2556 else if (isdirsep(*path
)) {
2557 const char *last
= path
++;
2558 while (isdirsep(*path
)) path
++;
2559 if (!*path
) return (char *)last
;
2560 if (*path
== ':') path
++;
2563 path
= CharNext(path
);
2566 return (char *)path
;
2570 #define BUFCHECK(cond) do {\
2571 long bdiff = p - buf;\
2573 do {buflen *= 2;} while (cond);\
2574 rb_str_resize(result, buflen);\
2575 buf = RSTRING_PTR(result);\
2577 pend = buf + buflen;\
2581 #define BUFINIT() (\
2582 p = buf = RSTRING_PTR(result),\
2583 buflen = RSTRING_LEN(result),\
2586 #define SET_EXTERNAL_ENCODING() (\
2587 (void)(extenc || (extenc = rb_default_external_encoding())),\
2588 rb_enc_associate(result, extenc))
2590 static int is_absolute_path(const char*);
2593 file_expand_path(VALUE fname
, VALUE dname
, VALUE result
)
2596 char *buf
, *p
, *pend
, *root
;
2597 long buflen
, dirlen
;
2599 rb_encoding
*extenc
= 0;
2601 FilePathValue(fname
);
2602 s
= StringValuePtr(fname
);
2604 tainted
= OBJ_TAINTED(fname
);
2607 if (isdirsep(s
[1]) || s
[1] == '\0') {
2608 const char *dir
= getenv("HOME");
2611 rb_raise(rb_eArgError
, "couldn't find HOME environment -- expanding `%s'", s
);
2613 dirlen
= strlen(dir
);
2614 BUFCHECK(dirlen
> buflen
);
2616 #if defined DOSISH || defined __CYGWIN__
2617 for (p
= buf
; *p
; p
= CharNext(p
)) {
2623 p
= buf
+ strlen(dir
);
2627 SET_EXTERNAL_ENCODING();
2631 struct passwd
*pwPtr
;
2634 s
= nextdirsep(b
= s
);
2635 BUFCHECK(bdiff
+ (s
-b
) >= buflen
);
2640 pwPtr
= getpwnam(buf
);
2643 rb_raise(rb_eArgError
, "user %s doesn't exist", buf
);
2645 dirlen
= strlen(pwPtr
->pw_dir
);
2646 BUFCHECK(dirlen
> buflen
);
2647 strcpy(buf
, pwPtr
->pw_dir
);
2648 p
= buf
+ strlen(pwPtr
->pw_dir
);
2653 #ifdef DOSISH_DRIVE_LETTER
2654 /* skip drive letter */
2655 else if (has_drive_letter(s
)) {
2656 if (isdirsep(s
[2])) {
2657 /* specified drive letter, and full path */
2658 /* skip drive letter */
2659 BUFCHECK(bdiff
+ 2 >= buflen
);
2665 /* specified drive, but not full path */
2667 if (!NIL_P(dname
)) {
2668 file_expand_path(dname
, Qnil
, result
);
2670 if (has_drive_letter(p
) && TOLOWER(p
[0]) == TOLOWER(s
[0])) {
2671 /* ok, same drive */
2676 char *dir
= getcwdofdrv(*s
);
2679 dirlen
= strlen(dir
);
2680 BUFCHECK(dirlen
> buflen
);
2683 SET_EXTERNAL_ENCODING();
2685 p
= chompdirsep(skiproot(buf
));
2690 else if (!is_absolute_path(s
)) {
2691 if (!NIL_P(dname
)) {
2692 file_expand_path(dname
, Qnil
, result
);
2696 char *dir
= my_getcwd();
2699 dirlen
= strlen(dir
);
2700 BUFCHECK(dirlen
> buflen
);
2703 SET_EXTERNAL_ENCODING();
2705 #if defined DOSISH || defined __CYGWIN__
2707 /* specified full path, but not drive letter nor UNC */
2708 /* we need to get the drive letter or UNC share name */
2709 p
= skipprefix(buf
);
2713 p
= chompdirsep(skiproot(buf
));
2717 do s
++; while (isdirsep(*s
));
2719 BUFCHECK(bdiff
>= buflen
);
2720 memset(buf
, '/', p
- buf
);
2722 if (p
> buf
&& p
[-1] == '/')
2726 BUFCHECK(bdiff
>= buflen
);
2731 root
= skipprefix(buf
);
2737 if (b
== s
++) { /* beginning of path element */
2743 if (*(s
+1) == '\0' || isdirsep(*(s
+1))) {
2744 /* We must go back to the parent */
2747 if (!(n
= strrdirsep(root
))) {
2757 do *++s
; while (istrailinggabage(*s
));
2762 #if defined DOSISH || defined __CYGWIN__
2768 /* ordinary path element, beginning don't move */
2777 while (istrailinggabage(*s
)) s
++;
2787 #if defined DOSISH || defined __CYGWIN__
2791 long rootdiff
= root
- buf
;
2792 BUFCHECK(bdiff
+ (s
-b
+1) >= buflen
);
2793 root
= buf
+ rootdiff
;
2794 memcpy(++p
, b
, s
-b
);
2809 if (s
> b
+ 6 && strncasecmp(s
- 6, ":$DATA", 6) == 0) {
2810 /* alias of stream */
2811 /* get rid of a bug of x64 VC++ */
2812 if (*(s
-7) == ':') s
-= 7; /* prime */
2813 else if (memchr(b
, ':', s
- 6 - b
)) s
-= 6; /* alternative */
2816 BUFCHECK(bdiff
+ (s
-b
) >= buflen
);
2817 memcpy(++p
, b
, s
-b
);
2820 if (p
== skiproot(buf
) - 1) p
++;
2824 if ((s
= strrdirsep(b
= buf
)) != 0 && !strpbrk(s
, "*?")) {
2826 WIN32_FIND_DATA wfd
;
2828 int lnk_added
= 0, is_symlink
= 0;
2830 char w32buf
[MAXPATHLEN
];
2832 if (lstat(buf
, &st
) == 0 && S_ISLNK(st
.st_mode
)) {
2836 if (cygwin_conv_to_win32_path((*buf
? buf
: "/"), w32buf
) == 0) {
2839 if (is_symlink
&& b
== w32buf
) {
2841 strlcat(w32buf
, p
, sizeof(w32buf
));
2843 if (len
> 4 && STRCASECMP(p
+ len
- 4, ".lnk") != 0) {
2845 strlcat(w32buf
, ".lnk", sizeof(w32buf
));
2850 HANDLE h
= FindFirstFile(b
, &wfd
);
2851 if (h
!= INVALID_HANDLE_VALUE
) {
2853 len
= strlen(wfd
.cFileName
);
2855 if (lnk_added
&& len
> 4 &&
2856 STRCASECMP(wfd
.cFileName
+ len
- 4, ".lnk") == 0) {
2857 wfd
.cFileName
[len
-= 4] = '\0';
2863 BUFCHECK(bdiff
+ len
>= buflen
);
2864 memcpy(p
, wfd
.cFileName
, len
+ 1);
2875 if (tainted
) OBJ_TAINT(result
);
2876 rb_str_set_len(result
, p
- buf
);
2877 rb_enc_check(fname
, result
);
2882 rb_file_expand_path(VALUE fname
, VALUE dname
)
2884 return file_expand_path(fname
, dname
, rb_usascii_str_new(0, MAXPATHLEN
+ 2));
2889 * File.expand_path(file_name [, dir_string] ) -> abs_file_name
2891 * Converts a pathname to an absolute pathname. Relative paths are
2892 * referenced from the current working directory of the process unless
2893 * <i>dir_string</i> is given, in which case it will be used as the
2894 * starting point. The given pathname may start with a
2895 * ``<code>~</code>'', which expands to the process owner's home
2896 * directory (the environment variable <code>HOME</code> must be set
2897 * correctly). ``<code>~</code><i>user</i>'' expands to the named
2898 * user's home directory.
2900 * File.expand_path("~oracle/bin") #=> "/home/oracle/bin"
2901 * File.expand_path("../../bin", "/tmp/x") #=> "/bin"
2905 rb_file_s_expand_path(int argc
, VALUE
*argv
)
2910 return rb_file_expand_path(argv
[0], Qnil
);
2912 rb_scan_args(argc
, argv
, "11", &fname
, &dname
);
2914 return rb_file_expand_path(fname
, dname
);
2918 rmext(const char *p
, int l1
, const char *e
)
2925 if (l2
== 2 && e
[1] == '*') {
2926 unsigned char c
= *e
;
2929 if (e
<= p
) return 0;
2930 } while (*--e
!= c
);
2933 if (l1
< l2
) return l1
;
2935 #if CASEFOLD_FILESYSTEM
2936 #define fncomp strncasecmp
2938 #define fncomp strncmp
2940 if (fncomp(p
+l1
-l2
, e
, l2
) == 0) {
2948 * File.basename(file_name [, suffix] ) -> base_name
2950 * Returns the last component of the filename given in <i>file_name</i>,
2951 * which must be formed using forward slashes (``<code>/</code>'')
2952 * regardless of the separator used on the local file system. If
2953 * <i>suffix</i> is given and present at the end of <i>file_name</i>,
2956 * File.basename("/home/gumby/work/ruby.rb") #=> "ruby.rb"
2957 * File.basename("/home/gumby/work/ruby.rb", ".rb") #=> "ruby"
2961 rb_file_s_basename(int argc
, VALUE
*argv
)
2963 VALUE fname
, fext
, basename
;
2964 const char *name
, *p
;
2965 #if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC
2970 if (rb_scan_args(argc
, argv
, "11", &fname
, &fext
) == 2) {
2973 FilePathStringValue(fname
);
2974 if (RSTRING_LEN(fname
) == 0 || !*(name
= RSTRING_PTR(fname
)))
2976 name
= skipprefix(name
);
2977 #if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC
2980 while (isdirsep(*name
))
2985 #if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC
2989 #ifdef DOSISH_DRIVE_LETTER
2990 else if (*p
== ':') {
3003 if (!(p
= strrdirsep(name
))) {
3007 while (isdirsep(*p
)) p
++; /* skip last / */
3010 n
= ntfs_tail(p
) - p
;
3012 n
= chompdirsep(p
) - p
;
3014 if (NIL_P(fext
) || !(f
= rmext(p
, n
, StringValueCStr(fext
)))) {
3017 if (f
== RSTRING_LEN(fname
)) return fname
;
3019 basename
= rb_str_new(p
, f
);
3020 rb_enc_copy(basename
, fname
);
3021 OBJ_INFECT(basename
, fname
);
3027 * File.dirname(file_name ) -> dir_name
3029 * Returns all components of the filename given in <i>file_name</i>
3030 * except the last one. The filename must be formed using forward
3031 * slashes (``<code>/</code>'') regardless of the separator used on the
3032 * local file system.
3034 * File.dirname("/home/gumby/work/ruby.rb") #=> "/home/gumby/work"
3038 rb_file_s_dirname(VALUE klass
, VALUE fname
)
3040 const char *name
, *root
, *p
;
3043 FilePathStringValue(fname
);
3044 name
= StringValueCStr(fname
);
3045 root
= skiproot(name
);
3047 if (root
> name
+ 1 && isdirsep(*name
))
3048 root
= skipprefix(name
= root
- 2);
3050 if (root
> name
+ 1)
3053 p
= strrdirsep(root
);
3058 return rb_usascii_str_new2(".");
3059 #ifdef DOSISH_DRIVE_LETTER
3060 if (has_drive_letter(name
) && isdirsep(*(name
+ 2))) {
3061 const char *top
= skiproot(name
+ 2);
3062 dirname
= rb_str_new(name
, 3);
3063 rb_str_cat(dirname
, top
, p
- top
);
3067 dirname
= rb_str_new(name
, p
- name
);
3068 #ifdef DOSISH_DRIVE_LETTER
3069 if (has_drive_letter(name
) && root
== name
+ 2 && p
- name
== 2)
3070 rb_str_cat(dirname
, ".", 1);
3072 rb_enc_copy(dirname
, fname
);
3073 OBJ_INFECT(dirname
, fname
);
3079 * File.extname(path) -> string
3081 * Returns the extension (the portion of file name in <i>path</i>
3082 * after the period).
3084 * File.extname("test.rb") #=> ".rb"
3085 * File.extname("a/b/d/test.rb") #=> ".rb"
3086 * File.extname("test") #=> ""
3087 * File.extname(".profile") #=> ""
3092 rb_file_s_extname(VALUE klass
, VALUE fname
)
3094 const char *name
, *p
, *e
;
3097 FilePathStringValue(fname
);
3098 name
= StringValueCStr(fname
);
3099 p
= strrdirsep(name
); /* get the last path component */
3107 if (*p
== '.' || istrailinggabage(*p
)) {
3109 const char *last
= p
++, *dot
= last
;
3110 while (istrailinggabage(*p
)) {
3111 if (*p
== '.') dot
= p
;
3114 if (!*p
|| *p
== ':') {
3118 if (*last
== '.') e
= dot
;
3121 e
= p
; /* get the last dot of the last component */
3125 else if (*p
== ':') {
3129 else if (isdirsep(*p
))
3133 if (!e
|| e
== name
|| e
+1 == p
) /* no dot, or the only dot is first or end? */
3134 return rb_str_new(0, 0);
3135 extname
= rb_str_new(e
, p
- e
); /* keep the dot, too! */
3136 rb_enc_copy(extname
, fname
);
3137 OBJ_INFECT(extname
, fname
);
3143 * File.path(path) -> string
3145 * Returns the string representation of the path
3147 * File.path("/dev/null") #=> "/dev/null"
3148 * File.path(Pathname.new("/tmp")) #=> "/tmp"
3153 rb_file_s_path(VALUE klass
, VALUE fname
)
3155 return rb_get_path(fname
);
3160 * File.split(file_name) => array
3162 * Splits the given string into a directory and a file component and
3163 * returns them in a two-element array. See also
3164 * <code>File::dirname</code> and <code>File::basename</code>.
3166 * File.split("/home/gumby/.profile") #=> ["/home/gumby", ".profile"]
3170 rb_file_s_split(VALUE klass
, VALUE path
)
3172 FilePathStringValue(path
); /* get rid of converting twice */
3173 return rb_assoc_new(rb_file_s_dirname(Qnil
, path
), rb_file_s_basename(1,&path
));
3176 static VALUE separator
;
3178 static VALUE
rb_file_join(VALUE ary
, VALUE sep
);
3181 file_inspect_join(VALUE ary
, VALUE argp
, int recur
)
3183 VALUE
*arg
= (VALUE
*)argp
;
3184 if (recur
) return rb_usascii_str_new2("[...]");
3185 return rb_file_join(arg
[0], arg
[1]);
3189 rb_file_join(VALUE ary
, VALUE sep
)
3193 const char *name
, *tail
;
3195 if (RARRAY_LEN(ary
) == 0) return rb_str_new(0, 0);
3198 for (i
=0; i
<RARRAY_LEN(ary
); i
++) {
3199 if (TYPE(RARRAY_PTR(ary
)[i
]) == T_STRING
) {
3200 len
+= RSTRING_LEN(RARRAY_PTR(ary
)[i
]);
3208 len
+= RSTRING_LEN(sep
) * RARRAY_LEN(ary
) - 1;
3210 result
= rb_str_buf_new(len
);
3211 OBJ_INFECT(result
, ary
);
3212 for (i
=0; i
<RARRAY_LEN(ary
); i
++) {
3213 tmp
= RARRAY_PTR(ary
)[i
];
3214 switch (TYPE(tmp
)) {
3223 tmp
= rb_exec_recursive(file_inspect_join
, ary
, (VALUE
)args
);
3227 FilePathStringValue(tmp
);
3229 name
= StringValueCStr(result
);
3230 if (i
> 0 && !NIL_P(sep
)) {
3231 tail
= chompdirsep(name
);
3232 if (RSTRING_PTR(tmp
) && isdirsep(RSTRING_PTR(tmp
)[0])) {
3233 rb_str_set_len(result
, tail
- name
);
3236 rb_str_buf_append(result
, sep
);
3239 rb_str_buf_append(result
, tmp
);
3247 * File.join(string, ...) -> path
3249 * Returns a new string formed by joining the strings using
3250 * <code>File::SEPARATOR</code>.
3252 * File.join("usr", "mail", "gumby") #=> "usr/mail/gumby"
3257 rb_file_s_join(VALUE klass
, VALUE args
)
3259 return rb_file_join(args
, separator
);
3264 * File.truncate(file_name, integer) => 0
3266 * Truncates the file <i>file_name</i> to be at most <i>integer</i>
3267 * bytes long. Not available on all platforms.
3269 * f = File.new("out", "w")
3270 * f.write("1234567890") #=> 10
3272 * File.truncate("out", 5) #=> 0
3273 * File.size("out") #=> 5
3278 rb_file_s_truncate(VALUE klass
, VALUE path
, VALUE len
)
3283 pos
= NUM2OFFT(len
);
3284 FilePathValue(path
);
3285 #ifdef HAVE_TRUNCATE
3286 if (truncate(StringValueCStr(path
), pos
) < 0)
3287 rb_sys_fail(RSTRING_PTR(path
));
3294 if ((tmpfd
= open(StringValueCStr(path
), O_RDWR
)) < 0) {
3295 rb_sys_fail(RSTRING_PTR(path
));
3298 if ((tmpfd
= open(StringValueCStr(path
), 0)) < 0) {
3299 rb_sys_fail(RSTRING_PTR(path
));
3302 if (chsize(tmpfd
, pos
) < 0) {
3304 rb_sys_fail(RSTRING_PTR(path
));
3317 * file.truncate(integer) => 0
3319 * Truncates <i>file</i> to at most <i>integer</i> bytes. The file
3320 * must be opened for writing. Not available on all platforms.
3322 * f = File.new("out", "w")
3323 * f.syswrite("1234567890") #=> 10
3324 * f.truncate(5) #=> 0
3326 * File.size("out") #=> 5
3330 rb_file_truncate(VALUE obj
, VALUE len
)
3336 pos
= NUM2OFFT(len
);
3337 GetOpenFile(obj
, fptr
);
3338 if (!(fptr
->mode
& FMODE_WRITABLE
)) {
3339 rb_raise(rb_eIOError
, "not opened for writing");
3342 #ifdef HAVE_FTRUNCATE
3343 if (ftruncate(fptr
->fd
, pos
) < 0)
3344 rb_sys_fail(fptr
->path
);
3347 if (chsize(fptr
->fd
, pos
) < 0)
3348 rb_sys_fail(fptr
->path
);
3370 #include <winerror.h>
3371 extern unsigned long __attribute__((stdcall)) GetLastError(void);
3375 rb_thread_flock(void *data
)
3378 int old_errno
= errno
;
3380 int *op
= data
, ret
= flock(op
[0], op
[1]);
3383 if (GetLastError() == ERROR_NOT_LOCKED
) {
3393 * file.flock (locking_constant ) => 0 or false
3395 * Locks or unlocks a file according to <i>locking_constant</i> (a
3396 * logical <em>or</em> of the values in the table below).
3397 * Returns <code>false</code> if <code>File::LOCK_NB</code> is
3398 * specified and the operation would otherwise have blocked. Not
3399 * available on all platforms.
3401 * Locking constants (in class File):
3403 * LOCK_EX | Exclusive lock. Only one process may hold an
3404 * | exclusive lock for a given file at a time.
3405 * ----------+------------------------------------------------
3406 * LOCK_NB | Don't block when locking. May be combined
3407 * | with other lock options using logical or.
3408 * ----------+------------------------------------------------
3409 * LOCK_SH | Shared lock. Multiple processes may each hold a
3410 * | shared lock for a given file at the same time.
3411 * ----------+------------------------------------------------
3416 * File.new("testfile").flock(File::LOCK_UN) #=> 0
3421 rb_file_flock(VALUE obj
, VALUE operation
)
3428 op
[1] = op1
= NUM2INT(operation
);
3429 GetOpenFile(obj
, fptr
);
3432 if (fptr
->mode
& FMODE_WRITABLE
) {
3435 while ((int)rb_thread_blocking_region(rb_thread_flock
, op
, RB_UBF_DFL
, 0) < 0) {
3439 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
3442 if (op1
& LOCK_NB
) return Qfalse
;
3443 rb_thread_polling();
3444 rb_io_check_closed(fptr
);
3448 #if defined(ERESTART)
3454 rb_sys_fail(fptr
->path
);
3463 test_check(int n
, int argc
, VALUE
*argv
)
3469 if (n
!= argc
) rb_raise(rb_eArgError
, "wrong number of arguments (%d for %d)", argc
, n
);
3470 for (i
=1; i
<n
; i
++) {
3471 switch (TYPE(argv
[i
])) {
3474 FilePathValue(argv
[i
]);
3482 #define CHECK(n) test_check((n), argc, argv)
3486 * test(int_cmd, file1 [, file2] ) => obj
3488 * Uses the integer <i>aCmd</i> to perform various tests on
3489 * <i>file1</i> (first table below) or on <i>file1</i> and
3490 * <i>file2</i> (second table).
3492 * File tests on a single file:
3494 * Test Returns Meaning
3495 * ?A | Time | Last access time for file1
3496 * ?b | boolean | True if file1 is a block device
3497 * ?c | boolean | True if file1 is a character device
3498 * ?C | Time | Last change time for file1
3499 * ?d | boolean | True if file1 exists and is a directory
3500 * ?e | boolean | True if file1 exists
3501 * ?f | boolean | True if file1 exists and is a regular file
3502 * ?g | boolean | True if file1 has the \CF{setgid} bit
3503 * | | set (false under NT)
3504 * ?G | boolean | True if file1 exists and has a group
3505 * | | ownership equal to the caller's group
3506 * ?k | boolean | True if file1 exists and has the sticky bit set
3507 * ?l | boolean | True if file1 exists and is a symbolic link
3508 * ?M | Time | Last modification time for file1
3509 * ?o | boolean | True if file1 exists and is owned by
3510 * | | the caller's effective uid
3511 * ?O | boolean | True if file1 exists and is owned by
3512 * | | the caller's real uid
3513 * ?p | boolean | True if file1 exists and is a fifo
3514 * ?r | boolean | True if file1 is readable by the effective
3515 * | | uid/gid of the caller
3516 * ?R | boolean | True if file is readable by the real
3517 * | | uid/gid of the caller
3518 * ?s | int/nil | If file1 has nonzero size, return the size,
3519 * | | otherwise return nil
3520 * ?S | boolean | True if file1 exists and is a socket
3521 * ?u | boolean | True if file1 has the setuid bit set
3522 * ?w | boolean | True if file1 exists and is writable by
3523 * | | the effective uid/gid
3524 * ?W | boolean | True if file1 exists and is writable by
3525 * | | the real uid/gid
3526 * ?x | boolean | True if file1 exists and is executable by
3527 * | | the effective uid/gid
3528 * ?X | boolean | True if file1 exists and is executable by
3529 * | | the real uid/gid
3530 * ?z | boolean | True if file1 exists and has a zero length
3532 * Tests that take two files:
3534 * ?- | boolean | True if file1 and file2 are identical
3535 * ?= | boolean | True if the modification times of file1
3536 * | | and file2 are equal
3537 * ?< | boolean | True if the modification time of file1
3538 * | | is prior to that of file2
3539 * ?> | boolean | True if the modification time of file1
3540 * | | is after that of file2
3544 rb_f_test(int argc
, VALUE
*argv
)
3548 if (argc
== 0) rb_raise(rb_eArgError
, "wrong number of arguments");
3549 cmd
= NUM2CHR(argv
[0]);
3550 if (cmd
== 0) goto unknown
;
3551 if (strchr("bcdefgGkloOprRsSuwWxXz", cmd
)) {
3555 return rb_file_blockdev_p(0, argv
[1]);
3558 return rb_file_chardev_p(0, argv
[1]);
3561 return rb_file_directory_p(0, argv
[1]);
3565 return rb_file_exist_p(0, argv
[1]);
3568 return rb_file_file_p(0, argv
[1]);
3571 return rb_file_sgid_p(0, argv
[1]);
3574 return rb_file_grpowned_p(0, argv
[1]);
3577 return rb_file_sticky_p(0, argv
[1]);
3580 return rb_file_symlink_p(0, argv
[1]);
3583 return rb_file_owned_p(0, argv
[1]);
3586 return rb_file_rowned_p(0, argv
[1]);
3589 return rb_file_pipe_p(0, argv
[1]);
3592 return rb_file_readable_p(0, argv
[1]);
3595 return rb_file_readable_real_p(0, argv
[1]);
3598 return rb_file_size_p(0, argv
[1]);
3601 return rb_file_socket_p(0, argv
[1]);
3604 return rb_file_suid_p(0, argv
[1]);
3607 return rb_file_writable_p(0, argv
[1]);
3610 return rb_file_world_writable_p(0, argv
[1]);
3613 return rb_file_executable_p(0, argv
[1]);
3616 return rb_file_executable_real_p(0, argv
[1]);
3619 return rb_file_zero_p(0, argv
[1]);
3623 if (strchr("MAC", cmd
)) {
3627 if (rb_stat(argv
[1], &st
) == -1) {
3628 rb_sys_fail(RSTRING_PTR(argv
[1]));
3633 return stat_atime(&st
);
3635 return stat_mtime(&st
);
3637 return stat_ctime(&st
);
3643 return rb_file_identical_p(0, argv
[1], argv
[2]);
3646 if (strchr("=<>", cmd
)) {
3647 struct stat st1
, st2
;
3650 if (rb_stat(argv
[1], &st1
) < 0) return Qfalse
;
3651 if (rb_stat(argv
[2], &st2
) < 0) return Qfalse
;
3655 if (st1
.st_mtime
== st2
.st_mtime
) return Qtrue
;
3659 if (st1
.st_mtime
> st2
.st_mtime
) return Qtrue
;
3663 if (st1
.st_mtime
< st2
.st_mtime
) return Qtrue
;
3668 /* unknown command */
3670 rb_raise(rb_eArgError
, "unknown command ?%c", cmd
);
3673 rb_raise(rb_eArgError
, "unknown command ?\\x%02X", cmd
);
3675 return Qnil
; /* not reached */
3681 * Document-class: File::Stat
3683 * Objects of class <code>File::Stat</code> encapsulate common status
3684 * information for <code>File</code> objects. The information is
3685 * recorded at the moment the <code>File::Stat</code> object is
3686 * created; changes made to the file after that point will not be
3687 * reflected. <code>File::Stat</code> objects are returned by
3688 * <code>IO#stat</code>, <code>File::stat</code>,
3689 * <code>File#lstat</code>, and <code>File::lstat</code>. Many of these
3690 * methods return platform-specific values, and not all values are
3691 * meaningful on all systems. See also <code>Kernel#test</code>.
3695 rb_stat_s_alloc(VALUE klass
)
3697 return stat_new_0(klass
, 0);
3703 * File::Stat.new(file_name) => stat
3705 * Create a File::Stat object for the given file name (raising an
3706 * exception if the file doesn't exist).
3710 rb_stat_init(VALUE obj
, VALUE fname
)
3712 struct stat st
, *nst
;
3715 FilePathValue(fname
);
3716 if (stat(StringValueCStr(fname
), &st
) == -1) {
3717 rb_sys_fail(RSTRING_PTR(fname
));
3719 if (DATA_PTR(obj
)) {
3720 xfree(DATA_PTR(obj
));
3721 DATA_PTR(obj
) = NULL
;
3723 nst
= ALLOC(struct stat
);
3725 DATA_PTR(obj
) = nst
;
3732 rb_stat_init_copy(VALUE copy
, VALUE orig
)
3736 if (copy
== orig
) return orig
;
3737 rb_check_frozen(copy
);
3738 /* need better argument type check */
3739 if (!rb_obj_is_instance_of(orig
, rb_obj_class(copy
))) {
3740 rb_raise(rb_eTypeError
, "wrong argument class");
3742 if (DATA_PTR(copy
)) {
3743 xfree(DATA_PTR(copy
));
3746 if (DATA_PTR(orig
)) {
3747 nst
= ALLOC(struct stat
);
3748 *nst
= *(struct stat
*)DATA_PTR(orig
);
3749 DATA_PTR(copy
) = nst
;
3757 * stat.ftype => string
3759 * Identifies the type of <i>stat</i>. The return string is one of:
3760 * ``<code>file</code>'', ``<code>directory</code>'',
3761 * ``<code>characterSpecial</code>'', ``<code>blockSpecial</code>'',
3762 * ``<code>fifo</code>'', ``<code>link</code>'',
3763 * ``<code>socket</code>'', or ``<code>unknown</code>''.
3765 * File.stat("/dev/tty").ftype #=> "characterSpecial"
3770 rb_stat_ftype(VALUE obj
)
3772 return rb_file_ftype(get_stat(obj
));
3777 * stat.directory? => true or false
3779 * Returns <code>true</code> if <i>stat</i> is a directory,
3780 * <code>false</code> otherwise.
3782 * File.stat("testfile").directory? #=> false
3783 * File.stat(".").directory? #=> true
3787 rb_stat_d(VALUE obj
)
3789 if (S_ISDIR(get_stat(obj
)->st_mode
)) return Qtrue
;
3795 * stat.pipe? => true or false
3797 * Returns <code>true</code> if the operating system supports pipes and
3798 * <i>stat</i> is a pipe; <code>false</code> otherwise.
3802 rb_stat_p(VALUE obj
)
3805 if (S_ISFIFO(get_stat(obj
)->st_mode
)) return Qtrue
;
3813 * stat.symlink? => true or false
3815 * Returns <code>true</code> if <i>stat</i> is a symbolic link,
3816 * <code>false</code> if it isn't or if the operating system doesn't
3817 * support this feature. As <code>File::stat</code> automatically
3818 * follows symbolic links, <code>symlink?</code> will always be
3819 * <code>false</code> for an object returned by
3820 * <code>File::stat</code>.
3822 * File.symlink("testfile", "alink") #=> 0
3823 * File.stat("alink").symlink? #=> false
3824 * File.lstat("alink").symlink? #=> true
3829 rb_stat_l(VALUE obj
)
3832 if (S_ISLNK(get_stat(obj
)->st_mode
)) return Qtrue
;
3839 * stat.socket? => true or false
3841 * Returns <code>true</code> if <i>stat</i> is a socket,
3842 * <code>false</code> if it isn't or if the operating system doesn't
3843 * support this feature.
3845 * File.stat("testfile").socket? #=> false
3850 rb_stat_S(VALUE obj
)
3853 if (S_ISSOCK(get_stat(obj
)->st_mode
)) return Qtrue
;
3861 * stat.blockdev? => true or false
3863 * Returns <code>true</code> if the file is a block device,
3864 * <code>false</code> if it isn't or if the operating system doesn't
3865 * support this feature.
3867 * File.stat("testfile").blockdev? #=> false
3868 * File.stat("/dev/hda1").blockdev? #=> true
3873 rb_stat_b(VALUE obj
)
3876 if (S_ISBLK(get_stat(obj
)->st_mode
)) return Qtrue
;
3884 * stat.chardev? => true or false
3886 * Returns <code>true</code> if the file is a character device,
3887 * <code>false</code> if it isn't or if the operating system doesn't
3888 * support this feature.
3890 * File.stat("/dev/tty").chardev? #=> true
3895 rb_stat_c(VALUE obj
)
3897 if (S_ISCHR(get_stat(obj
)->st_mode
)) return Qtrue
;
3904 * stat.owned? => true or false
3906 * Returns <code>true</code> if the effective user id of the process is
3907 * the same as the owner of <i>stat</i>.
3909 * File.stat("testfile").owned? #=> true
3910 * File.stat("/etc/passwd").owned? #=> false
3915 rb_stat_owned(VALUE obj
)
3917 if (get_stat(obj
)->st_uid
== geteuid()) return Qtrue
;
3922 rb_stat_rowned(VALUE obj
)
3924 if (get_stat(obj
)->st_uid
== getuid()) return Qtrue
;
3930 * stat.grpowned? => true or false
3932 * Returns true if the effective group id of the process is the same as
3933 * the group id of <i>stat</i>. On Windows NT, returns <code>false</code>.
3935 * File.stat("testfile").grpowned? #=> true
3936 * File.stat("/etc/passwd").grpowned? #=> false
3941 rb_stat_grpowned(VALUE obj
)
3944 if (group_member(get_stat(obj
)->st_gid
)) return Qtrue
;
3951 * stat.readable? => true or false
3953 * Returns <code>true</code> if <i>stat</i> is readable by the
3954 * effective user id of this process.
3956 * File.stat("testfile").readable? #=> true
3961 rb_stat_r(VALUE obj
)
3963 struct stat
*st
= get_stat(obj
);
3966 if (geteuid() == 0) return Qtrue
;
3969 if (rb_stat_owned(obj
))
3970 return st
->st_mode
& S_IRUSR
? Qtrue
: Qfalse
;
3973 if (rb_stat_grpowned(obj
))
3974 return st
->st_mode
& S_IRGRP
? Qtrue
: Qfalse
;
3977 if (!(st
->st_mode
& S_IROTH
)) return Qfalse
;
3986 * stat.readable_real? -> true or false
3988 * Returns <code>true</code> if <i>stat</i> is readable by the real
3989 * user id of this process.
3991 * File.stat("testfile").readable_real? #=> true
3996 rb_stat_R(VALUE obj
)
3998 struct stat
*st
= get_stat(obj
);
4001 if (getuid() == 0) return Qtrue
;
4004 if (rb_stat_rowned(obj
))
4005 return st
->st_mode
& S_IRUSR
? Qtrue
: Qfalse
;
4008 if (group_member(get_stat(obj
)->st_gid
))
4009 return st
->st_mode
& S_IRGRP
? Qtrue
: Qfalse
;
4012 if (!(st
->st_mode
& S_IROTH
)) return Qfalse
;
4019 * stat.world_readable? => fixnum or nil
4021 * If <i>stat</i> is readable by others, returns an integer
4022 * representing the file permission bits of <i>stat</i>. Returns
4023 * <code>nil</code> otherwise. The meaning of the bits is platform
4024 * dependent; on Unix systems, see <code>stat(2)</code>.
4026 * m = File.stat("/etc/passwd").world_readable? # => 420
4027 * sprintf("%o", m) # => "644"
4031 rb_stat_wr(VALUE obj
)
4034 if ((get_stat(obj
)->st_mode
& (S_IROTH
)) == S_IROTH
) {
4035 return UINT2NUM(get_stat(obj
)->st_mode
& (S_IRUGO
|S_IWUGO
|S_IXUGO
));
4045 * stat.writable? -> true or false
4047 * Returns <code>true</code> if <i>stat</i> is writable by the
4048 * effective user id of this process.
4050 * File.stat("testfile").writable? #=> true
4055 rb_stat_w(VALUE obj
)
4057 struct stat
*st
= get_stat(obj
);
4060 if (geteuid() == 0) return Qtrue
;
4063 if (rb_stat_owned(obj
))
4064 return st
->st_mode
& S_IWUSR
? Qtrue
: Qfalse
;
4067 if (rb_stat_grpowned(obj
))
4068 return st
->st_mode
& S_IWGRP
? Qtrue
: Qfalse
;
4071 if (!(st
->st_mode
& S_IWOTH
)) return Qfalse
;
4078 * stat.writable_real? -> true or false
4080 * Returns <code>true</code> if <i>stat</i> is writable by the real
4081 * user id of this process.
4083 * File.stat("testfile").writable_real? #=> true
4088 rb_stat_W(VALUE obj
)
4090 struct stat
*st
= get_stat(obj
);
4093 if (getuid() == 0) return Qtrue
;
4096 if (rb_stat_rowned(obj
))
4097 return st
->st_mode
& S_IWUSR
? Qtrue
: Qfalse
;
4100 if (group_member(get_stat(obj
)->st_gid
))
4101 return st
->st_mode
& S_IWGRP
? Qtrue
: Qfalse
;
4104 if (!(st
->st_mode
& S_IWOTH
)) return Qfalse
;
4111 * stat.world_writable? => fixnum or nil
4113 * If <i>stat</i> is writable by others, returns an integer
4114 * representing the file permission bits of <i>stat</i>. Returns
4115 * <code>nil</code> otherwise. The meaning of the bits is platform
4116 * dependent; on Unix systems, see <code>stat(2)</code>.
4118 * m = File.stat("/tmp").world_writable? # => 511
4119 * sprintf("%o", m) # => "777"
4123 rb_stat_ww(VALUE obj
)
4126 if ((get_stat(obj
)->st_mode
& (S_IWOTH
)) == S_IWOTH
) {
4127 return UINT2NUM(get_stat(obj
)->st_mode
& (S_IRUGO
|S_IWUGO
|S_IXUGO
));
4137 * stat.executable? => true or false
4139 * Returns <code>true</code> if <i>stat</i> is executable or if the
4140 * operating system doesn't distinguish executable files from
4141 * nonexecutable files. The tests are made using the effective owner of
4144 * File.stat("testfile").executable? #=> false
4149 rb_stat_x(VALUE obj
)
4151 struct stat
*st
= get_stat(obj
);
4154 if (geteuid() == 0) {
4155 return st
->st_mode
& S_IXUGO
? Qtrue
: Qfalse
;
4159 if (rb_stat_owned(obj
))
4160 return st
->st_mode
& S_IXUSR
? Qtrue
: Qfalse
;
4163 if (rb_stat_grpowned(obj
))
4164 return st
->st_mode
& S_IXGRP
? Qtrue
: Qfalse
;
4167 if (!(st
->st_mode
& S_IXOTH
)) return Qfalse
;
4174 * stat.executable_real? => true or false
4176 * Same as <code>executable?</code>, but tests using the real owner of
4182 rb_stat_X(VALUE obj
)
4184 struct stat
*st
= get_stat(obj
);
4187 if (getuid() == 0) {
4188 return st
->st_mode
& S_IXUGO
? Qtrue
: Qfalse
;
4192 if (rb_stat_rowned(obj
))
4193 return st
->st_mode
& S_IXUSR
? Qtrue
: Qfalse
;
4196 if (group_member(get_stat(obj
)->st_gid
))
4197 return st
->st_mode
& S_IXGRP
? Qtrue
: Qfalse
;
4200 if (!(st
->st_mode
& S_IXOTH
)) return Qfalse
;
4207 * stat.file? => true or false
4209 * Returns <code>true</code> if <i>stat</i> is a regular file (not
4210 * a device file, pipe, socket, etc.).
4212 * File.stat("testfile").file? #=> true
4217 rb_stat_f(VALUE obj
)
4219 if (S_ISREG(get_stat(obj
)->st_mode
)) return Qtrue
;
4225 * stat.zero? => true or false
4227 * Returns <code>true</code> if <i>stat</i> is a zero-length file;
4228 * <code>false</code> otherwise.
4230 * File.stat("testfile").zero? #=> false
4235 rb_stat_z(VALUE obj
)
4237 if (get_stat(obj
)->st_size
== 0) return Qtrue
;
4244 * state.size => integer
4246 * Returns the size of <i>stat</i> in bytes.
4248 * File.stat("testfile").size #=> 66
4253 rb_stat_s(VALUE obj
)
4255 off_t size
= get_stat(obj
)->st_size
;
4257 if (size
== 0) return Qnil
;
4258 return OFFT2NUM(size
);
4263 * stat.setuid? => true or false
4265 * Returns <code>true</code> if <i>stat</i> has the set-user-id
4266 * permission bit set, <code>false</code> if it doesn't or if the
4267 * operating system doesn't support this feature.
4269 * File.stat("/bin/su").setuid? #=> true
4273 rb_stat_suid(VALUE obj
)
4276 if (get_stat(obj
)->st_mode
& S_ISUID
) return Qtrue
;
4283 * stat.setgid? => true or false
4285 * Returns <code>true</code> if <i>stat</i> has the set-group-id
4286 * permission bit set, <code>false</code> if it doesn't or if the
4287 * operating system doesn't support this feature.
4289 * File.stat("/usr/sbin/lpc").setgid? #=> true
4294 rb_stat_sgid(VALUE obj
)
4297 if (get_stat(obj
)->st_mode
& S_ISGID
) return Qtrue
;
4304 * stat.sticky? => true or false
4306 * Returns <code>true</code> if <i>stat</i> has its sticky bit set,
4307 * <code>false</code> if it doesn't or if the operating system doesn't
4308 * support this feature.
4310 * File.stat("testfile").sticky? #=> false
4315 rb_stat_sticky(VALUE obj
)
4318 if (get_stat(obj
)->st_mode
& S_ISVTX
) return Qtrue
;
4326 rb_file_const(const char *name
, VALUE value
)
4328 rb_define_const(rb_mFConst
, name
, value
);
4332 is_absolute_path(const char *path
)
4334 #ifdef DOSISH_DRIVE_LETTER
4335 if (has_drive_letter(path
) && isdirsep(path
[2])) return 1;
4338 if (isdirsep(path
[0]) && isdirsep(path
[1])) return 1;
4341 if (path
[0] == '/') return 1;
4346 #ifndef ENABLE_PATH_CHECK
4347 # if defined DOSISH || defined __CYGWIN__
4348 # define ENABLE_PATH_CHECK 0
4350 # define ENABLE_PATH_CHECK 1
4354 #if ENABLE_PATH_CHECK
4356 path_check_0(VALUE path
, int execpath
)
4359 const char *p0
= StringValueCStr(path
);
4362 if (!is_absolute_path(p0
)) {
4363 char *buf
= my_getcwd();
4366 newpath
= rb_str_new2(buf
);
4369 rb_str_cat2(newpath
, "/");
4370 rb_str_cat2(newpath
, p0
);
4371 p0
= RSTRING_PTR(path
= newpath
);
4375 # define S_IWOTH 002
4377 if (stat(p0
, &st
) == 0 && S_ISDIR(st
.st_mode
) && (st
.st_mode
& S_IWOTH
)
4379 && !(p
&& execpath
&& (st
.st_mode
& S_ISVTX
))
4381 && !access(p0
, W_OK
)) {
4382 rb_warn("Insecure world writable dir %s in %sPATH, mode 0%o",
4383 p0
, (execpath
? "" : "LOAD_"), st
.st_mode
);
4389 if (!s
|| s
== p0
) return 1;
4397 fpath_check(const char *path
)
4399 #if ENABLE_PATH_CHECK
4400 return path_check_0(rb_str_new2(path
), Qfalse
);
4407 rb_path_check(const char *path
)
4409 #if ENABLE_PATH_CHECK
4410 const char *p0
, *p
, *pend
;
4411 const char sep
= PATH_SEP_CHAR
;
4413 if (!path
) return 1;
4415 pend
= path
+ strlen(path
);
4417 p
= strchr(path
, sep
);
4421 if (!path_check_0(rb_str_new(p0
, p
- p0
), Qtrue
)) {
4422 return 0; /* not safe */
4425 if (p0
> pend
) break;
4426 p
= strchr(p0
, sep
);
4433 #if defined(__MACOS__) || defined(riscos)
4435 is_macos_native_path(const char *path
)
4437 if (strchr(path
, ':')) return 1;
4443 file_load_ok(const char *path
)
4445 return eaccess(path
, R_OK
) == 0;
4449 is_explicit_relative(const char *path
)
4451 if (*path
++ != '.') return 0;
4452 if (*path
== '.') path
++;
4453 return isdirsep(*path
);
4456 VALUE
rb_get_load_path(void);
4459 rb_find_file_ext(VALUE
*filep
, const char *const *ext
)
4461 const char *f
= RSTRING_PTR(*filep
);
4462 VALUE fname
, load_path
, tmp
;
4465 if (!ext
[0]) return 0;
4468 fname
= rb_file_expand_path(*filep
, Qnil
);
4469 if (rb_safe_level() >= 2 && OBJ_TAINTED(fname
)) {
4470 rb_raise(rb_eSecurityError
, "loading from unsafe file %s", f
);
4473 f
= StringValueCStr(fname
);
4477 if (is_absolute_path(f
) || is_explicit_relative(f
)) {
4478 fname
= rb_str_dup(*filep
);
4479 fnlen
= RSTRING_LEN(fname
);
4480 for (i
=0; ext
[i
]; i
++) {
4481 rb_str_cat2(fname
, ext
[i
]);
4482 if (file_load_ok(StringValueCStr(fname
))) {
4483 if (!is_absolute_path(f
)) fname
= rb_file_expand_path(fname
, Qnil
);
4488 rb_str_set_len(fname
, fnlen
);
4493 load_path
= rb_get_load_path();
4494 if (!load_path
) return 0;
4496 fname
= rb_str_dup(*filep
);
4497 RBASIC(fname
)->klass
= 0;
4498 fnlen
= RSTRING_LEN(fname
);
4499 tmp
= rb_str_tmp_new(MAXPATHLEN
+ 2);
4500 for (j
=0; ext
[j
]; j
++) {
4501 rb_str_cat2(fname
, ext
[j
]);
4502 for (i
= 0; i
< RARRAY_LEN(load_path
); i
++) {
4503 VALUE str
= RARRAY_PTR(load_path
)[i
];
4506 if (RSTRING_LEN(str
) == 0) continue;
4507 file_expand_path(fname
, str
, tmp
);
4508 if (file_load_ok(RSTRING_PTR(tmp
))) {
4509 RBASIC(tmp
)->klass
= rb_obj_class(*filep
);
4515 rb_str_set_len(fname
, fnlen
);
4517 RB_GC_GUARD(load_path
);
4522 rb_find_file(VALUE path
)
4524 VALUE tmp
, load_path
;
4525 const char *f
= StringValueCStr(path
);
4528 path
= rb_file_expand_path(path
, Qnil
);
4529 if (rb_safe_level() >= 1 && OBJ_TAINTED(path
)) {
4530 rb_raise(rb_eSecurityError
, "loading from unsafe path %s", f
);
4533 f
= StringValueCStr(path
);
4536 #if defined(__MACOS__) || defined(riscos)
4537 if (is_macos_native_path(f
)) {
4538 if (rb_safe_level() >= 1 && !fpath_check(f
)) {
4539 rb_raise(rb_eSecurityError
, "loading from unsafe file %s", f
);
4541 if (file_load_ok(f
)) return path
;
4546 if (is_absolute_path(f
) || is_explicit_relative(f
)) {
4547 if (rb_safe_level() >= 1 && !fpath_check(f
)) {
4548 rb_raise(rb_eSecurityError
, "loading from unsafe file %s", f
);
4550 if (!file_load_ok(f
)) return 0;
4551 if (!is_absolute_path(f
)) path
= rb_file_expand_path(path
, Qnil
);
4555 if (rb_safe_level() >= 4) {
4556 rb_raise(rb_eSecurityError
, "loading from non-absolute path %s", f
);
4559 load_path
= rb_get_load_path();
4563 tmp
= rb_str_tmp_new(MAXPATHLEN
+ 2);
4564 for (i
= 0; i
< RARRAY_LEN(load_path
); i
++) {
4565 VALUE str
= RARRAY_PTR(load_path
)[i
];
4567 if (RSTRING_LEN(str
) > 0) {
4568 file_expand_path(path
, str
, tmp
);
4569 f
= RSTRING_PTR(tmp
);
4570 if (file_load_ok(f
)) goto found
;
4575 RBASIC(tmp
)->klass
= rb_obj_class(path
);
4579 return 0; /* no path, no load */
4582 if (rb_safe_level() >= 1 && !fpath_check(f
)) {
4583 rb_raise(rb_eSecurityError
, "loading from unsafe file %s", f
);
4590 define_filetest_function(const char *name
, VALUE (*func
)(ANYARGS
), int argc
)
4592 rb_define_module_function(rb_mFileTest
, name
, func
, argc
);
4593 rb_define_singleton_method(rb_cFile
, name
, func
, argc
);
4598 * A <code>File</code> is an abstraction of any file object accessible
4599 * by the program and is closely associated with class <code>IO</code>
4600 * <code>File</code> includes the methods of module
4601 * <code>FileTest</code> as class methods, allowing you to write (for
4602 * example) <code>File.exist?("foo")</code>.
4604 * In the description of File methods,
4605 * <em>permission bits</em> are a platform-specific
4606 * set of bits that indicate permissions of a file. On Unix-based
4607 * systems, permissions are viewed as a set of three octets, for the
4608 * owner, the group, and the rest of the world. For each of these
4609 * entities, permissions may be set to read, write, or execute the
4612 * The permission bits <code>0644</code> (in octal) would thus be
4613 * interpreted as read/write for owner, and read-only for group and
4614 * other. Higher-order bits may also be used to indicate the type of
4615 * file (plain, directory, pipe, socket, and so on) and various other
4616 * special features. If the permissions are for a directory, the
4617 * meaning of the execute bit changes; when set the directory can be
4620 * On non-Posix operating systems, there may be only the ability to
4621 * make a file read-only or read-write. In this case, the remaining
4622 * permission bits will be synthesized to resemble typical values. For
4623 * instance, on Windows NT the default permission bits are
4624 * <code>0644</code>, which means read/write for owner, read-only for
4625 * all others. The only change that can be made is to make the file
4626 * read-only, which is reported as <code>0444</code>.
4632 rb_mFileTest
= rb_define_module("FileTest");
4633 rb_cFile
= rb_define_class("File", rb_cIO
);
4635 define_filetest_function("directory?", rb_file_directory_p
, 1);
4636 define_filetest_function("exist?", rb_file_exist_p
, 1);
4637 define_filetest_function("exists?", rb_file_exist_p
, 1);
4638 define_filetest_function("readable?", rb_file_readable_p
, 1);
4639 define_filetest_function("readable_real?", rb_file_readable_real_p
, 1);
4640 define_filetest_function("world_readable?", rb_file_world_readable_p
, 1);
4641 define_filetest_function("writable?", rb_file_writable_p
, 1);
4642 define_filetest_function("writable_real?", rb_file_writable_real_p
, 1);
4643 define_filetest_function("world_writable?", rb_file_world_writable_p
, 1);
4644 define_filetest_function("executable?", rb_file_executable_p
, 1);
4645 define_filetest_function("executable_real?", rb_file_executable_real_p
, 1);
4646 define_filetest_function("file?", rb_file_file_p
, 1);
4647 define_filetest_function("zero?", rb_file_zero_p
, 1);
4648 define_filetest_function("size?", rb_file_size_p
, 1);
4649 define_filetest_function("size", rb_file_s_size
, 1);
4650 define_filetest_function("owned?", rb_file_owned_p
, 1);
4651 define_filetest_function("grpowned?", rb_file_grpowned_p
, 1);
4653 define_filetest_function("pipe?", rb_file_pipe_p
, 1);
4654 define_filetest_function("symlink?", rb_file_symlink_p
, 1);
4655 define_filetest_function("socket?", rb_file_socket_p
, 1);
4657 define_filetest_function("blockdev?", rb_file_blockdev_p
, 1);
4658 define_filetest_function("chardev?", rb_file_chardev_p
, 1);
4660 define_filetest_function("setuid?", rb_file_suid_p
, 1);
4661 define_filetest_function("setgid?", rb_file_sgid_p
, 1);
4662 define_filetest_function("sticky?", rb_file_sticky_p
, 1);
4664 define_filetest_function("identical?", rb_file_identical_p
, 2);
4666 rb_define_singleton_method(rb_cFile
, "stat", rb_file_s_stat
, 1);
4667 rb_define_singleton_method(rb_cFile
, "lstat", rb_file_s_lstat
, 1);
4668 rb_define_singleton_method(rb_cFile
, "ftype", rb_file_s_ftype
, 1);
4670 rb_define_singleton_method(rb_cFile
, "atime", rb_file_s_atime
, 1);
4671 rb_define_singleton_method(rb_cFile
, "mtime", rb_file_s_mtime
, 1);
4672 rb_define_singleton_method(rb_cFile
, "ctime", rb_file_s_ctime
, 1);
4674 rb_define_singleton_method(rb_cFile
, "utime", rb_file_s_utime
, -1);
4675 rb_define_singleton_method(rb_cFile
, "chmod", rb_file_s_chmod
, -1);
4676 rb_define_singleton_method(rb_cFile
, "chown", rb_file_s_chown
, -1);
4677 rb_define_singleton_method(rb_cFile
, "lchmod", rb_file_s_lchmod
, -1);
4678 rb_define_singleton_method(rb_cFile
, "lchown", rb_file_s_lchown
, -1);
4680 rb_define_singleton_method(rb_cFile
, "link", rb_file_s_link
, 2);
4681 rb_define_singleton_method(rb_cFile
, "symlink", rb_file_s_symlink
, 2);
4682 rb_define_singleton_method(rb_cFile
, "readlink", rb_file_s_readlink
, 1);
4684 rb_define_singleton_method(rb_cFile
, "unlink", rb_file_s_unlink
, -2);
4685 rb_define_singleton_method(rb_cFile
, "delete", rb_file_s_unlink
, -2);
4686 rb_define_singleton_method(rb_cFile
, "rename", rb_file_s_rename
, 2);
4687 rb_define_singleton_method(rb_cFile
, "umask", rb_file_s_umask
, -1);
4688 rb_define_singleton_method(rb_cFile
, "truncate", rb_file_s_truncate
, 2);
4689 rb_define_singleton_method(rb_cFile
, "expand_path", rb_file_s_expand_path
, -1);
4690 rb_define_singleton_method(rb_cFile
, "basename", rb_file_s_basename
, -1);
4691 rb_define_singleton_method(rb_cFile
, "dirname", rb_file_s_dirname
, 1);
4692 rb_define_singleton_method(rb_cFile
, "extname", rb_file_s_extname
, 1);
4693 rb_define_singleton_method(rb_cFile
, "path", rb_file_s_path
, 1);
4695 separator
= rb_obj_freeze(rb_usascii_str_new2("/"));
4696 rb_define_const(rb_cFile
, "Separator", separator
);
4697 rb_define_const(rb_cFile
, "SEPARATOR", separator
);
4698 rb_define_singleton_method(rb_cFile
, "split", rb_file_s_split
, 1);
4699 rb_define_singleton_method(rb_cFile
, "join", rb_file_s_join
, -2);
4702 rb_define_const(rb_cFile
, "ALT_SEPARATOR", rb_obj_freeze(rb_usascii_str_new2("\\")));
4704 rb_define_const(rb_cFile
, "ALT_SEPARATOR", Qnil
);
4706 rb_define_const(rb_cFile
, "PATH_SEPARATOR", rb_obj_freeze(rb_str_new2(PATH_SEP
)));
4708 rb_define_method(rb_cIO
, "stat", rb_io_stat
, 0); /* this is IO's method */
4709 rb_define_method(rb_cFile
, "lstat", rb_file_lstat
, 0);
4711 rb_define_method(rb_cFile
, "atime", rb_file_atime
, 0);
4712 rb_define_method(rb_cFile
, "mtime", rb_file_mtime
, 0);
4713 rb_define_method(rb_cFile
, "ctime", rb_file_ctime
, 0);
4715 rb_define_method(rb_cFile
, "chmod", rb_file_chmod
, 1);
4716 rb_define_method(rb_cFile
, "chown", rb_file_chown
, 2);
4717 rb_define_method(rb_cFile
, "truncate", rb_file_truncate
, 1);
4719 rb_define_method(rb_cFile
, "flock", rb_file_flock
, 1);
4721 rb_mFConst
= rb_define_module_under(rb_cFile
, "Constants");
4722 rb_include_module(rb_cIO
, rb_mFConst
);
4723 rb_file_const("LOCK_SH", INT2FIX(LOCK_SH
));
4724 rb_file_const("LOCK_EX", INT2FIX(LOCK_EX
));
4725 rb_file_const("LOCK_UN", INT2FIX(LOCK_UN
));
4726 rb_file_const("LOCK_NB", INT2FIX(LOCK_NB
));
4728 rb_define_method(rb_cFile
, "path", rb_file_path
, 0);
4729 rb_define_method(rb_cFile
, "to_path", rb_file_path
, 0);
4730 rb_define_global_function("test", rb_f_test
, -1);
4732 rb_cStat
= rb_define_class_under(rb_cFile
, "Stat", rb_cObject
);
4733 rb_define_alloc_func(rb_cStat
, rb_stat_s_alloc
);
4734 rb_define_method(rb_cStat
, "initialize", rb_stat_init
, 1);
4735 rb_define_method(rb_cStat
, "initialize_copy", rb_stat_init_copy
, 1);
4737 rb_include_module(rb_cStat
, rb_mComparable
);
4739 rb_define_method(rb_cStat
, "<=>", rb_stat_cmp
, 1);
4741 rb_define_method(rb_cStat
, "dev", rb_stat_dev
, 0);
4742 rb_define_method(rb_cStat
, "dev_major", rb_stat_dev_major
, 0);
4743 rb_define_method(rb_cStat
, "dev_minor", rb_stat_dev_minor
, 0);
4744 rb_define_method(rb_cStat
, "ino", rb_stat_ino
, 0);
4745 rb_define_method(rb_cStat
, "mode", rb_stat_mode
, 0);
4746 rb_define_method(rb_cStat
, "nlink", rb_stat_nlink
, 0);
4747 rb_define_method(rb_cStat
, "uid", rb_stat_uid
, 0);
4748 rb_define_method(rb_cStat
, "gid", rb_stat_gid
, 0);
4749 rb_define_method(rb_cStat
, "rdev", rb_stat_rdev
, 0);
4750 rb_define_method(rb_cStat
, "rdev_major", rb_stat_rdev_major
, 0);
4751 rb_define_method(rb_cStat
, "rdev_minor", rb_stat_rdev_minor
, 0);
4752 rb_define_method(rb_cStat
, "size", rb_stat_size
, 0);
4753 rb_define_method(rb_cStat
, "blksize", rb_stat_blksize
, 0);
4754 rb_define_method(rb_cStat
, "blocks", rb_stat_blocks
, 0);
4755 rb_define_method(rb_cStat
, "atime", rb_stat_atime
, 0);
4756 rb_define_method(rb_cStat
, "mtime", rb_stat_mtime
, 0);
4757 rb_define_method(rb_cStat
, "ctime", rb_stat_ctime
, 0);
4759 rb_define_method(rb_cStat
, "inspect", rb_stat_inspect
, 0);
4761 rb_define_method(rb_cStat
, "ftype", rb_stat_ftype
, 0);
4763 rb_define_method(rb_cStat
, "directory?", rb_stat_d
, 0);
4764 rb_define_method(rb_cStat
, "readable?", rb_stat_r
, 0);
4765 rb_define_method(rb_cStat
, "readable_real?", rb_stat_R
, 0);
4766 rb_define_method(rb_cStat
, "world_readable?", rb_stat_wr
, 0);
4767 rb_define_method(rb_cStat
, "writable?", rb_stat_w
, 0);
4768 rb_define_method(rb_cStat
, "writable_real?", rb_stat_W
, 0);
4769 rb_define_method(rb_cStat
, "world_writable?", rb_stat_ww
, 0);
4770 rb_define_method(rb_cStat
, "executable?", rb_stat_x
, 0);
4771 rb_define_method(rb_cStat
, "executable_real?", rb_stat_X
, 0);
4772 rb_define_method(rb_cStat
, "file?", rb_stat_f
, 0);
4773 rb_define_method(rb_cStat
, "zero?", rb_stat_z
, 0);
4774 rb_define_method(rb_cStat
, "size?", rb_stat_s
, 0);
4775 rb_define_method(rb_cStat
, "owned?", rb_stat_owned
, 0);
4776 rb_define_method(rb_cStat
, "grpowned?", rb_stat_grpowned
, 0);
4778 rb_define_method(rb_cStat
, "pipe?", rb_stat_p
, 0);
4779 rb_define_method(rb_cStat
, "symlink?", rb_stat_l
, 0);
4780 rb_define_method(rb_cStat
, "socket?", rb_stat_S
, 0);
4782 rb_define_method(rb_cStat
, "blockdev?", rb_stat_b
, 0);
4783 rb_define_method(rb_cStat
, "chardev?", rb_stat_c
, 0);
4785 rb_define_method(rb_cStat
, "setuid?", rb_stat_suid
, 0);
4786 rb_define_method(rb_cStat
, "setgid?", rb_stat_sgid
, 0);
4787 rb_define_method(rb_cStat
, "sticky?", rb_stat_sticky
, 0);