14#include "ruby/internal/config.h"
17# include "missing/file.h"
26# include <sys/cygwin.h>
31# if !(defined(__has_feature) && defined(__has_attribute))
36# define API_AVAILABLE(...)
37# define API_DEPRECATED(...)
39# include <CoreFoundation/CFString.h>
56#ifdef HAVE_SYS_PARAM_H
57# include <sys/param.h>
60# define MAXPATHLEN 1024
65#elif defined HAVE_SYS_UTIME_H
66# include <sys/utime.h>
73#ifdef HAVE_SYS_SYSMACROS_H
74# include <sys/sysmacros.h>
80#ifdef HAVE_SYS_MKDEV_H
81# include <sys/mkdev.h>
84#if defined(HAVE_FCNTL_H)
88#if defined(HAVE_SYS_TIME_H)
92#if !defined HAVE_LSTAT && !defined lstat
98# include "win32/file.h"
99# define STAT(p, s) rb_w32_ustati128((p), (s))
101# define lstat(p, s) rb_w32_ulstati128((p), (s))
103# define access(p, m) rb_w32_uaccess((p), (m))
105# define truncate(p, n) rb_w32_utruncate((p), (n))
107# define chmod(p, m) rb_w32_uchmod((p), (m))
109# define chown(p, o, g) rb_w32_uchown((p), (o), (g))
111# define lchown(p, o, g) rb_w32_ulchown((p), (o), (g))
113# define utimensat(s, p, t, f) rb_w32_uutimensat((s), (p), (t), (f))
115# define link(f, t) rb_w32_ulink((f), (t))
117# define unlink(p) rb_w32_uunlink(p)
119# define rename(f, t) rb_w32_urename((f), (t))
121# define symlink(s, l) rb_w32_usymlink((s), (l))
129# define STAT(p, s) stat((p), (s))
132#if defined _WIN32 || defined __APPLE__
134# define TO_OSPATH(str) rb_str_encode_ospath(str)
137# define TO_OSPATH(str) (str)
141#if defined DOSISH || defined __CYGWIN__
146#if defined HAVE_REALPATH && defined __sun && defined __SVR4
159#include "internal/compilers.h"
160#include "internal/dir.h"
161#include "internal/error.h"
162#include "internal/file.h"
163#include "internal/io.h"
164#include "internal/load.h"
165#include "internal/object.h"
166#include "internal/process.h"
167#include "internal/thread.h"
168#include "internal/vm.h"
179file_path_convert(VALUE name)
184 if (ENCINDEX_US_ASCII != fname_encidx &&
185 ENCINDEX_ASCII != fname_encidx &&
200check_path_encoding(VALUE str)
204 rb_raise(rb_eEncCompatError,
"path name must be ASCII-compatible (%s): %"PRIsVALUE,
211rb_get_path_check_to_string(VALUE obj)
220 tmp = rb_check_funcall_default(obj, to_path, 0, 0, obj);
226rb_get_path_check_convert(VALUE obj)
228 obj = file_path_convert(obj);
230 check_path_encoding(obj);
231 if (!rb_str_to_cstr(obj)) {
232 rb_raise(rb_eArgError,
"path name contains null byte");
247 return rb_get_path_check_convert(rb_get_path_check_to_string(obj));
255#if 0 && defined _WIN32
256 if (encidx == ENCINDEX_ASCII) {
260 if (encidx != ENCINDEX_ASCII && encidx != ENCINDEX_UTF_8) {
270# define NORMALIZE_UTF8PATH 1
272# ifdef HAVE_WORKING_FORK
274rb_CFString_class_initialize_before_fork(
void)
297 const char small_str[] =
"/";
298 long len =
sizeof(small_str) - 1;
300 const CFAllocatorRef alloc = kCFAllocatorDefault;
301 CFStringRef s = CFStringCreateWithBytesNoCopy(alloc,
302 (
const UInt8 *)small_str,
303 len, kCFStringEncodingUTF8,
304 FALSE, kCFAllocatorNull);
305 CFMutableStringRef m = CFStringCreateMutableCopy(alloc, len, s);
312rb_str_append_normalized_ospath(VALUE str,
const char *ptr,
long len)
316 CFStringRef s = CFStringCreateWithBytesNoCopy(kCFAllocatorDefault,
317 (
const UInt8 *)ptr, len,
318 kCFStringEncodingUTF8, FALSE,
320 CFMutableStringRef m = CFStringCreateMutableCopy(kCFAllocatorDefault, len, s);
323 CFStringNormalize(m, kCFStringNormalizationFormC);
324 all = CFRangeMake(0, CFStringGetLength(m));
325 CFStringGetBytes(m, all, kCFStringEncodingUTF8,
'?', FALSE, NULL, 0, &buflen);
327 CFStringGetBytes(m, all, kCFStringEncodingUTF8,
'?', FALSE,
328 (UInt8 *)(
RSTRING_PTR(str) + oldlen), buflen, &buflen);
336rb_str_normalize_ospath(
const char *ptr,
long len)
339 const char *e = ptr + len;
350 static const char invalid[3] =
"\xEF\xBF\xBD";
351 rb_str_append_normalized_ospath(str, p1, p-p1);
359 if ((0x2000 <= c && c <= 0x2FFF) || (0xF900 <= c && c <= 0xFAFF) ||
360 (0x2F800 <= c && c <= 0x2FAFF)) {
362 rb_str_append_normalized_ospath(str, p1, p-p1);
373 rb_str_append_normalized_ospath(str, p1, p-p1);
380ignored_char_p(
const char *p,
const char *e,
rb_encoding *enc)
383 if (p+3 > e)
return 0;
384 switch ((
unsigned char)*p) {
386 switch ((
unsigned char)p[1]) {
388 c = (
unsigned char)p[2];
390 if (c >= 0x8c && c <= 0x8f)
return 3;
392 if (c >= 0xaa && c <= 0xae)
return 3;
395 c = (
unsigned char)p[2];
397 if (c >= 0xaa && c <= 0xaf)
return 3;
403 if ((
unsigned char)p[1] == 0xbb &&
404 (
unsigned char)p[2] == 0xbf)
411# define NORMALIZE_UTF8PATH 0
414#define apply2args(n) (rb_check_arity(argc, n, UNLIMITED_ARGUMENTS), argc-=n)
425 int (*func)(
const char *,
void *);
431no_gvl_apply2files(
void *ptr)
435 for (aa->i = 0; aa->i < aa->argc; aa->i++) {
436 if (aa->func(aa->fn[aa->i].ptr, aa->arg) < 0) {
445NORETURN(
static void utime_failed(
struct apply_arg *));
446static int utime_internal(
const char *,
void *);
450apply2files(
int (*func)(
const char *,
void *),
int argc, VALUE *argv,
void *arg)
454 const long len = (long)(offsetof(
struct apply_arg, fn) + (size * argc));
462 for (aa->i = 0; aa->i < argc; aa->i++) {
467 aa->fn[aa->i].path = path;
473 if (func == utime_internal) {
477 rb_syserr_fail_path(aa->errnum, aa->fn[aa->i].path);
506rb_file_path(VALUE obj)
521stat_memsize(
const void *p)
523 return sizeof(
struct stat);
529 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
533stat_new_0(VALUE klass,
const struct stat *st)
535 struct stat *nst = 0;
557 if (!st)
rb_raise(rb_eTypeError,
"uninitialized File::Stat");
561static struct timespec stat_mtimespec(const struct
stat *st);
579rb_stat_cmp(VALUE
self, VALUE other)
581 if (rb_obj_is_kind_of(other, rb_obj_class(
self))) {
582 struct timespec ts1 = stat_mtimespec(get_stat(
self));
583 struct timespec ts2 = stat_mtimespec(get_stat(other));
584 if (ts1.tv_sec == ts2.tv_sec) {
585 if (ts1.tv_nsec == ts2.tv_nsec)
return INT2FIX(0);
586 if (ts1.tv_nsec < ts2.tv_nsec)
return INT2FIX(-1);
589 if (ts1.tv_sec < ts2.tv_sec)
return INT2FIX(-1);
595#define ST2UINT(val) ((val) & ~(~1UL << (sizeof(val) * CHAR_BIT - 1)))
598# define NUM2DEVT(v) NUM2UINT(v)
601# define DEVT2NUM(v) UINT2NUM(v)
603#ifndef PRI_DEVT_PREFIX
604# define PRI_DEVT_PREFIX ""
618rb_stat_dev(VALUE
self)
620#if SIZEOF_STRUCT_STAT_ST_DEV <= SIZEOF_DEV_T
621 return DEVT2NUM(get_stat(
self)->st_dev);
622#elif SIZEOF_STRUCT_STAT_ST_DEV <= SIZEOF_LONG
623 return ULONG2NUM(get_stat(
self)->st_dev);
625 return ULL2NUM(get_stat(
self)->st_dev);
641rb_stat_dev_major(VALUE
self)
644 return UINT2NUM(major(get_stat(
self)->st_dev));
662rb_stat_dev_minor(VALUE
self)
665 return UINT2NUM(minor(get_stat(
self)->st_dev));
682rb_stat_ino(VALUE
self)
684#ifdef HAVE_STRUCT_STAT_ST_INOHIGH
687 SIZEOF_STRUCT_STAT_ST_INO, 0,
690#elif SIZEOF_STRUCT_STAT_ST_INO > SIZEOF_LONG
691 return ULL2NUM(get_stat(
self)->st_ino);
693 return ULONG2NUM(get_stat(
self)->st_ino);
711rb_stat_mode(VALUE
self)
713 return UINT2NUM(ST2UINT(get_stat(
self)->st_mode));
729rb_stat_nlink(VALUE
self)
732 const struct stat *ptr = get_stat(
self);
734 if (
sizeof(ptr->st_nlink) <=
sizeof(
int)) {
735 return UINT2NUM((
unsigned)ptr->st_nlink);
737 else if (
sizeof(ptr->st_nlink) ==
sizeof(
long)) {
738 return ULONG2NUM((
unsigned long)ptr->st_nlink);
740 else if (
sizeof(ptr->st_nlink) ==
sizeof(
LONG_LONG)) {
744 rb_bug(
":FIXME: don't know what to do");
759rb_stat_uid(VALUE
self)
761 return UIDT2NUM(get_stat(
self)->st_uid);
775rb_stat_gid(VALUE
self)
777 return GIDT2NUM(get_stat(
self)->st_gid);
793rb_stat_rdev(VALUE
self)
795#ifdef HAVE_STRUCT_STAT_ST_RDEV
796# if SIZEOF_STRUCT_STAT_ST_RDEV <= SIZEOF_DEV_T
797 return DEVT2NUM(get_stat(
self)->st_rdev);
798# elif SIZEOF_STRUCT_STAT_ST_RDEV <= SIZEOF_LONG
799 return ULONG2NUM(get_stat(
self)->st_rdev);
801 return ULL2NUM(get_stat(
self)->st_rdev);
820rb_stat_rdev_major(VALUE
self)
822#if defined(HAVE_STRUCT_STAT_ST_RDEV) && defined(major)
823 return UINT2NUM(major(get_stat(
self)->st_rdev));
841rb_stat_rdev_minor(VALUE
self)
843#if defined(HAVE_STRUCT_STAT_ST_RDEV) && defined(minor)
844 return UINT2NUM(minor(get_stat(
self)->st_rdev));
860rb_stat_size(VALUE
self)
862 return OFFT2NUM(get_stat(
self)->st_size);
877rb_stat_blksize(VALUE
self)
879#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
880 return ULONG2NUM(get_stat(
self)->st_blksize);
898rb_stat_blocks(VALUE
self)
900#ifdef HAVE_STRUCT_STAT_ST_BLOCKS
901# if SIZEOF_STRUCT_STAT_ST_BLOCKS > SIZEOF_LONG
902 return ULL2NUM(get_stat(
self)->st_blocks);
904 return ULONG2NUM(get_stat(
self)->st_blocks);
912stat_atimespec(const struct
stat *st)
915 ts.tv_sec = st->st_atime;
916#if defined(HAVE_STRUCT_STAT_ST_ATIM)
917 ts.tv_nsec = st->st_atim.tv_nsec;
918#elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC)
919 ts.tv_nsec = st->st_atimespec.tv_nsec;
920#elif defined(HAVE_STRUCT_STAT_ST_ATIMENSEC)
921 ts.tv_nsec = (long)st->st_atimensec;
935stat_atime(
const struct stat *st)
937 return stat_time(stat_atimespec(st));
941stat_mtimespec(const struct
stat *st)
944 ts.tv_sec = st->st_mtime;
945#if defined(HAVE_STRUCT_STAT_ST_MTIM)
946 ts.tv_nsec = st->st_mtim.tv_nsec;
947#elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC)
948 ts.tv_nsec = st->st_mtimespec.tv_nsec;
949#elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC)
950 ts.tv_nsec = (long)st->st_mtimensec;
958stat_mtime(
const struct stat *st)
960 return stat_time(stat_mtimespec(st));
964stat_ctimespec(const struct
stat *st)
967 ts.tv_sec = st->st_ctime;
968#if defined(HAVE_STRUCT_STAT_ST_CTIM)
969 ts.tv_nsec = st->st_ctim.tv_nsec;
970#elif defined(HAVE_STRUCT_STAT_ST_CTIMESPEC)
971 ts.tv_nsec = st->st_ctimespec.tv_nsec;
972#elif defined(HAVE_STRUCT_STAT_ST_CTIMENSEC)
973 ts.tv_nsec = (long)st->st_ctimensec;
981stat_ctime(
const struct stat *st)
983 return stat_time(stat_ctimespec(st));
986#define HAVE_STAT_BIRTHTIME
987#if defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC)
988typedef struct stat statx_data;
990stat_birthtime(
const struct stat *st)
992 const struct timespec *ts = &st->st_birthtimespec;
996typedef struct stat statx_data;
997# define stat_birthtime stat_ctime
999# undef HAVE_STAT_BIRTHTIME
1014rb_stat_atime(VALUE
self)
1016 return stat_atime(get_stat(
self));
1030rb_stat_mtime(VALUE
self)
1032 return stat_mtime(get_stat(
self));
1050rb_stat_ctime(VALUE
self)
1052 return stat_ctime(get_stat(
self));
1055#if defined(HAVE_STAT_BIRTHTIME)
1079rb_stat_birthtime(VALUE
self)
1081 return stat_birthtime(get_stat(
self));
1084# define rb_stat_birthtime rb_f_notimplement
1103rb_stat_inspect(VALUE
self)
1107 static const struct {
1111 {
"dev", rb_stat_dev},
1112 {
"ino", rb_stat_ino},
1113 {
"mode", rb_stat_mode},
1114 {
"nlink", rb_stat_nlink},
1115 {
"uid", rb_stat_uid},
1116 {
"gid", rb_stat_gid},
1117 {
"rdev", rb_stat_rdev},
1118 {
"size", rb_stat_size},
1119 {
"blksize", rb_stat_blksize},
1120 {
"blocks", rb_stat_blocks},
1121 {
"atime", rb_stat_atime},
1122 {
"mtime", rb_stat_mtime},
1123 {
"ctime", rb_stat_ctime},
1124#if defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC)
1125 {
"birthtime", rb_stat_birthtime},
1139 for (i = 0; i <
sizeof(member)/
sizeof(member[0]); i++) {
1147 v = (*member[i].func)(
self);
1151 else if (i == 0 || i == 6) {
1152 rb_str_catf(str,
"0x%"PRI_DEVT_PREFIX
"x", NUM2DEVT(v));
1172no_gvl_fstat(
void *data)
1175 return (VALUE)fstat(arg->file.fd, arg->st);
1179fstat_without_gvl(
int fd,
struct stat *st)
1186 return (
int)(
VALUE)rb_thread_io_blocking_region(no_gvl_fstat, &data, fd);
1190no_gvl_stat(
void * data)
1193 return (
void *)(
VALUE)STAT(arg->file.path, arg->st);
1197stat_without_gvl(
const char *path,
struct stat *st)
1201 data.file.path = path;
1208#if !defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC) && \
1209 defined(HAVE_STRUCT_STATX_STX_BTIME)
1212# ifdef HAVE_SYSCALL_H
1213# include <syscall.h>
1214# elif defined HAVE_SYS_SYSCALL_H
1215# include <sys/syscall.h>
1217# if defined __linux__
1218# include <linux/stat.h>
1220statx(
int dirfd,
const char *pathname,
int flags,
1221 unsigned int mask,
struct statx *statxbuf)
1223 return (
int)syscall(__NR_statx, dirfd, pathname, flags, mask, statxbuf);
1228typedef struct no_gvl_statx_data {
1237io_blocking_statx(
void *data)
1239 no_gvl_statx_data *arg = data;
1240 return (VALUE)statx(arg->fd, arg->path, arg->flags, arg->mask, arg->stx);
1244no_gvl_statx(
void *data)
1246 return (
void *)io_blocking_statx(data);
1250statx_without_gvl(
const char *path,
struct statx *stx,
unsigned int mask)
1252 no_gvl_statx_data data = {stx, AT_FDCWD, path, 0, mask};
1260fstatx_without_gvl(
int fd,
struct statx *stx,
unsigned int mask)
1262 no_gvl_statx_data data = {stx, fd,
"", AT_EMPTY_PATH, mask};
1265 return (
int)rb_thread_io_blocking_region(io_blocking_statx, &data, fd);
1269rb_statx(VALUE file,
struct statx *stx,
unsigned int mask)
1274 tmp = rb_check_convert_type_with_id(file,
T_FILE,
"IO", idTo_io);
1278 result = fstatx_without_gvl(fptr->
fd, stx, mask);
1284 result = statx_without_gvl(
RSTRING_PTR(file), stx, mask);
1290# define statx_has_birthtime(st) ((st)->stx_mask & STATX_BTIME)
1292NORETURN(
static void statx_notimplement(
const char *field_name));
1297statx_notimplement(
const char *field_name)
1300 "%s is unimplemented on this filesystem",
1305statx_birthtime(
const struct statx *stx, VALUE fname)
1307 if (!statx_has_birthtime(stx)) {
1309 statx_notimplement(
"birthtime");
1311 return rb_time_nano_new((time_t)stx->stx_btime.tv_sec, stx->stx_btime.tv_nsec);
1314typedef struct statx statx_data;
1315# define HAVE_STAT_BIRTHTIME
1317#elif defined(HAVE_STAT_BIRTHTIME)
1318# define statx_without_gvl(path, st, mask) stat_without_gvl(path, st)
1319# define fstatx_without_gvl(fd, st, mask) fstat_without_gvl(fd, st)
1320# define statx_birthtime(st, fname) stat_birthtime(st)
1321# define statx_has_birthtime(st) 1
1322# define rb_statx(file, st, mask) rb_stat(file, st)
1324# define statx_has_birthtime(st) 0
1328rb_stat(VALUE file,
struct stat *st)
1333 tmp = rb_check_convert_type_with_id(file,
T_FILE,
"IO", idTo_io);
1338 result = fstat_without_gvl(fptr->
fd, st);
1361rb_file_s_stat(VALUE klass, VALUE fname)
1367 if (stat_without_gvl(
RSTRING_PTR(fname), &st) < 0) {
1368 rb_sys_fail_path(fname);
1389rb_io_stat(VALUE obj)
1395 if (fstat(fptr->
fd, &st) == -1) {
1396 rb_sys_fail_path(fptr->
pathv);
1403no_gvl_lstat(
void *ptr)
1406 return (
void *)(
VALUE)lstat(arg->file.path, arg->st);
1410lstat_without_gvl(
const char *path,
struct stat *st)
1414 data.file.path = path;
1437rb_file_s_lstat(VALUE klass, VALUE fname)
1445 rb_sys_fail_path(fname);
1449 return rb_file_s_stat(klass, fname);
1468rb_file_lstat(VALUE obj)
1478 if (lstat_without_gvl(
RSTRING_PTR(path), &st) == -1) {
1479 rb_sys_fail_path(fptr->
pathv);
1483 return rb_io_stat(obj);
1488rb_group_member(GETGROUPS_T gid)
1490#if defined(_WIN32) || !defined(HAVE_GETGROUPS)
1499 if (getgid() == gid || getegid() == gid)
1502 groups = getgroups(0, NULL);
1503 gary =
ALLOCV_N(GETGROUPS_T, v, groups);
1504 anum = getgroups(groups, gary);
1505 while (--anum >= 0) {
1506 if (gary[anum] == gid) {
1519# define S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH)
1522#if defined(S_IXGRP) && !defined(_WIN32) && !defined(__CYGWIN__)
1523#define USE_GETEUID 1
1528eaccess(
const char *path,
int mode)
1537 if (getuid() == euid && getgid() == getegid())
1538 return access(path, mode);
1540 if (STAT(path, &st) < 0)
1550 if (st.st_mode & S_IXUGO)
1556 if (st.st_uid == euid)
1558 else if (rb_group_member(st.st_gid))
1561 if ((
int)(st.st_mode & mode) == mode)
return 0;
1565 return access(path, mode);
1576nogvl_eaccess(
void *ptr)
1580 return (
void *)(
VALUE)eaccess(aa->path, aa->mode);
1584rb_eaccess(VALUE fname,
int mode)
1598nogvl_access(
void *ptr)
1602 return (
void *)(
VALUE)access(aa->path, aa->mode);
1606rb_access(VALUE fname,
int mode)
1648# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
1653 if (rb_stat(fname, &st) < 0)
return Qfalse;
1654 if (S_ISDIR(st.st_mode))
return Qtrue;
1668rb_file_pipe_p(VALUE obj, VALUE fname)
1672# define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
1677 if (rb_stat(fname, &st) < 0)
return Qfalse;
1678 if (S_ISFIFO(st.st_mode))
return Qtrue;
1692rb_file_symlink_p(VALUE obj, VALUE fname)
1696# define S_ISLNK(m) _S_ISLNK(m)
1699# define S_ISLNK(m) (((m) & S_IFMT) == _S_IFLNK)
1702# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
1714 if (S_ISLNK(st.st_mode))
return Qtrue;
1730rb_file_socket_p(VALUE obj, VALUE fname)
1734# define S_ISSOCK(m) _S_ISSOCK(m)
1737# define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
1740# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
1749 if (rb_stat(fname, &st) < 0)
return Qfalse;
1750 if (S_ISSOCK(st.st_mode))
return Qtrue;
1766rb_file_blockdev_p(VALUE obj, VALUE fname)
1770# define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
1772# define S_ISBLK(m) (0)
1779 if (rb_stat(fname, &st) < 0)
return Qfalse;
1780 if (S_ISBLK(st.st_mode))
return Qtrue;
1795rb_file_chardev_p(VALUE obj, VALUE fname)
1798# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
1803 if (rb_stat(fname, &st) < 0)
return Qfalse;
1804 if (S_ISCHR(st.st_mode))
return Qtrue;
1821rb_file_exist_p(VALUE obj, VALUE fname)
1825 if (rb_stat(fname, &st) < 0)
return Qfalse;
1831rb_file_exists_p(VALUE obj, VALUE fname)
1833 const char *s =
"FileTest#exist?";
1835 s =
"FileTest.exist?";
1842 rb_warn_deprecated(
"%.*ss?", s, (
int)(strlen(s)-1), s);
1843 return rb_file_exist_p(obj, fname);
1858rb_file_readable_p(VALUE obj, VALUE fname)
1860 return RBOOL(rb_eaccess(fname, R_OK) >= 0);
1875rb_file_readable_real_p(VALUE obj, VALUE fname)
1877 return RBOOL(rb_access(fname, R_OK) >= 0);
1881# define S_IRUGO (S_IRUSR | S_IRGRP | S_IROTH)
1885# define S_IWUGO (S_IWUSR | S_IWGRP | S_IWOTH)
1905rb_file_world_readable_p(VALUE obj, VALUE fname)
1910 if (rb_stat(fname, &st) < 0)
return Qnil;
1911 if ((st.st_mode & (S_IROTH)) == S_IROTH) {
1912 return UINT2NUM(st.st_mode & (S_IRUGO|S_IWUGO|S_IXUGO));
1930rb_file_writable_p(VALUE obj, VALUE fname)
1932 return RBOOL(rb_eaccess(fname, W_OK) >= 0);
1947rb_file_writable_real_p(VALUE obj, VALUE fname)
1949 return RBOOL(rb_access(fname, W_OK) >= 0);
1969rb_file_world_writable_p(VALUE obj, VALUE fname)
1974 if (rb_stat(fname, &st) < 0)
return Qnil;
1975 if ((st.st_mode & (S_IWOTH)) == S_IWOTH) {
1976 return UINT2NUM(st.st_mode & (S_IRUGO|S_IWUGO|S_IXUGO));
1998rb_file_executable_p(VALUE obj, VALUE fname)
2000 return RBOOL(rb_eaccess(fname, X_OK) >= 0);
2019rb_file_executable_real_p(VALUE obj, VALUE fname)
2021 return RBOOL(rb_access(fname, X_OK) >= 0);
2025# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
2041rb_file_file_p(VALUE obj, VALUE fname)
2045 if (rb_stat(fname, &st) < 0)
return Qfalse;
2046 return RBOOL(S_ISREG(st.st_mode));
2060rb_file_zero_p(VALUE obj, VALUE fname)
2064 if (rb_stat(fname, &st) < 0)
return Qfalse;
2065 return RBOOL(st.st_size == 0);
2079rb_file_size_p(VALUE obj, VALUE fname)
2083 if (rb_stat(fname, &st) < 0)
return Qnil;
2084 if (st.st_size == 0)
return Qnil;
2100rb_file_owned_p(VALUE obj, VALUE fname)
2104 if (rb_stat(fname, &st) < 0)
return Qfalse;
2105 return RBOOL(st.st_uid == geteuid());
2109rb_file_rowned_p(VALUE obj, VALUE fname)
2113 if (rb_stat(fname, &st) < 0)
return Qfalse;
2114 return RBOOL(st.st_uid == getuid());
2129rb_file_grpowned_p(VALUE obj, VALUE fname)
2134 if (rb_stat(fname, &st) < 0)
return Qfalse;
2135 if (rb_group_member(st.st_gid))
return Qtrue;
2140#if defined(S_ISUID) || defined(S_ISGID) || defined(S_ISVTX)
2142check3rdbyte(VALUE fname,
int mode)
2146 if (rb_stat(fname, &st) < 0)
return Qfalse;
2147 return RBOOL(st.st_mode & mode);
2161rb_file_suid_p(VALUE obj, VALUE fname)
2164 return check3rdbyte(fname, S_ISUID);
2180rb_file_sgid_p(VALUE obj, VALUE fname)
2183 return check3rdbyte(fname, S_ISGID);
2199rb_file_sticky_p(VALUE obj, VALUE fname)
2202 return check3rdbyte(fname, S_ISVTX);
2228rb_file_identical_p(VALUE obj, VALUE fname1, VALUE fname2)
2231 struct stat st1, st2;
2233 if (rb_stat(fname1, &st1) < 0)
return Qfalse;
2234 if (rb_stat(fname2, &st2) < 0)
return Qfalse;
2235 if (st1.st_dev != st2.st_dev)
return Qfalse;
2236 if (st1.st_ino != st2.st_ino)
return Qfalse;
2239 extern VALUE rb_w32_file_identical_p(VALUE, VALUE);
2240 return rb_w32_file_identical_p(fname1, fname2);
2254rb_file_s_size(VALUE klass, VALUE fname)
2258 if (rb_stat(fname, &st) < 0) {
2261 rb_syserr_fail_path(e, fname);
2267rb_file_ftype(
const struct stat *st)
2271 if (S_ISREG(st->st_mode)) {
2274 else if (S_ISDIR(st->st_mode)) {
2277 else if (S_ISCHR(st->st_mode)) {
2278 t =
"characterSpecial";
2281 else if (S_ISBLK(st->st_mode)) {
2286 else if (S_ISFIFO(st->st_mode)) {
2291 else if (S_ISLNK(st->st_mode)) {
2296 else if (S_ISSOCK(st->st_mode)) {
2323rb_file_s_ftype(VALUE klass, VALUE fname)
2330 rb_sys_fail_path(fname);
2333 return rb_file_ftype(&st);
2349rb_file_s_atime(VALUE klass, VALUE fname)
2353 if (rb_stat(fname, &st) < 0) {
2356 rb_syserr_fail_path(e, fname);
2358 return stat_atime(&st);
2373rb_file_atime(VALUE obj)
2379 if (fstat(fptr->
fd, &st) == -1) {
2380 rb_sys_fail_path(fptr->
pathv);
2382 return stat_atime(&st);
2398rb_file_s_mtime(VALUE klass, VALUE fname)
2402 if (rb_stat(fname, &st) < 0) {
2405 rb_syserr_fail_path(e, fname);
2407 return stat_mtime(&st);
2421rb_file_mtime(VALUE obj)
2427 if (fstat(fptr->
fd, &st) == -1) {
2428 rb_sys_fail_path(fptr->
pathv);
2430 return stat_mtime(&st);
2450rb_file_s_ctime(VALUE klass, VALUE fname)
2454 if (rb_stat(fname, &st) < 0) {
2457 rb_syserr_fail_path(e, fname);
2459 return stat_ctime(&st);
2476rb_file_ctime(VALUE obj)
2482 if (fstat(fptr->
fd, &st) == -1) {
2483 rb_sys_fail_path(fptr->
pathv);
2485 return stat_ctime(&st);
2502#if defined(HAVE_STAT_BIRTHTIME)
2503RUBY_FUNC_EXPORTED VALUE
2504rb_file_s_birthtime(VALUE klass, VALUE fname)
2508 if (rb_statx(fname, &st, STATX_BTIME) < 0) {
2511 rb_syserr_fail_path(e, fname);
2513 return statx_birthtime(&st, fname);
2516# define rb_file_s_birthtime rb_f_notimplement
2519#if defined(HAVE_STAT_BIRTHTIME)
2533rb_file_birthtime(VALUE obj)
2539 if (fstatx_without_gvl(fptr->
fd, &st, STATX_BTIME) == -1) {
2540 rb_sys_fail_path(fptr->
pathv);
2542 return statx_birthtime(&st, fptr->
pathv);
2545# define rb_file_birthtime rb_f_notimplement
2567 rb_io_flush_raw(file, 0);
2570 if (fstat(fptr->
fd, &st) == -1) {
2571 rb_sys_fail_path(fptr->
pathv);
2582file_size(VALUE
self)
2588chmod_internal(
const char *path,
void *mode)
2590 return chmod(path, *(mode_t *)mode);
2607rb_file_s_chmod(
int argc, VALUE *argv, VALUE
_)
2614 return apply2files(chmod_internal, argc, argv, &mode);
2631rb_file_chmod(VALUE obj, VALUE vmode)
2635#if !defined HAVE_FCHMOD || !HAVE_FCHMOD
2643 if (fchmod(fptr->
fd, mode) == -1) {
2644 if (HAVE_FCHMOD || errno != ENOSYS)
2645 rb_sys_fail_path(fptr->
pathv);
2648 if (!HAVE_FCHMOD)
return INT2FIX(0);
2651#if !defined HAVE_FCHMOD || !HAVE_FCHMOD
2655 rb_sys_fail_path(fptr->
pathv);
2661#if defined(HAVE_LCHMOD)
2663lchmod_internal(
const char *path,
void *mode)
2665 return lchmod(path, *(mode_t *)mode);
2679rb_file_s_lchmod(
int argc, VALUE *argv, VALUE
_)
2686 return apply2files(lchmod_internal, argc, argv, &mode);
2689#define rb_file_s_lchmod rb_f_notimplement
2692static inline rb_uid_t
2696 return (rb_uid_t)-1;
2701static inline rb_gid_t
2705 return (rb_gid_t)-1;
2716chown_internal(
const char *path,
void *arg)
2719 return chown(path, args->owner, args->group);
2738rb_file_s_chown(
int argc, VALUE *argv, VALUE
_)
2743 arg.owner = to_uid(*argv++);
2744 arg.group = to_gid(*argv++);
2746 return apply2files(chown_internal, argc, argv, &arg);
2765rb_file_chown(VALUE obj, VALUE owner, VALUE group)
2781 rb_sys_fail_path(fptr->
pathv);
2783 if (fchown(fptr->
fd, o, g) == -1)
2784 rb_sys_fail_path(fptr->
pathv);
2790#if defined(HAVE_LCHOWN)
2792lchown_internal(
const char *path,
void *arg)
2795 return lchown(path, args->owner, args->group);
2810rb_file_s_lchown(
int argc, VALUE *argv, VALUE
_)
2815 arg.owner = to_uid(*argv++);
2816 arg.group = to_gid(*argv++);
2818 return apply2files(lchown_internal, argc, argv, &arg);
2821#define rb_file_s_lchown rb_f_notimplement
2831NORETURN(
static void utime_failed(
struct apply_arg *));
2837 VALUE path = aa->fn[aa->i].path;
2840 if (ua->tsp && e == EINVAL) {
2843 VALUE atime = ua->atime;
2844 VALUE mtime = ua->mtime;
2846 if (!
NIL_P(atime)) {
2847 a = rb_inspect(atime);
2849 if (!
NIL_P(mtime) && mtime != atime && !rb_equal(atime, mtime)) {
2850 m = rb_inspect(mtime);
2852 if (
NIL_P(a)) e[0] = m;
2865 rb_exc_raise(rb_class_new_instance(2, e, rb_eSystemCallError));
2868 rb_syserr_fail_path(e, path);
2872#if defined(HAVE_UTIMES)
2875utime_internal(
const char *path,
void *arg)
2878 const struct timespec *tsp = v->tsp;
2879 struct timeval tvbuf[2], *tvp = NULL;
2881#if defined(HAVE_UTIMENSAT)
2882 static int try_utimensat = 1;
2883# ifdef AT_SYMLINK_NOFOLLOW
2884 static int try_utimensat_follow = 1;
2886 const int try_utimensat_follow = 0;
2890 if (v->follow ? try_utimensat_follow : try_utimensat) {
2891# ifdef AT_SYMLINK_NOFOLLOW
2893 flags = AT_SYMLINK_NOFOLLOW;
2897 if (utimensat(AT_FDCWD, path, tsp, flags) < 0) {
2898 if (errno == ENOSYS) {
2899# ifdef AT_SYMLINK_NOFOLLOW
2900 try_utimensat_follow = 0;
2914 tvbuf[0].tv_sec = tsp[0].tv_sec;
2915 tvbuf[0].tv_usec = (int)(tsp[0].tv_nsec / 1000);
2916 tvbuf[1].tv_sec = tsp[1].tv_sec;
2917 tvbuf[1].tv_usec = (int)(tsp[1].tv_nsec / 1000);
2921 if (v->follow)
return lutimes(path, tvp);
2923 return utimes(path, tvp);
2928#if !defined HAVE_UTIME_H && !defined HAVE_SYS_UTIME_H
2936utime_internal(
const char *path,
void *arg)
2939 const struct timespec *tsp = v->tsp;
2940 struct utimbuf utbuf, *utp = NULL;
2942 utbuf.actime = tsp[0].tv_sec;
2943 utbuf.modtime = tsp[1].tv_sec;
2946 return utime(path, utp);
2952utime_internal_i(
int argc, VALUE *argv,
int follow)
2955 struct timespec tss[2], *tsp = NULL;
2958 args.atime = *argv++;
2959 args.mtime = *argv++;
2961 args.follow = follow;
2963 if (!
NIL_P(args.atime) || !
NIL_P(args.mtime)) {
2966 if (args.atime == args.mtime)
2973 return apply2files(utime_internal, argc, argv, &args);
2988rb_file_s_utime(
int argc, VALUE *argv, VALUE
_)
2990 return utime_internal_i(argc, argv, FALSE);
2993#if defined(HAVE_UTIMES) && (defined(HAVE_LUTIMES) || (defined(HAVE_UTIMENSAT) && defined(AT_SYMLINK_NOFOLLOW)))
3007rb_file_s_lutime(
int argc, VALUE *argv, VALUE
_)
3009 return utime_internal_i(argc, argv, TRUE);
3012#define rb_file_s_lutime rb_f_notimplement
3015#ifdef RUBY_FUNCTION_NAME_STRING
3016# define syserr_fail2(e, s1, s2) syserr_fail2_in(RUBY_FUNCTION_NAME_STRING, e, s1, s2)
3018# define syserr_fail2_in(func, e, s1, s2) syserr_fail2(e, s1, s2)
3020#define sys_fail2(s1, s2) syserr_fail2(errno, s1, s2)
3021NORETURN(
static void syserr_fail2_in(
const char *,
int,VALUE,VALUE));
3023syserr_fail2_in(
const char *func,
int e, VALUE s1, VALUE s2)
3027 const int max_pathlen = MAX_PATH;
3029 const int max_pathlen = MAXPATHLEN;
3040#ifdef RUBY_FUNCTION_NAME_STRING
3041 rb_syserr_fail_path_in(func, e, str);
3043 rb_syserr_fail_path(e, str);
3061rb_file_s_link(VALUE klass, VALUE from, VALUE to)
3069 sys_fail2(from, to);
3074#define rb_file_s_link rb_f_notimplement
3091rb_file_s_symlink(VALUE klass, VALUE from, VALUE to)
3099 sys_fail2(from, to);
3104#define rb_file_s_symlink rb_f_notimplement
3120rb_file_s_readlink(VALUE klass, VALUE path)
3126struct readlink_arg {
3133nogvl_readlink(
void *ptr)
3135 struct readlink_arg *ra = ptr;
3137 return (
void *)(
VALUE)readlink(ra->path, ra->buf, ra->size);
3141readlink_without_gvl(VALUE path, VALUE buf,
size_t size)
3143 struct readlink_arg ra;
3163 while ((rv = readlink_without_gvl(path, v, size)) == size
3165 || (rv < 0 && errno == ERANGE)
3175 rb_syserr_fail_path(e, path);
3183#define rb_file_s_readlink rb_f_notimplement
3187unlink_internal(
const char *path,
void *arg)
3189 return unlink(path);
3209rb_file_s_unlink(
int argc, VALUE *argv, VALUE klass)
3211 return apply2files(unlink_internal, argc, argv, 0);
3220no_gvl_rename(
void *ptr)
3224 return (
void *)(
VALUE)rename(ra->src, ra->dst);
3238rb_file_s_rename(VALUE klass, VALUE from, VALUE to)
3249#if defined __CYGWIN__
3258 if (chmod(ra.dst, 0666) == 0 &&
3259 unlink(ra.dst) == 0 &&
3260 rename(ra.src, ra.dst) == 0)
3264 syserr_fail2(e, from, to);
3286rb_file_s_umask(
int argc, VALUE *argv, VALUE
_)
3299 rb_error_arity(argc, 0, 1);
3307#if defined __CYGWIN__ || defined DOSISH
3309#define DOSISH_DRIVE_LETTER
3310#define FILE_ALT_SEPARATOR '\\'
3312#ifdef FILE_ALT_SEPARATOR
3313#define isdirsep(x) ((x) == '/' || (x) == FILE_ALT_SEPARATOR)
3315static const char file_alt_separator[] = {FILE_ALT_SEPARATOR,
'\0'};
3318#define isdirsep(x) ((x) == '/')
3330# define USE_NTFS_ADS 1
3332# define USE_NTFS_ADS 0
3337#define istrailinggarbage(x) ((x) == '.' || (x) == ' ')
3339#define istrailinggarbage(x) 0
3342# define isADS(x) ((x) == ':')
3347#define Next(p, e, enc) ((p) + rb_enc_mbclen((p), (e), (enc)))
3348#define Inc(p, e, enc) ((p) = Next((p), (e), (enc)))
3350#if defined(DOSISH_UNC)
3351#define has_unc(buf) (isdirsep((buf)[0]) && isdirsep((buf)[1]))
3353#define has_unc(buf) 0
3356#ifdef DOSISH_DRIVE_LETTER
3358has_drive_letter(
const char *buf)
3360 if (
ISALPHA(buf[0]) && buf[1] ==
':') {
3373 char *drvcwd, *oldcwd;
3384 if (chdir(drive) == 0) {
3397not_same_drive(VALUE path,
int drive)
3401 if (has_drive_letter(p)) {
3412skiproot(
const char *path,
const char *end,
rb_encoding *enc)
3414#ifdef DOSISH_DRIVE_LETTER
3415 if (path + 2 <= end && has_drive_letter(path)) path += 2;
3417 while (path < end && isdirsep(*path)) path++;
3418 return (
char *)path;
3421#define nextdirsep rb_enc_path_next
3425 while (s < e && !isdirsep(*s)) {
3431#if defined(DOSISH_UNC) || defined(DOSISH_DRIVE_LETTER)
3432#define skipprefix rb_enc_path_skip_prefix
3434#define skipprefix(path, end, enc) (path)
3439#if defined(DOSISH_UNC) || defined(DOSISH_DRIVE_LETTER)
3441 if (path + 2 <= end && isdirsep(path[0]) && isdirsep(path[1])) {
3443 while (path < end && isdirsep(*path)) path++;
3444 if ((path =
rb_enc_path_next(path, end, enc)) < end && path[0] && path[1] && !isdirsep(path[1]))
3446 return (
char *)path;
3449#ifdef DOSISH_DRIVE_LETTER
3450 if (has_drive_letter(path))
3451 return (
char *)(path + 2);
3454 return (
char *)path;
3458skipprefixroot(
const char *path,
const char *end,
rb_encoding *enc)
3460#if defined(DOSISH_UNC) || defined(DOSISH_DRIVE_LETTER)
3461 char *p = skipprefix(path, end, enc);
3462 while (isdirsep(*p)) p++;
3465 return skiproot(path, end, enc);
3469#define strrdirsep rb_enc_path_last_separator
3474 while (path < end) {
3475 if (isdirsep(*path)) {
3476 const char *tmp = path++;
3477 while (path < end && isdirsep(*path)) path++;
3478 if (path >= end)
break;
3482 Inc(path, end, enc);
3489chompdirsep(
const char *path,
const char *end,
rb_encoding *enc)
3491 while (path < end) {
3492 if (isdirsep(*path)) {
3493 const char *last = path++;
3494 while (path < end && isdirsep(*path)) path++;
3495 if (path >= end)
return (
char *)last;
3498 Inc(path, end, enc);
3501 return (
char *)path;
3507 if (path < end && isdirsep(*path)) path++;
3508 return chompdirsep(path, end, enc);
3512fs_enc_check(VALUE path1, VALUE path2)
3516 if (encidx == ENCINDEX_US_ASCII) {
3518 if (encidx == ENCINDEX_US_ASCII)
3527ntfs_tail(
const char *path,
const char *end,
rb_encoding *enc)
3529 while (path < end && *path ==
'.') path++;
3530 while (path < end && !isADS(*path)) {
3531 if (istrailinggarbage(*path)) {
3532 const char *last = path++;
3533 while (path < end && istrailinggarbage(*path)) path++;
3534 if (path >= end || isADS(*path))
return (
char *)last;
3536 else if (isdirsep(*path)) {
3537 const char *last = path++;
3538 while (path < end && isdirsep(*path)) path++;
3539 if (path >= end)
return (
char *)last;
3540 if (isADS(*path)) path++;
3543 Inc(path, end, enc);
3546 return (
char *)path;
3550#define BUFCHECK(cond) do {\
3553 do {buflen *= 2;} while (cond);\
3554 rb_str_resize(result, buflen);\
3555 buf = RSTRING_PTR(result);\
3557 pend = buf + buflen;\
3562 p = buf = RSTRING_PTR(result),\
3563 buflen = RSTRING_LEN(result),\
3567# define SKIPPATHSEP(p) ((*(p)) ? 1 : 0)
3569# define SKIPPATHSEP(p) 1
3572#define BUFCOPY(srcptr, srclen) do { \
3573 const int skip = SKIPPATHSEP(p); \
3574 rb_str_set_len(result, p-buf+skip); \
3575 BUFCHECK(bdiff + ((srclen)+skip) >= buflen); \
3577 memcpy(p, (srcptr), (srclen)); \
3581#define WITH_ROOTDIFF(stmt) do { \
3582 long rootdiff = root - buf; \
3584 root = buf + rootdiff; \
3588copy_home_path(VALUE result,
const char *dir)
3591#if defined DOSISH || defined __CYGWIN__
3598 dirlen = strlen(dir);
3603#if defined DOSISH || defined __CYGWIN__
3605 for (bend = (p = buf) + dirlen; p < bend; Inc(p, bend, enc)) {
3615rb_home_dir_of(VALUE user, VALUE result)
3618 struct passwd *pwPtr;
3620 extern char *getlogin(
void);
3621 const char *pwPtr = 0;
3622 # define endpwent() ((void)0)
3636 pwPtr = getpwnam(username);
3638 if (strcasecmp(username, getlogin()) == 0)
3639 dir = pwPtr = getenv(
"HOME");
3643 rb_raise(rb_eArgError,
"user %"PRIsVALUE
" doesn't exist", user);
3646 dir = pwPtr->pw_dir;
3648 copy_home_path(result, dir);
3655rb_default_home_dir(VALUE result)
3657 const char *dir = getenv(
"HOME");
3659#if defined HAVE_PWD_H
3673 VALUE login_name = rb_getlogin();
3675# if !defined(HAVE_GETPWUID_R) && !defined(HAVE_GETPWUID)
3680 if (
NIL_P(login_name)) {
3681 rb_raise(rb_eArgError,
"couldn't find login name -- expanding `~'");
3685 VALUE pw_dir = rb_getpwdirnam_for_login(login_name);
3686 if (
NIL_P(pw_dir)) {
3687 pw_dir = rb_getpwdiruid();
3688 if (
NIL_P(pw_dir)) {
3689 rb_raise(rb_eArgError,
"couldn't find home for uid `%ld'", (
long)getuid());
3700 rb_raise(rb_eArgError,
"couldn't find HOME environment -- expanding `~'");
3702 return copy_home_path(result, dir);
3706ospath_new(
const char *ptr,
long len,
rb_encoding *fsenc)
3708#if NORMALIZE_UTF8PATH
3709 VALUE path = rb_str_normalize_ospath(ptr, len);
3720 char *buf, *cwdp = dir;
3721 VALUE dirname =
Qnil;
3724 if (NORMALIZE_UTF8PATH || *enc != fsenc) {
3725 rb_encoding *direnc = fs_enc_check(fname, dirname = ospath_new(dir, dirlen, fsenc));
3726 if (direnc != fsenc) {
3730 else if (NORMALIZE_UTF8PATH) {
3735 do {buflen *= 2;}
while (dirlen > buflen);
3738 memcpy(buf, cwdp, dirlen);
3742 return buf + dirlen;
3746rb_file_expand_path_internal(VALUE fname, VALUE dname,
int abs_mode,
int long_name, VALUE result)
3748 const char *s, *b, *fend;
3749 char *buf, *p, *pend, *root;
3750 size_t buflen, bdiff;
3758 if (s[0] ==
'~' && abs_mode == 0) {
3760 if (isdirsep(s[1]) || s[1] ==
'\0') {
3765 rb_default_home_dir(result);
3768 s = nextdirsep(b = s, fend, enc);
3771 BUFCHECK(bdiff + userlen >= buflen);
3772 memcpy(p, b, userlen);
3776 rb_home_dir_of(result, result);
3782 rb_enc_raise(enc, rb_eArgError,
"non-absolute home of %.*s%.0"PRIsVALUE,
3783 (
int)userlen, b, fname);
3786 rb_raise(rb_eArgError,
"non-absolute home");
3792#ifdef DOSISH_DRIVE_LETTER
3794 else if (has_drive_letter(s)) {
3795 if (isdirsep(s[2])) {
3798 BUFCHECK(bdiff + 2 >= buflen);
3807 if (!
NIL_P(dname) && !not_same_drive(dname, s[0])) {
3808 rb_file_expand_path_internal(dname,
Qnil, abs_mode, long_name, result);
3816 char *e = append_fspath(result, fname, getcwdofdrv(*s), &enc, fsenc);
3824 p = chompdirsep(skiproot(buf, p, enc), p, enc);
3830 if (!
NIL_P(dname)) {
3831 rb_file_expand_path_internal(dname,
Qnil, abs_mode, long_name, result);
3837 char *e = append_fspath(result, fname,
ruby_getcwd(), &enc, fsenc);
3841#if defined DOSISH || defined __CYGWIN__
3845 p = skipprefix(buf, p, enc);
3849 p = chompdirsep(skiproot(buf, p, enc), p, enc);
3854 do s++;
while (isdirsep(*s));
3857 BUFCHECK(bdiff >= buflen);
3858 memset(buf,
'/', len);
3862 if (p > buf && p[-1] ==
'/')
3866 BUFCHECK(bdiff + 1 >= buflen);
3871 BUFCHECK(bdiff + 1 >= buflen);
3873 root = skipprefix(buf, p+1, enc);
3885 if (*(s+1) ==
'\0' || isdirsep(*(s+1))) {
3889 if (!(n = strrdirsep(root, p, enc))) {
3899 do ++s;
while (istrailinggarbage(*s));
3904#if defined DOSISH || defined __CYGWIN__
3919 while (s < fend && istrailinggarbage(*s)) s++;
3929#if defined DOSISH || defined __CYGWIN__
3933 WITH_ROOTDIFF(BUFCOPY(b, s-b));
3941 int n = ignored_char_p(s, fend, enc);
3944 WITH_ROOTDIFF(BUFCOPY(b, s-b));
3960 static const char prime[] =
":$DATA";
3961 enum {prime_len =
sizeof(prime) -1};
3965 if (s > b + prime_len && strncasecmp(s - prime_len, prime, prime_len) == 0) {
3968 if (isADS(*(s - (prime_len+1)))) {
3971 else if (memchr(b,
':', s - prime_len - b)) {
3980 if (p == skiproot(buf, p + !!*p, enc) - 1) p++;
3984 if ((s = strrdirsep(b = buf, p, enc)) != 0 && !strpbrk(s,
"*?")) {
3989 WIN32_FIND_DATAW wfd;
3992#ifdef HAVE_CYGWIN_CONV_PATH
3993 char *w32buf = NULL;
3994 const int flags = CCP_POSIX_TO_WIN_A | CCP_RELATIVE;
3996 char w32buf[MAXPATHLEN];
4000 int lnk_added = 0, is_symlink = 0;
4004 if (lstat_without_gvl(buf, &st) == 0 && S_ISLNK(st.st_mode)) {
4006 if (len > 4 &&
STRCASECMP(p + len - 4,
".lnk") != 0) {
4010 path = *buf ? buf :
"/";
4011#ifdef HAVE_CYGWIN_CONV_PATH
4012 bufsize = cygwin_conv_path(flags, path, NULL, 0);
4015 if (lnk_added) bufsize += 4;
4017 if (cygwin_conv_path(flags, path, w32buf, bufsize) == 0) {
4022 bufsize = MAXPATHLEN;
4023 if (cygwin_conv_to_win32_path(path, w32buf) == 0) {
4027 if (is_symlink && b == w32buf) {
4029 strlcat(w32buf, p, bufsize);
4031 strlcat(w32buf,
".lnk", bufsize);
4045 len = MultiByteToWideChar(CP_UTF8, 0,
RSTRING_PTR(tmp), -1, NULL, 0);
4047 MultiByteToWideChar(CP_UTF8, 0,
RSTRING_PTR(tmp), -1, wstr, len);
4049 h = FindFirstFileW(wstr, &wfd);
4051 if (h != INVALID_HANDLE_VALUE) {
4054 len = lstrlenW(wfd.cFileName);
4056 if (lnk_added && len > 4 &&
4057 wcscasecmp(wfd.cFileName + len - 4, L
".lnk") == 0) {
4058 wfd.cFileName[len -= 4] = L
'\0';
4065 len = WideCharToMultiByte(CP_UTF8, 0, wfd.cFileName, wlen, NULL, 0, NULL, NULL);
4066 if (tmp == result) {
4067 BUFCHECK(bdiff + len >= buflen);
4068 WideCharToMultiByte(CP_UTF8, 0, wfd.cFileName, wlen, p, len + 1, NULL, NULL);
4072 WideCharToMultiByte(CP_UTF8, 0, wfd.cFileName, wlen,
RSTRING_PTR(tmp), len + 1, NULL, NULL);
4073 rb_str_cat_conv_enc_opts(result, bdiff,
RSTRING_PTR(tmp), len,
4095#define EXPAND_PATH_BUFFER() rb_usascii_str_new(0, MAXPATHLEN + 2)
4098str_shrink(VALUE str)
4104#define expand_path(fname, dname, abs_mode, long_name, result) \
4105 str_shrink(rb_file_expand_path_internal(fname, dname, abs_mode, long_name, result))
4107#define check_expand_path_args(fname, dname) \
4108 (((fname) = rb_get_path(fname)), \
4109 (void)(NIL_P(dname) ? (dname) : ((dname) = rb_get_path(dname))))
4112file_expand_path_1(VALUE fname)
4114 return rb_file_expand_path_internal(fname,
Qnil, 0, 0, EXPAND_PATH_BUFFER());
4120 check_expand_path_args(fname, dname);
4121 return expand_path(fname, dname, 0, 1, EXPAND_PATH_BUFFER());
4125rb_file_expand_path_fast(VALUE fname, VALUE dname)
4127 return expand_path(fname, dname, 0, 0, EXPAND_PATH_BUFFER());
4166s_expand_path(
int c,
const VALUE * v, VALUE
_)
4174 check_expand_path_args(fname, dname);
4175 return expand_path(fname, dname, 1, 1, EXPAND_PATH_BUFFER());
4199s_absolute_path(
int c,
const VALUE * v, VALUE
_)
4215s_absolute_path_p(VALUE klass, VALUE fname)
4223enum rb_realpath_mode {
4227 RB_REALPATH_MODE_MAX
4231realpath_rec(
long *prefixlenp, VALUE *resolvedp,
const char *unresolved, VALUE fallback,
4232 VALUE loopcheck,
enum rb_realpath_mode mode,
int last)
4234 const char *pend = unresolved + strlen(unresolved);
4238 while (unresolved < pend) {
4239 const char *testname = unresolved;
4241 long testnamelen = unresolved_firstsep - unresolved;
4242 const char *unresolved_nextname = unresolved_firstsep;
4243 while (unresolved_nextname < pend && isdirsep(*unresolved_nextname))
4244 unresolved_nextname++;
4245 unresolved = unresolved_nextname;
4246 if (testnamelen == 1 && testname[0] ==
'.') {
4248 else if (testnamelen == 2 && testname[0] ==
'.' && testname[1] ==
'.') {
4250 const char *resolved_str =
RSTRING_PTR(*resolvedp);
4251 const char *resolved_names = resolved_str + *prefixlenp;
4252 const char *lastsep = strrdirsep(resolved_names, resolved_str +
RSTRING_LEN(*resolvedp), enc);
4253 long len = lastsep ? lastsep - resolved_names : 0;
4262#if defined(DOSISH_UNC) || defined(DOSISH_DRIVE_LETTER)
4263 if (*prefixlenp > 1 && *prefixlenp ==
RSTRING_LEN(testpath)) {
4265 const char *last =
rb_enc_left_char_head(prefix, prefix + *prefixlenp - 1, prefix + *prefixlenp, enc);
4271 if (!
NIL_P(checkval)) {
4272 if (checkval ==
ID2SYM(resolving)) {
4273 if (mode == RB_REALPATH_CHECK) {
4277 rb_syserr_fail_path(ELOOP, testpath);
4286 ret = lstat_without_gvl(
RSTRING_PTR(testpath), &sbuf);
4289 if (e == ENOENT && !
NIL_P(fallback)) {
4290 if (stat_without_gvl(
RSTRING_PTR(fallback), &sbuf) == 0) {
4295 if (mode == RB_REALPATH_CHECK)
return -1;
4297 if (mode == RB_REALPATH_STRICT || !last || *unresolved_firstsep)
4298 rb_syserr_fail_path(e, testpath);
4299 *resolvedp = testpath;
4303 rb_syserr_fail_path(e, testpath);
4307 if (S_ISLNK(sbuf.st_mode)) {
4309 VALUE link_orig =
Qnil;
4310 const char *link_prefix, *link_names;
4311 long link_prefixlen;
4313 link = rb_readlink(testpath, enc);
4316 link_prefixlen = link_names - link_prefix;
4317 if (link_prefixlen > 0) {
4321 tmpenc = fs_enc_check(*resolvedp, link);
4324 *prefixlenp = link_prefixlen;
4326 if (realpath_rec(prefixlenp, resolvedp, link_names, testpath,
4327 loopcheck, mode, !*unresolved_firstsep))
4337 *resolvedp = testpath;
4346rb_check_realpath_emulate(VALUE basedir, VALUE path,
rb_encoding *origenc,
enum rb_realpath_mode mode)
4350 VALUE unresolved_path;
4352 VALUE curdir =
Qnil;
4355 char *path_names = NULL, *basedir_names = NULL, *curdir_names = NULL;
4356 char *ptr, *prefixptr = NULL, *pend;
4361 if (!
NIL_P(basedir)) {
4367 unresolved_path = TO_OSPATH(unresolved_path);
4369 path_names = skipprefixroot(ptr, ptr + len,
rb_enc_get(unresolved_path));
4370 if (ptr != path_names) {
4371 resolved =
rb_str_subseq(unresolved_path, 0, path_names - ptr);
4375 if (!
NIL_P(basedir)) {
4377 basedir_names = skipprefixroot(ptr, ptr + len,
rb_enc_get(basedir));
4378 if (ptr != basedir_names) {
4384 curdir = rb_dir_getwd_ospath();
4386 curdir_names = skipprefixroot(ptr, ptr + len,
rb_enc_get(curdir));
4391 pend = prefixptr + prefixlen;
4392 ptr = chompdirsep(prefixptr, pend, enc);
4394 prefixlen = ++ptr - prefixptr;
4397#ifdef FILE_ALT_SEPARATOR
4398 while (prefixptr < ptr) {
4399 if (*prefixptr == FILE_ALT_SEPARATOR) {
4402 Inc(prefixptr, pend, enc);
4407 case ENCINDEX_ASCII:
4408 case ENCINDEX_US_ASCII:
4414 if (realpath_rec(&prefixlen, &resolved, curdir_names,
Qnil, loopcheck, mode, 0))
4417 if (basedir_names) {
4418 if (realpath_rec(&prefixlen, &resolved, basedir_names,
Qnil, loopcheck, mode, 0))
4421 if (realpath_rec(&prefixlen, &resolved, path_names,
Qnil, loopcheck, mode, 1))
4424 if (origenc && origenc !=
rb_enc_get(resolved)) {
4438static VALUE rb_file_join(VALUE ary);
4440#ifndef HAVE_REALPATH
4442rb_check_realpath_emulate_try(VALUE arg)
4444 VALUE *args = (VALUE *)arg;
4445 return rb_check_realpath_emulate(args[0], args[1], (
rb_encoding *)args[2], RB_REALPATH_CHECK);
4449rb_check_realpath_emulate_rescue(VALUE arg, VALUE exc)
4456rb_check_realpath_internal(VALUE basedir, VALUE path,
rb_encoding *origenc,
enum rb_realpath_mode mode)
4459 VALUE unresolved_path;
4460 char *resolved_ptr = NULL;
4463 if (mode == RB_REALPATH_DIR) {
4464 return rb_check_realpath_emulate(basedir, path, origenc, mode);
4469 unresolved_path = rb_file_join(
rb_assoc_new(basedir, unresolved_path));
4471 if (origenc) unresolved_path = TO_OSPATH(unresolved_path);
4473 if ((resolved_ptr = realpath(
RSTRING_PTR(unresolved_path), NULL)) == NULL) {
4479 if (errno == ENOTDIR ||
4480 (errno == ENOENT && rb_file_exist_p(0, unresolved_path))) {
4481 return rb_check_realpath_emulate(basedir, path, origenc, mode);
4484 if (mode == RB_REALPATH_CHECK) {
4487 rb_sys_fail_path(unresolved_path);
4492# if !defined(__LINUX__) && !defined(__APPLE__)
4496 if (stat_without_gvl(
RSTRING_PTR(resolved), &st) < 0) {
4497 if (mode == RB_REALPATH_CHECK) {
4500 rb_sys_fail_path(unresolved_path);
4504 if (origenc && origenc !=
rb_enc_get(resolved)) {
4521 if (mode == RB_REALPATH_CHECK) {
4525 arg[2] = (
VALUE)origenc;
4527 return rb_rescue(rb_check_realpath_emulate_try, (VALUE)arg,
4528 rb_check_realpath_emulate_rescue,
Qnil);
4531 return rb_check_realpath_emulate(basedir, path, origenc, mode);
4537rb_realpath_internal(VALUE basedir, VALUE path,
int strict)
4539 const enum rb_realpath_mode mode =
4540 strict ? RB_REALPATH_STRICT : RB_REALPATH_DIR;
4541 return rb_check_realpath_internal(basedir, path,
rb_enc_get(path), mode);
4545rb_check_realpath(VALUE basedir, VALUE path,
rb_encoding *enc)
4547 return rb_check_realpath_internal(basedir, path, enc, RB_REALPATH_CHECK);
4564rb_file_s_realpath(
int argc, VALUE *argv, VALUE klass)
4567 VALUE path = argv[0];
4569 return rb_realpath_internal(basedir, path, 1);
4585rb_file_s_realdirpath(
int argc, VALUE *argv, VALUE klass)
4588 VALUE path = argv[0];
4590 return rb_realpath_internal(basedir, path, 0);
4594rmext(
const char *p,
long l0,
long l1,
const char *e,
long l2,
rb_encoding *enc)
4598 const char *s, *last;
4600 if (!e || !l2)
return 0;
4603 if (
rb_enc_ascget(e + len1, e + l2, &len2, enc) ==
'*' && len1 + len2 == l2) {
4604 if (c ==
'.')
return l0;
4614 if (l1 < l2)
return l1;
4618#if CASEFOLD_FILESYSTEM
4619#define fncomp strncasecmp
4621#define fncomp strncmp
4623 if (fncomp(s, e, l2) == 0) {
4632 const char *p, *q, *e, *end;
4633#if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC
4638 end = name + (alllen ? (size_t)*alllen : strlen(name));
4639 name = skipprefix(name, end, enc);
4640#if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC
4643 while (isdirsep(*name))
4648#if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC
4652#ifdef DOSISH_DRIVE_LETTER
4653 else if (*p ==
':') {
4666 if (!(p = strrdirsep(name, end, enc))) {
4670 while (isdirsep(*p)) p++;
4673 n = ntfs_tail(p, end, enc) - p;
4675 n = chompdirsep(p, end, enc) - p;
4677 for (q = p; q - p < n && *q ==
'.'; q++);
4678 for (e = 0; q - p < n; Inc(q, end, enc)) {
4679 if (*q ==
'.') e = q;
4710rb_file_s_basename(
int argc, VALUE *argv, VALUE
_)
4712 VALUE fname, fext, basename;
4713 const char *name, *p;
4721 enc = check_path_encoding(fext);
4740 if (!(f = rmext(p, f, n, fp,
RSTRING_LEN(fext), enc))) {
4753static VALUE rb_file_dirname_n(VALUE fname,
int n);
4775rb_file_s_dirname(
int argc, VALUE *argv, VALUE klass)
4781 return rb_file_dirname_n(argv[0], n);
4787 return rb_file_dirname_n(fname, 1);
4791rb_file_dirname_n(VALUE fname,
int n)
4793 const char *name, *root, *p, *end;
4799 if (n < 0)
rb_raise(rb_eArgError,
"negative level: %d", n);
4804 root = skiproot(name, end, enc);
4806 if (root > name + 1 && isdirsep(*name))
4807 root = skipprefix(name = root - 2, end, enc);
4809 if (root > name + 1)
4812 if (n > (end - root + 1) / 2) {
4822 if (!(p = strrdirsep(root, end, enc))) p = root;
4825 seps =
ALLOCV_N(
const char *, sepsv, n);
4826 for (i = 0; i < n; ++i) seps[i] = root;
4828 for (p = root; p < end; ) {
4830 const char *tmp = p++;
4831 while (p < end && isdirsep(*p)) p++;
4832 if (p >= end)
break;
4847#ifdef DOSISH_DRIVE_LETTER
4848 if (has_drive_letter(name) && isdirsep(*(name + 2))) {
4849 const char *top = skiproot(name + 2, end, enc);
4856#ifdef DOSISH_DRIVE_LETTER
4857 if (has_drive_letter(name) && root == name + 2 && p - name == 2)
4879 const char *p, *e, *end = name + (len ? *len : (long)strlen(name));
4881 p = strrdirsep(name, end, enc);
4885 do name = ++p;
while (isdirsep(*p));
4888 while (*p && *p ==
'.') p++;
4890 if (*p ==
'.' || istrailinggarbage(*p)) {
4892 const char *last = p++, *dot = last;
4893 while (istrailinggarbage(*p)) {
4894 if (*p ==
'.') dot = p;
4897 if (!*p || isADS(*p)) {
4901 if (*last ==
'.' || dot > last) e = dot;
4908 else if (isADS(*p)) {
4912 else if (isdirsep(*p))
4919 if (!e || e == name)
4956rb_file_s_extname(VALUE klass, VALUE fname)
4958 const char *name, *e;
4984rb_file_s_path(VALUE klass, VALUE fname)
5001rb_file_s_split(VALUE klass, VALUE path)
5008file_inspect_join(VALUE ary, VALUE arg,
int recur)
5010 if (recur || ary == arg)
rb_raise(rb_eArgError,
"recursive array");
5011 return rb_file_join(arg);
5015rb_file_join(VALUE ary)
5019 const char *name, *tail;
5029 check_path_encoding(tmp);
5038 RBASIC_CLEAR_CLASS(result);
5041 switch (OBJ_BUILTIN_TYPE(tmp)) {
5043 if (!checked) check_path_encoding(tmp);
5048 rb_raise(rb_eArgError,
"recursive array");
5063 tail = chompdirsep(name, name + len,
rb_enc_get(result));
5071 enc = fs_enc_check(result, tmp);
5092rb_file_s_join(VALUE klass, VALUE args)
5094 return rb_file_join(args);
5097#if defined(HAVE_TRUNCATE) || defined(HAVE_CHSIZE)
5098struct truncate_arg {
5100#if defined(HAVE_TRUNCATE)
5101#define NUM2POS(n) NUM2OFFT(n)
5104#define NUM2POS(n) NUM2LONG(n)
5110nogvl_truncate(
void *ptr)
5112 struct truncate_arg *ta = ptr;
5114 return (
void *)(
VALUE)truncate(ta->path, ta->pos);
5122 if (chsize(tmpfd, ta->pos) < 0) {
5150rb_file_s_truncate(VALUE klass, VALUE path, VALUE len)
5152 struct truncate_arg ta;
5155 ta.pos = NUM2POS(len);
5163 rb_sys_fail_path(path);
5168#define rb_file_s_truncate rb_f_notimplement
5171#if defined(HAVE_FTRUNCATE) || defined(HAVE_CHSIZE)
5172struct ftruncate_arg {
5174#if defined(HAVE_FTRUNCATE)
5175#define NUM2POS(n) NUM2OFFT(n)
5178#define NUM2POS(n) NUM2LONG(n)
5184nogvl_ftruncate(
void *ptr)
5186 struct ftruncate_arg *fa = ptr;
5188#ifdef HAVE_FTRUNCATE
5189 return (VALUE)ftruncate(fa->fd, fa->pos);
5191 return (VALUE)chsize(fa->fd, fa->pos);
5210rb_file_truncate(VALUE obj, VALUE len)
5213 struct ftruncate_arg fa;
5215 fa.pos = NUM2POS(len);
5220 rb_io_flush_raw(obj, 0);
5222 if ((
int)rb_thread_io_blocking_region(nogvl_ftruncate, &fa, fa.fd) < 0) {
5223 rb_sys_fail_path(fptr->
pathv);
5229#define rb_file_truncate rb_f_notimplement
5246#include <winerror.h>
5250rb_thread_flock(
void *data)
5253 int old_errno = errno;
5255 int *op = data, ret =
flock(op[0], op[1]);
5258 if (GetLastError() == ERROR_NOT_LOCKED) {
5311rb_file_flock(VALUE obj, VALUE operation)
5317 op[1] = op1 =
NUM2INT(operation);
5322 rb_io_flush_raw(obj, 0);
5324 while ((
int)rb_thread_io_blocking_region(rb_thread_flock, op, fptr->
fd) < 0) {
5329#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
5332 if (op1 & LOCK_NB)
return Qfalse;
5335 time.tv_usec = 100 * 1000;
5341#if defined(ERESTART)
5347 rb_syserr_fail_path(e, fptr->
pathv);
5354test_check(
int n,
int argc, VALUE *argv)
5360 for (i=1; i<n; i++) {
5367#define CHECK(n) test_check((n), argc, argv)
5428rb_f_test(
int argc, VALUE *argv, VALUE
_)
5437 if (strchr(
"bcdefgGkloOprRsSuwWxXz", cmd)) {
5441 return rb_file_blockdev_p(0, argv[1]);
5444 return rb_file_chardev_p(0, argv[1]);
5450 return rb_file_exist_p(0, argv[1]);
5453 return rb_file_file_p(0, argv[1]);
5456 return rb_file_sgid_p(0, argv[1]);
5459 return rb_file_grpowned_p(0, argv[1]);
5462 return rb_file_sticky_p(0, argv[1]);
5465 return rb_file_symlink_p(0, argv[1]);
5468 return rb_file_owned_p(0, argv[1]);
5471 return rb_file_rowned_p(0, argv[1]);
5474 return rb_file_pipe_p(0, argv[1]);
5477 return rb_file_readable_p(0, argv[1]);
5480 return rb_file_readable_real_p(0, argv[1]);
5483 return rb_file_size_p(0, argv[1]);
5486 return rb_file_socket_p(0, argv[1]);
5489 return rb_file_suid_p(0, argv[1]);
5492 return rb_file_writable_p(0, argv[1]);
5495 return rb_file_writable_real_p(0, argv[1]);
5498 return rb_file_executable_p(0, argv[1]);
5501 return rb_file_executable_real_p(0, argv[1]);
5504 return rb_file_zero_p(0, argv[1]);
5508 if (strchr(
"MAC", cmd)) {
5510 VALUE fname = argv[1];
5513 if (rb_stat(fname, &st) == -1) {
5516 rb_syserr_fail_path(e, fname);
5521 return stat_atime(&st);
5523 return stat_mtime(&st);
5525 return stat_ctime(&st);
5531 return rb_file_identical_p(0, argv[1], argv[2]);
5534 if (strchr(
"=<>", cmd)) {
5535 struct stat st1, st2;
5539 if (rb_stat(argv[1], &st1) < 0)
return Qfalse;
5540 if (rb_stat(argv[2], &st2) < 0)
return Qfalse;
5542 t1 = stat_mtimespec(&st1);
5543 t2 = stat_mtimespec(&st2);
5547 if (t1.tv_sec == t2.tv_sec && t1.tv_nsec == t2.tv_nsec)
return Qtrue;
5551 if (t1.tv_sec > t2.tv_sec)
return Qtrue;
5552 if (t1.tv_sec == t2.tv_sec && t1.tv_nsec > t2.tv_nsec)
return Qtrue;
5556 if (t1.tv_sec < t2.tv_sec)
return Qtrue;
5557 if (t1.tv_sec == t2.tv_sec && t1.tv_nsec < t2.tv_nsec)
return Qtrue;
5564 rb_raise(rb_eArgError,
"unknown command '%s%c'", cmd ==
'\'' || cmd ==
'\\' ?
"\\" :
"", cmd);
5567 rb_raise(rb_eArgError,
"unknown command \"\\x%02X\"", cmd);
5586rb_stat_s_alloc(VALUE klass)
5588 return stat_new_0(klass, 0);
5601rb_stat_init(VALUE obj, VALUE fname)
5603 struct stat st, *nst;
5608 rb_sys_fail_path(fname);
5623rb_stat_init_copy(VALUE copy, VALUE orig)
5656rb_stat_ftype(VALUE obj)
5658 return rb_file_ftype(get_stat(obj));
5675 if (S_ISDIR(get_stat(obj)->st_mode))
return Qtrue;
5691 if (S_ISFIFO(get_stat(obj)->st_mode))
return Qtrue;
5717 if (S_ISLNK(get_stat(obj)->st_mode))
return Qtrue;
5738 if (S_ISSOCK(get_stat(obj)->st_mode))
return Qtrue;
5761 if (S_ISBLK(get_stat(obj)->st_mode))
return Qtrue;
5782 if (S_ISCHR(get_stat(obj)->st_mode))
return Qtrue;
5800rb_stat_owned(VALUE obj)
5802 if (get_stat(obj)->st_uid == geteuid())
return Qtrue;
5807rb_stat_rowned(VALUE obj)
5809 if (get_stat(obj)->st_uid == getuid())
return Qtrue;
5826rb_stat_grpowned(VALUE obj)
5829 if (rb_group_member(get_stat(obj)->st_gid))
return Qtrue;
5848 struct stat *st = get_stat(obj);
5851 if (geteuid() == 0)
return Qtrue;
5854 if (rb_stat_owned(obj))
5855 return RBOOL(st->st_mode & S_IRUSR);
5858 if (rb_stat_grpowned(obj))
5859 return RBOOL(st->st_mode & S_IRGRP);
5862 if (!(st->st_mode & S_IROTH))
return Qfalse;
5881 struct stat *st = get_stat(obj);
5884 if (getuid() == 0)
return Qtrue;
5887 if (rb_stat_rowned(obj))
5888 return RBOOL(st->st_mode & S_IRUSR);
5891 if (rb_group_member(get_stat(obj)->st_gid))
5892 return RBOOL(st->st_mode & S_IRGRP);
5895 if (!(st->st_mode & S_IROTH))
return Qfalse;
5914rb_stat_wr(VALUE obj)
5917 struct stat *st = get_stat(obj);
5918 if ((st->st_mode & (S_IROTH)) == S_IROTH) {
5919 return UINT2NUM(st->st_mode & (S_IRUGO|S_IWUGO|S_IXUGO));
5941 struct stat *st = get_stat(obj);
5944 if (geteuid() == 0)
return Qtrue;
5947 if (rb_stat_owned(obj))
5948 return RBOOL(st->st_mode & S_IWUSR);
5951 if (rb_stat_grpowned(obj))
5952 return RBOOL(st->st_mode & S_IWGRP);
5955 if (!(st->st_mode & S_IWOTH))
return Qfalse;
5974 struct stat *st = get_stat(obj);
5977 if (getuid() == 0)
return Qtrue;
5980 if (rb_stat_rowned(obj))
5981 return RBOOL(st->st_mode & S_IWUSR);
5984 if (rb_group_member(get_stat(obj)->st_gid))
5985 return RBOOL(st->st_mode & S_IWGRP);
5988 if (!(st->st_mode & S_IWOTH))
return Qfalse;
6007rb_stat_ww(VALUE obj)
6010 struct stat *st = get_stat(obj);
6011 if ((st->st_mode & (S_IWOTH)) == S_IWOTH) {
6012 return UINT2NUM(st->st_mode & (S_IRUGO|S_IWUGO|S_IXUGO));
6036 struct stat *st = get_stat(obj);
6039 if (geteuid() == 0) {
6040 return RBOOL(st->st_mode & S_IXUGO);
6044 if (rb_stat_owned(obj))
6045 return RBOOL(st->st_mode & S_IXUSR);
6048 if (rb_stat_grpowned(obj))
6049 return RBOOL(st->st_mode & S_IXGRP);
6052 if (!(st->st_mode & S_IXOTH))
return Qfalse;
6068 struct stat *st = get_stat(obj);
6071 if (getuid() == 0) {
6072 return RBOOL(st->st_mode & S_IXUGO);
6076 if (rb_stat_rowned(obj))
6077 return RBOOL(st->st_mode & S_IXUSR);
6080 if (rb_group_member(get_stat(obj)->st_gid))
6081 return RBOOL(st->st_mode & S_IXGRP);
6084 if (!(st->st_mode & S_IXOTH))
return Qfalse;
6103 if (S_ISREG(get_stat(obj)->st_mode))
return Qtrue;
6121 if (get_stat(obj)->st_size == 0)
return Qtrue;
6140 off_t size = get_stat(obj)->st_size;
6142 if (size == 0)
return Qnil;
6158rb_stat_suid(VALUE obj)
6161 if (get_stat(obj)->st_mode & S_ISUID)
return Qtrue;
6179rb_stat_sgid(VALUE obj)
6182 if (get_stat(obj)->st_mode & S_ISGID)
return Qtrue;
6200rb_stat_sticky(VALUE obj)
6203 if (get_stat(obj)->st_mode & S_ISVTX)
return Qtrue;
6208#if !defined HAVE_MKFIFO && defined HAVE_MKNOD && defined S_IFIFO
6209#define mkfifo(path, mode) mknod(path, (mode)&~S_IFMT|S_IFIFO, 0)
6220nogvl_mkfifo(
void *ptr)
6222 struct mkfifo_arg *ma = ptr;
6224 return (
void *)(
VALUE)mkfifo(ma->path, ma->mode);
6238rb_file_s_mkfifo(
int argc, VALUE *argv, VALUE
_)
6241 struct mkfifo_arg ma;
6253 rb_sys_fail_path(path);
6258#define rb_file_s_mkfifo rb_f_notimplement
6261static VALUE rb_mFConst;
6264rb_file_const(
const char *name, VALUE value)
6272#ifdef DOSISH_DRIVE_LETTER
6273 if (has_drive_letter(path) && isdirsep(path[2]))
return 1;
6276 if (isdirsep(path[0]) && isdirsep(path[1]))
return 1;
6279 if (path[0] ==
'/')
return 1;
6284#ifndef ENABLE_PATH_CHECK
6285# if defined DOSISH || defined __CYGWIN__
6286# define ENABLE_PATH_CHECK 0
6288# define ENABLE_PATH_CHECK 1
6292#if ENABLE_PATH_CHECK
6294path_check_0(VALUE path)
6320 if (STAT(p0, &st) == 0 && S_ISDIR(st.st_mode) && (st.st_mode & S_IWOTH)
6322 && !(p && (st.st_mode & S_ISVTX))
6324 && !access(p0, W_OK)) {
6325 rb_enc_warn(enc,
"Insecure world writable dir %s in PATH, mode 0%"
6326#
if SIZEOF_DEV_T > SIZEOF_INT
6336 s = strrdirsep(p0, e0, enc);
6338 if (!s || s == p0)
return 1;
6349#if ENABLE_PATH_CHECK
6350 const char *p0, *p, *pend;
6353 if (!path)
return 1;
6355 pend = path + strlen(path);
6357 p = strchr(path, sep);
6365 if (p0 > pend)
break;
6366 p = strchr(p0, sep);
6374ruby_is_fd_loadable(
int fd)
6381 if (fstat(fd, &st) < 0)
6384 if (S_ISREG(st.st_mode))
6387 if (S_ISFIFO(st.st_mode) || S_ISCHR(st.st_mode))
6390 if (S_ISDIR(st.st_mode))
6401rb_file_load_ok(
const char *path)
6408 int mode = (O_RDONLY |
6409#if defined O_NONBLOCK
6411#elif defined O_NDELAY
6416 if (fd == -1)
return 0;
6418 ret = ruby_is_fd_loadable(fd);
6425is_explicit_relative(
const char *path)
6427 if (*path++ !=
'.')
return 0;
6428 if (*path ==
'.') path++;
6429 return isdirsep(*path);
6433copy_path_class(VALUE path, VALUE orig)
6436 if (encidx == ENCINDEX_ASCII || encidx == ENCINDEX_US_ASCII)
6440 RBASIC_SET_CLASS(path, rb_obj_class(orig));
6449 VALUE fname = *filep, load_path, tmp;
6453 if (!ext[0])
return 0;
6456 fname = file_expand_path_1(fname);
6463 if (!expanded) fname = file_expand_path_1(fname);
6465 for (i=0; ext[i]; i++) {
6468 *filep = copy_path_class(fname, *filep);
6476 RB_GC_GUARD(load_path) = rb_get_expanded_load_path();
6477 if (!load_path)
return 0;
6480 RBASIC_CLEAR_CLASS(fname);
6484 for (j=0; ext[j]; j++) {
6486 for (i = 0; i <
RARRAY_LEN(load_path); i++) {
6491 rb_file_expand_path_internal(fname, str, 0, 0, tmp);
6493 *filep = copy_path_class(tmp, *filep);
6507 VALUE tmp, load_path;
6512 tmp = file_expand_path_1(path);
6513 path = copy_path_class(tmp, path);
6519 if (!rb_file_load_ok(f))
return 0;
6521 path = copy_path_class(file_expand_path_1(path), path);
6525 RB_GC_GUARD(load_path) = rb_get_expanded_load_path();
6531 for (i = 0; i <
RARRAY_LEN(load_path); i++) {
6535 rb_file_expand_path_internal(path, str, 0, 0, tmp);
6537 if (rb_file_load_ok(f))
goto found;
6548 return copy_path_class(tmp, path);
6552define_filetest_function(
const char *name, VALUE (*func)(
ANYARGS),
int argc)
6558const char ruby_null_device[] =
6561#elif defined AMIGA || defined __amigaos__
6739#if defined(__APPLE__) && defined(HAVE_WORKING_FORK)
6740 rb_CFString_class_initialize_before_fork();
6749 define_filetest_function(
"exist?", rb_file_exist_p, 1);
6750 define_filetest_function(
"exists?", rb_file_exists_p, 1);
6751 define_filetest_function(
"readable?", rb_file_readable_p, 1);
6752 define_filetest_function(
"readable_real?", rb_file_readable_real_p, 1);
6753 define_filetest_function(
"world_readable?", rb_file_world_readable_p, 1);
6754 define_filetest_function(
"writable?", rb_file_writable_p, 1);
6755 define_filetest_function(
"writable_real?", rb_file_writable_real_p, 1);
6756 define_filetest_function(
"world_writable?", rb_file_world_writable_p, 1);
6757 define_filetest_function(
"executable?", rb_file_executable_p, 1);
6758 define_filetest_function(
"executable_real?", rb_file_executable_real_p, 1);
6759 define_filetest_function(
"file?", rb_file_file_p, 1);
6760 define_filetest_function(
"zero?", rb_file_zero_p, 1);
6761 define_filetest_function(
"empty?", rb_file_zero_p, 1);
6762 define_filetest_function(
"size?", rb_file_size_p, 1);
6763 define_filetest_function(
"size", rb_file_s_size, 1);
6764 define_filetest_function(
"owned?", rb_file_owned_p, 1);
6765 define_filetest_function(
"grpowned?", rb_file_grpowned_p, 1);
6767 define_filetest_function(
"pipe?", rb_file_pipe_p, 1);
6768 define_filetest_function(
"symlink?", rb_file_symlink_p, 1);
6769 define_filetest_function(
"socket?", rb_file_socket_p, 1);
6771 define_filetest_function(
"blockdev?", rb_file_blockdev_p, 1);
6772 define_filetest_function(
"chardev?", rb_file_chardev_p, 1);
6774 define_filetest_function(
"setuid?", rb_file_suid_p, 1);
6775 define_filetest_function(
"setgid?", rb_file_sgid_p, 1);
6776 define_filetest_function(
"sticky?", rb_file_sticky_p, 1);
6778 define_filetest_function(
"identical?", rb_file_identical_p, 2);
6816 separator = rb_fstring_lit(
"/");
6876#if defined(O_NDELAY) || defined(O_NONBLOCK)
6878# define O_NONBLOCK O_NDELAY
6894#ifndef O_SHARE_DELETE
6895# define O_SHARE_DELETE 0
6938 rb_define_const(rb_mFConst,
"NULL", rb_fstring_cstr(ruby_null_device));
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
#define PATH_SEP
The delimiter of PATH environment variable.
#define PATH_SEP_CHAR
Identical to PATH_SEP, except it is of type char.
#define GIDT2NUM
Converts a C's gid_t into an instance of rb_cInteger.
#define NUM2GIDT
Converts an instance of rb_cNumeric into C's gid_t.
void rb_include_module(VALUE klass, VALUE module)
Includes a module to a class.
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
VALUE rb_define_module(const char *name)
Defines a top-level module.
VALUE rb_define_module_under(VALUE outer, const char *name)
Defines a module under the namespace of outer.
void rb_define_module_function(VALUE module, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a module function for a module.
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a method.
void rb_define_global_function(const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a global function.
#define rb_str_new2
Old name of rb_str_new_cstr.
#define ENC_CODERANGE_7BIT
Old name of RUBY_ENC_CODERANGE_7BIT.
#define T_FILE
Old name of RUBY_T_FILE.
#define NUM2ULONG
Old name of RB_NUM2ULONG.
#define ALLOCV
Old name of RB_ALLOCV.
#define OBJ_INIT_COPY(obj, orig)
Old name of RB_OBJ_INIT_COPY.
#define ALLOC
Old name of RB_ALLOC.
#define T_STRING
Old name of RUBY_T_STRING.
#define xfree
Old name of ruby_xfree.
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
#define ID2SYM
Old name of RB_ID2SYM.
#define rb_str_buf_new2
Old name of rb_str_buf_new_cstr.
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
#define ULONG2NUM
Old name of RB_ULONG2NUM.
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
#define ENCODING_GET(obj)
Old name of RB_ENCODING_GET.
#define LONG2FIX
Old name of RB_INT2FIX.
#define MBCLEN_CHARFOUND_LEN(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_LEN.
#define STRCASECMP
Old name of st_locale_insensitive_strcasecmp.
#define rb_usascii_str_new2
Old name of rb_usascii_str_new_cstr.
#define ISALPHA
Old name of rb_isalpha.
#define ULL2NUM
Old name of RB_ULL2NUM.
#define TOLOWER
Old name of rb_tolower.
#define Qtrue
Old name of RUBY_Qtrue.
#define NUM2INT
Old name of RB_NUM2INT.
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define ENC_CODERANGE_BROKEN
Old name of RUBY_ENC_CODERANGE_BROKEN.
#define T_ARRAY
Old name of RUBY_T_ARRAY.
#define NIL_P
Old name of RB_NIL_P.
#define ALLOCV_N
Old name of RB_ALLOCV_N.
#define MBCLEN_CHARFOUND_P(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_P.
#define ISPRINT
Old name of rb_isprint.
#define NUM2CHR
Old name of RB_NUM2CHR.
#define T_CLASS
Old name of RUBY_T_CLASS.
#define ENC_CODERANGE_CLEAR(obj)
Old name of RB_ENC_CODERANGE_CLEAR.
#define UINT2NUM
Old name of RB_UINT2NUM.
#define CONST_ID
Old name of RUBY_CONST_ID.
#define rb_str_new4
Old name of rb_str_new_frozen.
#define ALLOCV_END
Old name of RB_ALLOCV_END.
void rb_raise(VALUE exc, const char *fmt,...)
Exception entry point.
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
void rb_bug(const char *fmt,...)
Interpreter panic switch.
VALUE rb_eIOError
IOError exception.
VALUE rb_rescue(VALUE(*b_proc)(VALUE), VALUE data1, VALUE(*r_proc)(VALUE, VALUE), VALUE data2)
Identical to rb_rescue2(), except it does not take a list of exception classes.
VALUE rb_cStat
File::Stat class.
VALUE rb_class_inherited_p(VALUE scion, VALUE ascendant)
Determines if the given two modules are relatives.
VALUE rb_mFileTest
FileTest module.
VALUE rb_mComparable
Comparable module.
VALUE rb_cFile
File class.
VALUE rb_cString
String class.
int rb_enc_precise_mbclen(const char *p, const char *e, rb_encoding *enc)
Queries the number of bytes of the character at the passed pointer.
int rb_enc_get_index(VALUE obj)
Queries the index of the encoding of the passed object, if any.
int rb_filesystem_encindex(void)
Identical to rb_filesystem_encoding(), except it returns the encoding's index instead of the encoding...
VALUE rb_enc_associate(VALUE obj, rb_encoding *enc)
Identical to rb_enc_associate(), except it takes an encoding itself instead of its index.
rb_encoding * rb_utf8_encoding(void)
Queries the encoding that represents UTF-8.
rb_encoding * rb_ascii8bit_encoding(void)
Queries the encoding that represents ASCII-8BIT a.k.a.
rb_encoding * rb_filesystem_encoding(void)
Queries the "filesystem" encoding.
static const char * rb_enc_name(rb_encoding *enc)
Queries the (canonical) name of the passed encoding.
rb_encoding * rb_default_internal_encoding(void)
Queries the "default internal" encoding.
void rb_enc_copy(VALUE dst, VALUE src)
Destructively copies the encoding of the latter object to that of former one.
static char * rb_enc_left_char_head(const char *s, const char *p, const char *e, rb_encoding *enc)
Queries the left boundary of a character.
rb_encoding * rb_enc_get(VALUE obj)
Identical to rb_enc_get_index(), except the return type.
rb_encoding * rb_enc_from_index(int idx)
Identical to rb_find_encoding(), except it takes an encoding index instead of a Ruby object.
unsigned int rb_enc_codepoint_len(const char *p, const char *e, int *len, rb_encoding *enc)
Queries the code point of character pointed by the passed pointer.
int rb_enc_to_index(rb_encoding *enc)
Queries the index of the encoding.
static bool rb_enc_asciicompat(rb_encoding *enc)
Queries if the passed encoding is in some sense compatible with ASCII.
rb_encoding * rb_enc_check(VALUE str1, VALUE str2)
Identical to rb_enc_compatible(), except it raises an exception instead of returning NULL.
VALUE rb_enc_associate_index(VALUE obj, int encindex)
Identical to rb_enc_set_index(), except it additionally does contents fix-up depending on the passed ...
rb_encoding * rb_enc_compatible(VALUE str1, VALUE str2)
Look for the "common" encoding between the two.
static OnigCodePoint rb_enc_mbc_to_codepoint(const char *p, const char *e, rb_encoding *enc)
Identical to rb_enc_codepoint(), except it assumes the passed character is not broken.
int rb_enc_ascget(const char *p, const char *e, int *len, rb_encoding *enc)
Queries the code point of character pointed by the passed pointer.
int rb_usascii_encindex(void)
Identical to rb_usascii_encoding(), except it returns the encoding's index instead of the encoding it...
VALUE rb_str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to)
Encoding conversion main routine.
int rb_enc_str_coderange(VALUE str)
Scans the passed string to collect its code range.
VALUE rb_enc_str_new(const char *ptr, long len, rb_encoding *enc)
Identical to rb_enc_str_new(), except it additionally takes an encoding.
int rb_enc_str_asciionly_p(VALUE str)
Queries if the passed string is "ASCII only".
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Identical to rb_ary_new_from_values(), except it expects exactly two parameters.
#define INTEGER_PACK_NATIVE_BYTE_ORDER
Means either INTEGER_PACK_MSBYTE_FIRST or INTEGER_PACK_LSBYTE_FIRST, depending on the host processor'...
VALUE rb_integer_unpack(const void *words, size_t numwords, size_t wordsize, size_t nails, int flags)
Import an integer from a buffer.
#define INTEGER_PACK_2COMP
Uses 2's complement representation.
#define INTEGER_PACK_LSWORD_FIRST
Stores/interprets the least significant word as the first word.
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
VALUE rb_find_file(VALUE path)
Identical to rb_find_file_ext(), except it takes a feature name and is extension at once,...
VALUE rb_file_s_absolute_path(int argc, const VALUE *argv)
Identical to rb_file_absolute_path(), except how arguments are passed.
VALUE rb_str_encode_ospath(VALUE path)
Converts a string into an "OS Path" encoding, if any.
int rb_is_absolute_path(const char *path)
Queries if the given path is an absolute path.
int rb_find_file_ext(VALUE *feature, const char *const *exts)
Resolves a feature's path.
off_t rb_file_size(VALUE file)
Queries the file size of the given file.
VALUE rb_file_s_expand_path(int argc, const VALUE *argv)
Identical to rb_file_expand_path(), except how arguments are passed.
VALUE rb_file_directory_p(VALUE _, VALUE path)
Queries if the given path is either a directory, or a symlink that (potentially recursively) points t...
VALUE rb_file_expand_path(VALUE fname, VALUE dname)
Identical to rb_file_absolute_path(), except it additionally understands ~.
VALUE rb_file_dirname(VALUE fname)
Strips a file path's last component (and trailing separators if any).
VALUE rb_file_absolute_path(VALUE fname, VALUE dname)
Maps a relative path to its absolute representation.
int rb_path_check(const char *path)
This function is mysterious.
VALUE rb_hash_aref(VALUE hash, VALUE key)
Queries the given key in the given hash table.
VALUE rb_hash_aset(VALUE hash, VALUE key, VALUE val)
Inserts or replaces ("upsert"s) the objects into the given hash table.
VALUE rb_hash_new(void)
Creates a new, empty hash object.
void rb_update_max_fd(int fd)
Informs the interpreter that the passed fd can be the max.
int rb_cloexec_open(const char *pathname, int flags, mode_t mode)
Opens a file that closes on exec.
VALUE rb_str_new_shared(VALUE str)
Identical to rb_str_new_cstr(), except it takes a Ruby's string instead of C's.
VALUE rb_str_plus(VALUE lhs, VALUE rhs)
Generates a new string, concatenating the former to the latter.
VALUE rb_str_append(VALUE dst, VALUE src)
Identical to rb_str_buf_append(), except it converts the right hand side before concatenating.
VALUE rb_str_tmp_new(long len)
Allocates a "temporary" string.
VALUE rb_str_subseq(VALUE str, long beg, long len)
Identical to rb_str_substr(), except the numbers are interpreted as byte offsets instead of character...
VALUE rb_str_ellipsize(VALUE str, long len)
Shortens str and adds three dots, an ellipsis, if it is longer than len characters.
size_t rb_str_capacity(VALUE str)
Queries the capacity of the given string.
VALUE rb_str_cat2(VALUE, const char *)
Just another name of rb_str_cat_cstr.
VALUE rb_str_dup(VALUE str)
Duplicates a string.
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
VALUE rb_str_replace(VALUE dst, VALUE src)
Replaces the contents of the former object with the stringised contents of the latter.
VALUE rb_str_buf_cat2(VALUE, const char *)
Just another name of rb_str_cat_cstr.
VALUE rb_str_buf_append(VALUE dst, VALUE src)
Identical to rb_str_cat_cstr(), except it takes Ruby's string instead of C's.
void rb_str_set_len(VALUE str, long len)
Overwrites the length of the string.
VALUE rb_str_inspect(VALUE str)
Generates a "readable" version of the receiver.
int rb_str_cmp(VALUE lhs, VALUE rhs)
Compares two strings, as in strcmp(3).
VALUE rb_str_new(const char *ptr, long len)
Allocates an instance of rb_cString.
VALUE rb_str_dup_frozen(VALUE)
Just another name of rb_str_new_frozen.
VALUE rb_str_new_cstr(const char *ptr)
Identical to rb_str_new(), except it assumes the passed pointer is a pointer to a C string.
VALUE rb_str_resize(VALUE str, long len)
Overwrites the length of the string.
void rb_str_modify_expand(VALUE str, long capa)
Identical to rb_str_modify(), except it additionally expands the capacity of the receiver.
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
#define RUBY_UBF_IO
A special UBF for blocking IO operations.
VALUE rb_exec_recursive(VALUE(*f)(VALUE g, VALUE h, int r), VALUE g, VALUE h)
"Recursion" API entry point.
void rb_thread_wait_for(struct timeval time)
Identical to rb_thread_sleep(), except it takes struct timeval instead.
VALUE rb_time_nano_new(time_t sec, long nsec)
Identical to rb_time_new(), except it accepts the time in nanoseconds resolution.
struct timespec rb_time_timespec(VALUE time)
Identical to rb_time_timeval(), except for return type.
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
void rb_define_const(VALUE klass, const char *name, VALUE val)
Defines a Ruby level constant under a namespace.
VALUE rb_stat_new(const struct stat *st)
Constructs an instance of rb_cStat from the passed information.
VALUE rb_io_taint_check(VALUE obj)
#define GetOpenFile
This is an old name of RB_IO_POINTER.
#define FMODE_WRITABLE
The IO is opened for writing.
#define RB_IO_POINTER(obj, fp)
Queries the underlying IO pointer.
void rb_io_check_initialized(rb_io_t *fptr)
Asserts that the passed IO is initialised.
void rb_io_check_closed(rb_io_t *fptr)
This badly named function asserts that the passed IO is open.
void * rb_thread_call_without_gvl(void *(*func)(void *), void *data1, rb_unblock_function_t *ubf, void *data2)
Allows the passed function to run in parallel with other Ruby threads.
char * ruby_getcwd(void)
This is our own version of getcwd(3) that uses ruby_xmalloc() instead of system malloc (benefits our ...
#define strdup(s)
Just another name of ruby_strdup.
VALUE rb_sprintf(const char *fmt,...)
Ruby's extended sprintf(3).
VALUE rb_str_catf(VALUE dst, const char *fmt,...)
Identical to rb_sprintf(), except it renders the output to the specified object rather than creating ...
#define ALLOCA_N(type, n)
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
#define PRI_MODET_PREFIX
A rb_sprintf() format prefix to be used for a mode_t parameter.
#define NUM2MODET
Converts a C's mode_t into an instance of rb_cInteger.
#define MODET2NUM
Converts an instance of rb_cNumeric into C's mode_t.
#define OFFT2NUM
Converts a C's off_t into an instance of rb_cInteger.
#define NUM2OFFT
Converts an instance of rb_cNumeric into C's off_t.
const char * ruby_enc_find_basename(const char *name, long *baselen, long *alllen, rb_encoding *enc)
Our own encoding-aware version of basename(3).
char * rb_enc_path_end(const char *path, const char *end, rb_encoding *enc)
This just returns the passed end basically.
char * rb_enc_path_last_separator(const char *path, const char *end, rb_encoding *enc)
Returns the last path component.
char * rb_enc_path_next(const char *path, const char *end, rb_encoding *enc)
Returns a path component directly adjacent to the passed pointer.
char * rb_enc_path_skip_prefix(const char *path, const char *end, rb_encoding *enc)
Seeks for non-prefix part of a pathname.
const char * ruby_enc_find_extname(const char *name, long *len, rb_encoding *enc)
Our own encoding-aware version of extname.
#define RARRAY_LEN
Just another name of rb_array_len.
#define RARRAY_AREF(a, i)
#define DATA_PTR(obj)
Convenient getter macro.
#define RFILE(obj)
Convenient casting macro.
#define StringValue(v)
Ensures that the parameter object is a String.
#define StringValuePtr(v)
Identical to StringValue, except it returns a char*.
#define RSTRING_GETMEM(str, ptrvar, lenvar)
Convenient macro to obtain the contents and length at once.
static long RSTRING_LEN(VALUE str)
Queries the length of the string.
static char * RSTRING_PTR(VALUE str)
Queries the contents pointer of the string.
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
#define RTYPEDDATA_DATA(v)
Convenient getter macro.
#define RUBY_TYPED_DEFAULT_FREE
This is a value you can set to rb_data_type_struct::dfree.
#define TypedData_Get_Struct(obj, type, data_type, sval)
Obtains a C struct from inside of a wrapper Ruby object.
#define TypedData_Wrap_Struct(klass, data_type, sval)
Converts sval, a pointer to your struct, into a Ruby object.
VALUE rb_get_path(VALUE obj)
Converts an object to a path.
const char * rb_obj_classname(VALUE obj)
Queries the name of the class of the passed object.
#define FilePathValue(v)
Ensures that the parameter object is a path.
#define FilePathStringValue(v)
VALUE rb_get_path_no_checksafe(VALUE)
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
#define ANYARGS
Functions declared using this macro take arbitrary arguments, including void.
This is the struct that holds necessary info for a struct.
Ruby's IO, metadata and buffers.
VALUE pathv
pathname for file
int mode
mode flags: FMODE_XXXs
#define UIDT2NUM
Converts a C's uid_t into an instance of rb_cInteger.
#define NUM2UIDT
Converts an instance of rb_cNumeric into C's uid_t.
uintptr_t VALUE
Type that represents a Ruby object.
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.