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 readlink(f, t, l) rb_w32_ureadlink((f), (t), (l))
121# define rename(f, t) rb_w32_urename((f), (t))
123# define symlink(s, l) rb_w32_usymlink((s), (l))
131# define STAT(p, s) stat((p), (s))
134#if defined _WIN32 || defined __APPLE__
136# define TO_OSPATH(str) rb_str_encode_ospath(str)
139# define TO_OSPATH(str) (str)
143#if defined DOSISH || defined __CYGWIN__
148#if defined HAVE_REALPATH && defined __sun && defined __SVR4
161#include "internal/compilers.h"
162#include "internal/dir.h"
163#include "internal/error.h"
164#include "internal/file.h"
165#include "internal/io.h"
166#include "internal/load.h"
167#include "internal/object.h"
168#include "internal/process.h"
169#include "internal/thread.h"
170#include "internal/vm.h"
180file_path_convert(
VALUE name)
185 if (ENCINDEX_US_ASCII != fname_encidx &&
186 ENCINDEX_ASCII_8BIT != fname_encidx &&
187 (fs_encidx = rb_filesystem_encindex()) != fname_encidx &&
188 rb_default_internal_encoding() &&
192 rb_encoding *fname_encoding = rb_enc_from_index(fname_encidx);
193 rb_encoding *fs_encoding = rb_enc_from_index(fs_encidx);
201check_path_encoding(
VALUE str)
204 if (!rb_enc_asciicompat(enc)) {
212rb_get_path_check_to_string(
VALUE obj)
221 tmp = rb_check_funcall_default(obj, to_path, 0, 0, obj);
227rb_get_path_check_convert(
VALUE obj)
229 obj = file_path_convert(obj);
231 check_path_encoding(obj);
232 if (!rb_str_to_cstr(obj)) {
233 rb_raise(rb_eArgError,
"path name contains null byte");
242 return rb_get_path(obj);
248 return rb_get_path_check_convert(rb_get_path_check_to_string(obj));
256#if 0 && defined _WIN32
257 if (encidx == ENCINDEX_ASCII_8BIT) {
258 encidx = rb_filesystem_encindex();
261 if (encidx != ENCINDEX_ASCII_8BIT && encidx != ENCINDEX_UTF_8) {
271# define NORMALIZE_UTF8PATH 1
273# ifdef HAVE_WORKING_FORK
275rb_CFString_class_initialize_before_fork(
void)
298 const char small_str[] =
"/";
299 long len =
sizeof(small_str) - 1;
301 const CFAllocatorRef alloc = kCFAllocatorDefault;
302 CFStringRef s = CFStringCreateWithBytesNoCopy(alloc,
303 (
const UInt8 *)small_str,
304 len, kCFStringEncodingUTF8,
305 FALSE, kCFAllocatorNull);
306 CFMutableStringRef m = CFStringCreateMutableCopy(alloc,
len, s);
313rb_str_append_normalized_ospath(
VALUE str,
const char *ptr,
long len)
317 CFStringRef s = CFStringCreateWithBytesNoCopy(kCFAllocatorDefault,
318 (
const UInt8 *)ptr,
len,
319 kCFStringEncodingUTF8, FALSE,
321 CFMutableStringRef m = CFStringCreateMutableCopy(kCFAllocatorDefault,
len, s);
322 long oldlen = RSTRING_LEN(str);
324 CFStringNormalize(m, kCFStringNormalizationFormC);
325 all = CFRangeMake(0, CFStringGetLength(m));
326 CFStringGetBytes(m, all, kCFStringEncodingUTF8,
'?', FALSE, NULL, 0, &buflen);
328 CFStringGetBytes(m, all, kCFStringEncodingUTF8,
'?', FALSE,
329 (UInt8 *)(RSTRING_PTR(str) + oldlen), buflen, &buflen);
330 rb_str_set_len(str, oldlen + buflen);
337rb_str_normalize_ospath(
const char *ptr,
long len)
340 const char *e = ptr +
len;
344 rb_enc_associate(str, enc);
348 int r = rb_enc_precise_mbclen(p, e, enc);
351 static const char invalid[3] =
"\xEF\xBF\xBD";
352 rb_str_append_normalized_ospath(str, p1, p-p1);
353 rb_str_cat(str, invalid,
sizeof(invalid));
360 if ((0x2000 <= c && c <= 0x2FFF) || (0xF900 <= c && c <= 0xFAFF) ||
361 (0x2F800 <= c && c <= 0x2FAFF)) {
363 rb_str_append_normalized_ospath(str, p1, p-p1);
365 rb_str_cat(str, p, l);
374 rb_str_append_normalized_ospath(str, p1, p-p1);
381ignored_char_p(
const char *p,
const char *e,
rb_encoding *enc)
384 if (p+3 > e)
return 0;
385 switch ((
unsigned char)*p) {
387 switch ((
unsigned char)p[1]) {
389 c = (
unsigned char)p[2];
391 if (c >= 0x8c && c <= 0x8f)
return 3;
393 if (c >= 0xaa && c <= 0xae)
return 3;
396 c = (
unsigned char)p[2];
398 if (c >= 0xaa && c <= 0xaf)
return 3;
404 if ((
unsigned char)p[1] == 0xbb &&
405 (
unsigned char)p[2] == 0xbf)
412# define NORMALIZE_UTF8PATH 0
415#define apply2args(n) (rb_check_arity(argc, n, UNLIMITED_ARGUMENTS), argc-=n)
426 int (*func)(
const char *,
void *);
432no_gvl_apply2files(
void *ptr)
436 for (aa->i = 0; aa->i < aa->argc; aa->i++) {
437 if (aa->func(aa->fn[aa->i].ptr, aa->arg) < 0) {
446NORETURN(
static void utime_failed(
struct apply_arg *));
447static int utime_internal(
const char *,
void *);
451apply2files(
int (*func)(
const char *,
void *),
int argc,
VALUE *argv,
void *arg)
455 const long len = (long)(offsetof(
struct apply_arg, fn) + (size * argc));
463 for (aa->i = 0; aa->i < argc; aa->i++) {
464 VALUE path = rb_get_path(argv[aa->i]);
466 path = rb_str_encode_ospath(path);
467 aa->fn[aa->i].ptr = RSTRING_PTR(path);
468 aa->fn[aa->i].path = path;
474 if (func == utime_internal) {
478 rb_syserr_fail_path(aa->errnum, aa->fn[aa->i].path);
493 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
502stat_new_0(
VALUE klass,
const struct stat *st)
508 rb_st->initialized =
true;
514rb_stat_new(
const struct stat *st)
524 if (!rb_st->initialized) rb_raise(
rb_eTypeError,
"uninitialized File::Stat");
528static struct timespec stat_mtimespec(const struct stat *st);
549 struct timespec ts1 = stat_mtimespec(get_stat(self));
550 struct timespec ts2 = stat_mtimespec(get_stat(other));
551 if (ts1.tv_sec == ts2.tv_sec) {
552 if (ts1.tv_nsec == ts2.tv_nsec)
return INT2FIX(0);
553 if (ts1.tv_nsec < ts2.tv_nsec)
return INT2FIX(-1);
556 if (ts1.tv_sec < ts2.tv_sec)
return INT2FIX(-1);
562#define ST2UINT(val) ((val) & ~(~1UL << (sizeof(val) * CHAR_BIT - 1)))
565# define NUM2DEVT(v) NUM2UINT(v)
568# define DEVT2NUM(v) UINT2NUM(v)
570#ifndef PRI_DEVT_PREFIX
571# define PRI_DEVT_PREFIX ""
585rb_stat_dev(
VALUE self)
587#if SIZEOF_STRUCT_STAT_ST_DEV <= SIZEOF_DEV_T
588 return DEVT2NUM(get_stat(self)->st_dev);
589#elif SIZEOF_STRUCT_STAT_ST_DEV <= SIZEOF_LONG
590 return ULONG2NUM(get_stat(self)->st_dev);
592 return ULL2NUM(get_stat(self)->st_dev);
608rb_stat_dev_major(
VALUE self)
611 return UINT2NUM(major(get_stat(self)->st_dev));
629rb_stat_dev_minor(
VALUE self)
632 return UINT2NUM(minor(get_stat(self)->st_dev));
649rb_stat_ino(
VALUE self)
651#ifdef HAVE_STRUCT_STAT_ST_INOHIGH
653 return rb_integer_unpack(&get_stat(self)->st_ino, 2,
654 SIZEOF_STRUCT_STAT_ST_INO, 0,
657#elif SIZEOF_STRUCT_STAT_ST_INO > SIZEOF_LONG
658 return ULL2NUM(get_stat(self)->st_ino);
660 return ULONG2NUM(get_stat(self)->st_ino);
678rb_stat_mode(
VALUE self)
680 return UINT2NUM(ST2UINT(get_stat(self)->st_mode));
696rb_stat_nlink(
VALUE self)
699 const struct stat *ptr = get_stat(self);
701 if (
sizeof(ptr->st_nlink) <=
sizeof(
int)) {
702 return UINT2NUM((
unsigned)ptr->st_nlink);
704 else if (
sizeof(ptr->st_nlink) ==
sizeof(
long)) {
705 return ULONG2NUM((
unsigned long)ptr->st_nlink);
707 else if (
sizeof(ptr->st_nlink) ==
sizeof(
LONG_LONG)) {
711 rb_bug(
":FIXME: don't know what to do");
726rb_stat_uid(
VALUE self)
728 return UIDT2NUM(get_stat(self)->st_uid);
742rb_stat_gid(
VALUE self)
744 return GIDT2NUM(get_stat(self)->st_gid);
760rb_stat_rdev(
VALUE self)
762#ifdef HAVE_STRUCT_STAT_ST_RDEV
763# if SIZEOF_STRUCT_STAT_ST_RDEV <= SIZEOF_DEV_T
764 return DEVT2NUM(get_stat(self)->st_rdev);
765# elif SIZEOF_STRUCT_STAT_ST_RDEV <= SIZEOF_LONG
766 return ULONG2NUM(get_stat(self)->st_rdev);
768 return ULL2NUM(get_stat(self)->st_rdev);
787rb_stat_rdev_major(
VALUE self)
789#if defined(HAVE_STRUCT_STAT_ST_RDEV) && defined(major)
790 return UINT2NUM(major(get_stat(self)->st_rdev));
808rb_stat_rdev_minor(
VALUE self)
810#if defined(HAVE_STRUCT_STAT_ST_RDEV) && defined(minor)
811 return UINT2NUM(minor(get_stat(self)->st_rdev));
827rb_stat_size(
VALUE self)
829 return OFFT2NUM(get_stat(self)->st_size);
844rb_stat_blksize(
VALUE self)
846#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
847 return ULONG2NUM(get_stat(self)->st_blksize);
865rb_stat_blocks(
VALUE self)
867#ifdef HAVE_STRUCT_STAT_ST_BLOCKS
868# if SIZEOF_STRUCT_STAT_ST_BLOCKS > SIZEOF_LONG
869 return ULL2NUM(get_stat(self)->st_blocks);
871 return ULONG2NUM(get_stat(self)->st_blocks);
879stat_atimespec(const struct stat *st)
882 ts.tv_sec = st->st_atime;
883#if defined(HAVE_STRUCT_STAT_ST_ATIM)
884 ts.tv_nsec = st->st_atim.tv_nsec;
885#elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC)
886 ts.tv_nsec = st->st_atimespec.tv_nsec;
887#elif defined(HAVE_STRUCT_STAT_ST_ATIMENSEC)
888 ts.tv_nsec = (long)st->st_atimensec;
902stat_atime(
const struct stat *st)
904 return stat_time(stat_atimespec(st));
908stat_mtimespec(const struct stat *st)
911 ts.tv_sec = st->st_mtime;
912#if defined(HAVE_STRUCT_STAT_ST_MTIM)
913 ts.tv_nsec = st->st_mtim.tv_nsec;
914#elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC)
915 ts.tv_nsec = st->st_mtimespec.tv_nsec;
916#elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC)
917 ts.tv_nsec = (long)st->st_mtimensec;
925stat_mtime(
const struct stat *st)
927 return stat_time(stat_mtimespec(st));
931stat_ctimespec(const struct stat *st)
934 ts.tv_sec = st->st_ctime;
935#if defined(HAVE_STRUCT_STAT_ST_CTIM)
936 ts.tv_nsec = st->st_ctim.tv_nsec;
937#elif defined(HAVE_STRUCT_STAT_ST_CTIMESPEC)
938 ts.tv_nsec = st->st_ctimespec.tv_nsec;
939#elif defined(HAVE_STRUCT_STAT_ST_CTIMENSEC)
940 ts.tv_nsec = (long)st->st_ctimensec;
948stat_ctime(
const struct stat *st)
950 return stat_time(stat_ctimespec(st));
953#define HAVE_STAT_BIRTHTIME
954#if defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC)
955typedef struct stat statx_data;
957stat_birthtime(
const struct stat *st)
959 const struct timespec *ts = &st->st_birthtimespec;
963typedef struct stat statx_data;
964# define stat_birthtime stat_ctime
966# undef HAVE_STAT_BIRTHTIME
981rb_stat_atime(
VALUE self)
983 return stat_atime(get_stat(self));
997rb_stat_mtime(
VALUE self)
999 return stat_mtime(get_stat(self));
1017rb_stat_ctime(
VALUE self)
1019 return stat_ctime(get_stat(self));
1022#if defined(HAVE_STAT_BIRTHTIME)
1046rb_stat_birthtime(
VALUE self)
1048 return stat_birthtime(get_stat(self));
1051# define rb_stat_birthtime rb_f_notimplement
1070rb_stat_inspect(
VALUE self)
1074 static const struct {
1078 {
"dev", rb_stat_dev},
1079 {
"ino", rb_stat_ino},
1080 {
"mode", rb_stat_mode},
1081 {
"nlink", rb_stat_nlink},
1082 {
"uid", rb_stat_uid},
1083 {
"gid", rb_stat_gid},
1084 {
"rdev", rb_stat_rdev},
1085 {
"size", rb_stat_size},
1086 {
"blksize", rb_stat_blksize},
1087 {
"blocks", rb_stat_blocks},
1088 {
"atime", rb_stat_atime},
1089 {
"mtime", rb_stat_mtime},
1090 {
"ctime", rb_stat_ctime},
1091#if defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC)
1092 {
"birthtime", rb_stat_birthtime},
1098 if (!rb_st->initialized) {
1106 for (i = 0; i <
sizeof(member)/
sizeof(member[0]); i++) {
1114 v = (*member[i].func)(self);
1116 rb_str_catf(str,
"0%lo", (
unsigned long)
NUM2ULONG(v));
1118 else if (i == 0 || i == 6) {
1119 rb_str_catf(str,
"0x%"PRI_DEVT_PREFIX
"x", NUM2DEVT(v));
1139no_gvl_fstat(
void *data)
1142 return (
VALUE)fstat(arg->file.fd, arg->st);
1146fstat_without_gvl(
int fd,
struct stat *st)
1153 return (
int)(
VALUE)rb_thread_io_blocking_region(no_gvl_fstat, &data, fd);
1157no_gvl_stat(
void * data)
1160 return (
void *)(
VALUE)STAT(arg->file.path, arg->st);
1164stat_without_gvl(
const char *path,
struct stat *st)
1168 data.file.path = path;
1175#if !defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC) && \
1176 defined(HAVE_STRUCT_STATX_STX_BTIME)
1179# ifdef HAVE_SYSCALL_H
1180# include <syscall.h>
1181# elif defined HAVE_SYS_SYSCALL_H
1182# include <sys/syscall.h>
1184# if defined __linux__
1185# include <linux/stat.h>
1187statx(
int dirfd,
const char *pathname,
int flags,
1188 unsigned int mask,
struct statx *statxbuf)
1190 return (
int)syscall(__NR_statx, dirfd, pathname, flags, mask, statxbuf);
1195typedef struct no_gvl_statx_data {
1204io_blocking_statx(
void *data)
1206 no_gvl_statx_data *arg = data;
1207 return (
VALUE)statx(arg->fd, arg->path, arg->flags, arg->mask, arg->stx);
1211no_gvl_statx(
void *data)
1213 return (
void *)io_blocking_statx(data);
1217statx_without_gvl(
const char *path,
struct statx *stx,
unsigned int mask)
1219 no_gvl_statx_data data = {stx, AT_FDCWD, path, 0, mask};
1227fstatx_without_gvl(
int fd,
struct statx *stx,
unsigned int mask)
1229 no_gvl_statx_data data = {stx, fd,
"", AT_EMPTY_PATH, mask};
1232 return (
int)rb_thread_io_blocking_region(io_blocking_statx, &data, fd);
1236rb_statx(
VALUE file,
struct statx *stx,
unsigned int mask)
1241 tmp = rb_check_convert_type_with_id(file,
T_FILE,
"IO", idTo_io);
1245 result = fstatx_without_gvl(fptr->
fd, stx, mask);
1250 file = rb_str_encode_ospath(file);
1251 result = statx_without_gvl(RSTRING_PTR(file), stx, mask);
1257# define statx_has_birthtime(st) ((st)->stx_mask & STATX_BTIME)
1259NORETURN(
static void statx_notimplement(
const char *field_name));
1264statx_notimplement(
const char *field_name)
1267 "%s is unimplemented on this filesystem",
1272statx_birthtime(
const struct statx *stx,
VALUE fname)
1274 if (!statx_has_birthtime(stx)) {
1276 statx_notimplement(
"birthtime");
1278 return rb_time_nano_new((time_t)stx->stx_btime.tv_sec, stx->stx_btime.tv_nsec);
1281typedef struct statx statx_data;
1282# define HAVE_STAT_BIRTHTIME
1284#elif defined(HAVE_STAT_BIRTHTIME)
1285# define statx_without_gvl(path, st, mask) stat_without_gvl(path, st)
1286# define fstatx_without_gvl(fd, st, mask) fstat_without_gvl(fd, st)
1287# define statx_birthtime(st, fname) stat_birthtime(st)
1288# define statx_has_birthtime(st) 1
1289# define rb_statx(file, st, mask) rb_stat(file, st)
1291# define statx_has_birthtime(st) 0
1301 tmp = rb_check_convert_type_with_id(file,
T_FILE,
"IO", idTo_io);
1306 result = fstat_without_gvl(fptr->
fd, st);
1311 file = rb_str_encode_ospath(file);
1312 result = stat_without_gvl(RSTRING_PTR(file), st);
1334 fname = rb_str_encode_ospath(fname);
1335 if (stat_without_gvl(RSTRING_PTR(fname), &st) < 0) {
1336 rb_sys_fail_path(fname);
1338 return rb_stat_new(&st);
1357rb_io_stat(
VALUE obj)
1363 if (fstat(fptr->
fd, &st) == -1) {
1364 rb_sys_fail_path(fptr->
pathv);
1366 return rb_stat_new(&st);
1371no_gvl_lstat(
void *ptr)
1374 return (
void *)(
VALUE)lstat(arg->file.path, arg->st);
1378lstat_without_gvl(
const char *path,
struct stat *st)
1382 data.file.path = path;
1410 fname = rb_str_encode_ospath(fname);
1412 rb_sys_fail_path(fname);
1414 return rb_stat_new(&st);
1416 return rb_file_s_stat(klass, fname);
1435rb_file_lstat(
VALUE obj)
1444 path = rb_str_encode_ospath(fptr->
pathv);
1445 if (lstat_without_gvl(RSTRING_PTR(path), &st) == -1) {
1446 rb_sys_fail_path(fptr->
pathv);
1448 return rb_stat_new(&st);
1450 return rb_io_stat(obj);
1455rb_group_member(GETGROUPS_T gid)
1457#if defined(_WIN32) || !defined(HAVE_GETGROUPS)
1466 if (getgid() == gid || getegid() == gid)
1469 groups = getgroups(0, NULL);
1470 gary =
ALLOCV_N(GETGROUPS_T, v, groups);
1471 anum = getgroups(groups, gary);
1472 while (--anum >= 0) {
1473 if (gary[anum] == gid) {
1486# define S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH)
1489#if defined(S_IXGRP) && !defined(_WIN32) && !defined(__CYGWIN__)
1490#define USE_GETEUID 1
1495eaccess(
const char *path,
int mode)
1504 if (getuid() == euid && getgid() == getegid())
1505 return access(path, mode);
1507 if (STAT(path, &st) < 0)
1517 if (st.st_mode & S_IXUGO)
1523 if (st.st_uid == euid)
1525 else if (rb_group_member(st.st_gid))
1528 if ((
int)(st.st_mode & mode) == mode)
return 0;
1532 return access(path, mode);
1543nogvl_eaccess(
void *ptr)
1547 return (
void *)(
VALUE)eaccess(aa->path, aa->mode);
1551rb_eaccess(
VALUE fname,
int mode)
1556 fname = rb_str_encode_ospath(fname);
1565nogvl_access(
void *ptr)
1569 return (
void *)(
VALUE)access(aa->path, aa->mode);
1573rb_access(
VALUE fname,
int mode)
1578 fname = rb_str_encode_ospath(fname);
1618# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
1624 if (S_ISDIR(st.st_mode))
return Qtrue;
1645# define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
1651 if (S_ISFIFO(st.st_mode))
return Qtrue;
1674# define S_ISLNK(m) _S_ISLNK(m)
1677# define S_ISLNK(m) (((m) & S_IFMT) == _S_IFLNK)
1680# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
1690 fname = rb_str_encode_ospath(fname);
1692 if (S_ISLNK(st.st_mode))
return Qtrue;
1715# define S_ISSOCK(m) _S_ISSOCK(m)
1718# define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
1721# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
1731 if (S_ISSOCK(st.st_mode))
return Qtrue;
1753# define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
1755# define S_ISBLK(m) (0)
1763 if (S_ISBLK(st.st_mode))
return Qtrue;
1783# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
1789 if (S_ISCHR(st.st_mode))
return Qtrue;
1828 return RBOOL(rb_eaccess(fname, R_OK) >= 0);
1843rb_file_readable_real_p(
VALUE obj,
VALUE fname)
1845 return RBOOL(rb_access(fname, R_OK) >= 0);
1849# define S_IRUGO (S_IRUSR | S_IRGRP | S_IROTH)
1853# define S_IWUGO (S_IWUSR | S_IWGRP | S_IWOTH)
1873rb_file_world_readable_p(
VALUE obj,
VALUE fname)
1879 if ((st.st_mode & (S_IROTH)) == S_IROTH) {
1880 return UINT2NUM(st.st_mode & (S_IRUGO|S_IWUGO|S_IXUGO));
1900 return RBOOL(rb_eaccess(fname, W_OK) >= 0);
1915rb_file_writable_real_p(
VALUE obj,
VALUE fname)
1917 return RBOOL(rb_access(fname, W_OK) >= 0);
1937rb_file_world_writable_p(
VALUE obj,
VALUE fname)
1943 if ((st.st_mode & (S_IWOTH)) == S_IWOTH) {
1944 return UINT2NUM(st.st_mode & (S_IRUGO|S_IWUGO|S_IXUGO));
1968 return RBOOL(rb_eaccess(fname, X_OK) >= 0);
1987rb_file_executable_real_p(
VALUE obj,
VALUE fname)
1989 return RBOOL(rb_access(fname, X_OK) >= 0);
1993# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
2014 return RBOOL(S_ISREG(st.st_mode));
2033 return RBOOL(st.st_size == 0);
2052 if (st.st_size == 0)
return Qnil;
2073 return RBOOL(st.st_uid == geteuid());
2082 return RBOOL(st.st_uid == getuid());
2103 if (rb_group_member(st.st_gid))
return Qtrue;
2108#if defined(S_ISUID) || defined(S_ISGID) || defined(S_ISVTX)
2110check3rdbyte(
VALUE fname,
int mode)
2115 return RBOOL(st.st_mode & mode);
2132 return check3rdbyte(fname, S_ISUID);
2151 return check3rdbyte(fname, S_ISGID);
2170 return check3rdbyte(fname, S_ISVTX);
2199 struct stat st1, st2;
2203 if (st1.st_dev != st2.st_dev)
return Qfalse;
2204 if (st1.st_ino != st2.st_ino)
return Qfalse;
2208 return rb_w32_file_identical_p(fname1, fname2);
2226 if (
rb_stat(fname, &st) < 0) {
2229 rb_syserr_fail_path(e, fname);
2235rb_file_ftype(
const struct stat *st)
2239 if (S_ISREG(st->st_mode)) {
2242 else if (S_ISDIR(st->st_mode)) {
2245 else if (S_ISCHR(st->st_mode)) {
2246 t =
"characterSpecial";
2249 else if (S_ISBLK(st->st_mode)) {
2254 else if (S_ISFIFO(st->st_mode)) {
2259 else if (S_ISLNK(st->st_mode)) {
2264 else if (S_ISSOCK(st->st_mode)) {
2296 fname = rb_str_encode_ospath(fname);
2298 rb_sys_fail_path(fname);
2301 return rb_file_ftype(&st);
2321 if (
rb_stat(fname, &st) < 0) {
2324 rb_syserr_fail_path(e, fname);
2326 return stat_atime(&st);
2341rb_file_atime(
VALUE obj)
2347 if (fstat(fptr->
fd, &st) == -1) {
2348 rb_sys_fail_path(fptr->
pathv);
2350 return stat_atime(&st);
2370 if (
rb_stat(fname, &st) < 0) {
2373 rb_syserr_fail_path(e, fname);
2375 return stat_mtime(&st);
2389rb_file_mtime(
VALUE obj)
2395 if (fstat(fptr->
fd, &st) == -1) {
2396 rb_sys_fail_path(fptr->
pathv);
2398 return stat_mtime(&st);
2422 if (
rb_stat(fname, &st) < 0) {
2425 rb_syserr_fail_path(e, fname);
2427 return stat_ctime(&st);
2444rb_file_ctime(
VALUE obj)
2450 if (fstat(fptr->
fd, &st) == -1) {
2451 rb_sys_fail_path(fptr->
pathv);
2453 return stat_ctime(&st);
2456#if defined(HAVE_STAT_BIRTHTIME)
2471RUBY_FUNC_EXPORTED
VALUE
2476 if (rb_statx(fname, &st, STATX_BTIME) < 0) {
2479 rb_syserr_fail_path(e, fname);
2481 return statx_birthtime(&st, fname);
2484# define rb_file_s_birthtime rb_f_notimplement
2487#if defined(HAVE_STAT_BIRTHTIME)
2501rb_file_birthtime(
VALUE obj)
2507 if (fstatx_without_gvl(fptr->
fd, &st, STATX_BTIME) == -1) {
2508 rb_sys_fail_path(fptr->
pathv);
2510 return statx_birthtime(&st, fptr->
pathv);
2513# define rb_file_birthtime rb_f_notimplement
2519 if (RB_TYPE_P(file,
T_FILE)) {
2525 rb_io_flush_raw(file, 0);
2528 if (fstat(fptr->
fd, &st) == -1) {
2529 rb_sys_fail_path(fptr->
pathv);
2550file_size(
VALUE self)
2552 return OFFT2NUM(rb_file_size(self));
2556chmod_internal(
const char *path,
void *mode)
2558 return chmod(path, *(mode_t *)mode);
2582 return apply2files(chmod_internal, argc, argv, &mode);
2603#if !defined HAVE_FCHMOD || !HAVE_FCHMOD
2611 if (fchmod(fptr->
fd, mode) == -1) {
2612 if (HAVE_FCHMOD ||
errno != ENOSYS)
2613 rb_sys_fail_path(fptr->
pathv);
2616 if (!HAVE_FCHMOD)
return INT2FIX(0);
2619#if !defined HAVE_FCHMOD || !HAVE_FCHMOD
2621 path = rb_str_encode_ospath(fptr->
pathv);
2622 if (chmod(RSTRING_PTR(path), mode) == -1)
2623 rb_sys_fail_path(fptr->
pathv);
2629#if defined(HAVE_LCHMOD)
2631lchmod_internal(
const char *path,
void *mode)
2633 return lchmod(path, *(mode_t *)mode);
2654 return apply2files(lchmod_internal, argc, argv, &mode);
2657#define rb_file_s_lchmod rb_f_notimplement
2660static inline rb_uid_t
2664 return (rb_uid_t)-1;
2669static inline rb_gid_t
2673 return (rb_gid_t)-1;
2684chown_internal(
const char *path,
void *arg)
2687 return chown(path, args->owner, args->group);
2711 arg.owner = to_uid(*argv++);
2712 arg.group = to_gid(*argv++);
2714 return apply2files(chown_internal, argc, argv, &arg);
2747 path = rb_str_encode_ospath(fptr->
pathv);
2748 if (chown(RSTRING_PTR(path), o, g) == -1)
2749 rb_sys_fail_path(fptr->
pathv);
2751 if (fchown(fptr->
fd, o, g) == -1)
2752 rb_sys_fail_path(fptr->
pathv);
2758#if defined(HAVE_LCHOWN)
2760lchown_internal(
const char *path,
void *arg)
2763 return lchown(path, args->owner, args->group);
2783 arg.owner = to_uid(*argv++);
2784 arg.group = to_gid(*argv++);
2786 return apply2files(lchown_internal, argc, argv, &arg);
2789#define rb_file_s_lchown rb_f_notimplement
2799NORETURN(
static void utime_failed(
struct apply_arg *));
2805 VALUE path = aa->fn[aa->i].path;
2808 if (ua->tsp && e == EINVAL) {
2811 VALUE atime = ua->atime;
2812 VALUE mtime = ua->mtime;
2814 if (!
NIL_P(atime)) {
2817 if (!
NIL_P(mtime) && mtime != atime && !
rb_equal(atime, mtime)) {
2820 if (
NIL_P(a)) e[0] = m;
2829 if (!d) e[0] = rb_str_dup(e[0]);
2836 rb_syserr_fail_path(e, path);
2840#if defined(HAVE_UTIMES)
2842# if !defined(HAVE_UTIMENSAT)
2844# elif defined(__APPLE__) && \
2845 (!defined(MAC_OS_X_VERSION_13_0) || (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_13_0))
2847# if defined(__has_attribute) && __has_attribute(availability)
2848typedef int utimensat_func(
int,
const char *,
const struct timespec [2],
int);
2852static
inline utimensat_func *
2859# define utimensat rb_utimensat()
2866utime_internal(
const char *path,
void *arg)
2869 const struct timespec *tsp = v->tsp;
2870 struct timeval tvbuf[2], *tvp = NULL;
2872#if defined(HAVE_UTIMENSAT)
2873# if defined(__APPLE__)
2874 const int try_utimensat = utimensat != NULL;
2875 const int try_utimensat_follow = utimensat != NULL;
2877# define TRY_UTIMENSAT 1
2878 static int try_utimensat = 1;
2879# ifdef AT_SYMLINK_NOFOLLOW
2880 static int try_utimensat_follow = 1;
2882 const int try_utimensat_follow = 0;
2887 if (v->follow ? try_utimensat_follow : try_utimensat) {
2888# ifdef AT_SYMLINK_NOFOLLOW
2890 flags = AT_SYMLINK_NOFOLLOW;
2894 int result = utimensat(AT_FDCWD, path, tsp, flags);
2895# ifdef TRY_UTIMENSAT
2896 if (result < 0 &&
errno == ENOSYS) {
2897# ifdef AT_SYMLINK_NOFOLLOW
2898 try_utimensat_follow = 0;
2910 tvbuf[0].tv_sec = tsp[0].tv_sec;
2911 tvbuf[0].tv_usec = (int)(tsp[0].tv_nsec / 1000);
2912 tvbuf[1].tv_sec = tsp[1].tv_sec;
2913 tvbuf[1].tv_usec = (int)(tsp[1].tv_nsec / 1000);
2917 if (v->follow)
return lutimes(path, tvp);
2919 return utimes(path, tvp);
2924#if !defined HAVE_UTIME_H && !defined HAVE_SYS_UTIME_H
2932utime_internal(
const char *path,
void *arg)
2935 const struct timespec *tsp = v->tsp;
2936 struct utimbuf utbuf, *utp = NULL;
2938 utbuf.actime = tsp[0].tv_sec;
2939 utbuf.modtime = tsp[1].tv_sec;
2942 return utime(path, utp);
2947utime_internal_i(
int argc,
VALUE *argv,
int follow)
2950 struct timespec tss[2], *tsp = NULL;
2953 args.atime = *argv++;
2954 args.mtime = *argv++;
2956 args.follow = follow;
2958 if (!
NIL_P(args.atime) || !
NIL_P(args.mtime)) {
2961 if (args.atime == args.mtime)
2968 return apply2files(utime_internal, argc, argv, &args);
2985 return utime_internal_i(argc, argv, FALSE);
2988#if defined(HAVE_UTIMES) && (defined(HAVE_LUTIMES) || (defined(HAVE_UTIMENSAT) && defined(AT_SYMLINK_NOFOLLOW)))
3004 return utime_internal_i(argc, argv, TRUE);
3007#define rb_file_s_lutime rb_f_notimplement
3010#ifdef RUBY_FUNCTION_NAME_STRING
3011# define syserr_fail2(e, s1, s2) syserr_fail2_in(RUBY_FUNCTION_NAME_STRING, e, s1, s2)
3013# define syserr_fail2_in(func, e, s1, s2) syserr_fail2(e, s1, s2)
3015#define sys_fail2(s1, s2) syserr_fail2(errno, s1, s2)
3016NORETURN(
static void syserr_fail2_in(
const char *,
int,
VALUE,
VALUE));
3018syserr_fail2_in(
const char *func,
int e,
VALUE s1,
VALUE s2)
3022 const int max_pathlen = MAX_PATH;
3024 const int max_pathlen = MAXPATHLEN;
3035#ifdef RUBY_FUNCTION_NAME_STRING
3036 rb_syserr_fail_path_in(func, e, str);
3038 rb_syserr_fail_path(e, str);
3060 from = rb_str_encode_ospath(from);
3061 to = rb_str_encode_ospath(to);
3064 sys_fail2(from, to);
3069#define rb_file_s_link rb_f_notimplement
3090 from = rb_str_encode_ospath(from);
3091 to = rb_str_encode_ospath(to);
3094 sys_fail2(from, to);
3099#define rb_file_s_symlink rb_f_notimplement
3117 return rb_readlink(path, rb_filesystem_encoding());
3120struct readlink_arg {
3127nogvl_readlink(
void *ptr)
3129 struct readlink_arg *ra = ptr;
3131 return (
void *)(
VALUE)readlink(ra->path, ra->buf, ra->size);
3135readlink_without_gvl(
VALUE path,
VALUE buf,
size_t size)
3137 struct readlink_arg ra;
3139 ra.path = RSTRING_PTR(path);
3140 ra.buf = RSTRING_PTR(buf);
3155 path = rb_str_encode_ospath(path);
3156 v = rb_enc_str_new(0, size, enc);
3157 while ((rv = readlink_without_gvl(path, v, size)) == size
3159 || (rv < 0 &&
errno == ERANGE)
3164 rb_str_set_len(v, size);
3168 rb_str_resize(v, 0);
3169 rb_syserr_fail_path(e, path);
3171 rb_str_resize(v, rv);
3176#define rb_file_s_readlink rb_f_notimplement
3180unlink_internal(
const char *path,
void *arg)
3182 return unlink(path);
3202rb_file_s_unlink(
int argc,
VALUE *argv,
VALUE klass)
3204 return apply2files(unlink_internal, argc, argv, 0);
3213no_gvl_rename(
void *ptr)
3217 return (
void *)(
VALUE)rename(ra->src, ra->dst);
3238 f = rb_str_encode_ospath(from);
3239 t = rb_str_encode_ospath(to);
3242#if defined __CYGWIN__
3251 if (chmod(ra.dst, 0666) == 0 &&
3252 unlink(ra.dst) == 0 &&
3253 rename(ra.src, ra.dst) == 0)
3257 syserr_fail2(e, from, to);
3292 rb_error_arity(argc, 0, 1);
3300#if defined __CYGWIN__ || defined DOSISH
3302#define DOSISH_DRIVE_LETTER
3303#define FILE_ALT_SEPARATOR '\\'
3305#ifdef FILE_ALT_SEPARATOR
3306#define isdirsep(x) ((x) == '/' || (x) == FILE_ALT_SEPARATOR)
3308static const char file_alt_separator[] = {FILE_ALT_SEPARATOR,
'\0'};
3311#define isdirsep(x) ((x) == '/')
3324# define USE_NTFS_ADS 1
3326# define USE_NTFS_ADS 0
3331#define istrailinggarbage(x) ((x) == '.' || (x) == ' ')
3333#define istrailinggarbage(x) 0
3337# define isADS(x) ((x) == ':')
3342#define Next(p, e, enc) ((p) + rb_enc_mbclen((p), (e), (enc)))
3343#define Inc(p, e, enc) ((p) = Next((p), (e), (enc)))
3345#if defined(DOSISH_UNC)
3346#define has_unc(buf) (isdirsep((buf)[0]) && isdirsep((buf)[1]))
3348#define has_unc(buf) 0
3351#ifdef DOSISH_DRIVE_LETTER
3353has_drive_letter(
const char *buf)
3355 if (
ISALPHA(buf[0]) && buf[1] ==
':') {
3368 char *drvcwd, *oldcwd;
3379 if (chdir(drive) == 0) {
3392not_same_drive(
VALUE path,
int drive)
3394 const char *p = RSTRING_PTR(path);
3395 if (RSTRING_LEN(path) < 2)
return 0;
3396 if (has_drive_letter(p)) {
3407skiproot(
const char *path,
const char *end,
rb_encoding *enc)
3409#ifdef DOSISH_DRIVE_LETTER
3410 if (path + 2 <= end && has_drive_letter(path)) path += 2;
3412 while (path < end && isdirsep(*path)) path++;
3413 return (
char *)path;
3416#define nextdirsep rb_enc_path_next
3420 while (s < e && !isdirsep(*s)) {
3426#if defined(DOSISH_UNC) || defined(DOSISH_DRIVE_LETTER)
3427#define skipprefix rb_enc_path_skip_prefix
3429#define skipprefix(path, end, enc) (path)
3432rb_enc_path_skip_prefix(
const char *path,
const char *end,
rb_encoding *enc)
3434#if defined(DOSISH_UNC) || defined(DOSISH_DRIVE_LETTER)
3436 if (path + 2 <= end && isdirsep(path[0]) && isdirsep(path[1])) {
3438 while (path < end && isdirsep(*path)) path++;
3439 if ((path = rb_enc_path_next(path, end, enc)) < end && path[0] && path[1] && !isdirsep(path[1]))
3440 path = rb_enc_path_next(path + 1, end, enc);
3441 return (
char *)path;
3444#ifdef DOSISH_DRIVE_LETTER
3445 if (has_drive_letter(path))
3446 return (
char *)(path + 2);
3449 return (
char *)path;
3453skipprefixroot(
const char *path,
const char *end,
rb_encoding *enc)
3455#if defined(DOSISH_UNC) || defined(DOSISH_DRIVE_LETTER)
3456 char *p = skipprefix(path, end, enc);
3457 while (isdirsep(*p)) p++;
3460 return skiproot(path, end, enc);
3464#define strrdirsep rb_enc_path_last_separator
3466rb_enc_path_last_separator(
const char *path,
const char *end,
rb_encoding *enc)
3469 while (path < end) {
3470 if (isdirsep(*path)) {
3471 const char *tmp = path++;
3472 while (path < end && isdirsep(*path)) path++;
3473 if (path >= end)
break;
3477 Inc(path, end, enc);
3484chompdirsep(
const char *path,
const char *end,
rb_encoding *enc)
3486 while (path < end) {
3487 if (isdirsep(*path)) {
3488 const char *last = path++;
3489 while (path < end && isdirsep(*path)) path++;
3490 if (path >= end)
return (
char *)last;
3493 Inc(path, end, enc);
3496 return (
char *)path;
3502 if (path < end && isdirsep(*path)) path++;
3503 return chompdirsep(path, end, enc);
3510 int encidx = rb_enc_to_index(enc);
3511 if (encidx == ENCINDEX_US_ASCII) {
3512 encidx = rb_enc_get_index(path1);
3513 if (encidx == ENCINDEX_US_ASCII)
3514 encidx = rb_enc_get_index(path2);
3515 enc = rb_enc_from_index(encidx);
3522ntfs_tail(
const char *path,
const char *end,
rb_encoding *enc)
3524 while (path < end && *path ==
'.') path++;
3525 while (path < end && !isADS(*path)) {
3526 if (istrailinggarbage(*path)) {
3527 const char *last = path++;
3528 while (path < end && istrailinggarbage(*path)) path++;
3529 if (path >= end || isADS(*path))
return (
char *)last;
3531 else if (isdirsep(*path)) {
3532 const char *last = path++;
3533 while (path < end && isdirsep(*path)) path++;
3534 if (path >= end)
return (
char *)last;
3535 if (isADS(*path)) path++;
3538 Inc(path, end, enc);
3541 return (
char *)path;
3545#define BUFCHECK(cond) do {\
3548 do {buflen *= 2;} while (cond);\
3549 rb_str_resize(result, buflen);\
3550 buf = RSTRING_PTR(result);\
3552 pend = buf + buflen;\
3557 p = buf = RSTRING_PTR(result),\
3558 buflen = RSTRING_LEN(result),\
3562# define SKIPPATHSEP(p) ((*(p)) ? 1 : 0)
3564# define SKIPPATHSEP(p) 1
3567#define BUFCOPY(srcptr, srclen) do { \
3568 const int skip = SKIPPATHSEP(p); \
3569 rb_str_set_len(result, p-buf+skip); \
3570 BUFCHECK(bdiff + ((srclen)+skip) >= buflen); \
3572 memcpy(p, (srcptr), (srclen)); \
3576#define WITH_ROOTDIFF(stmt) do { \
3577 long rootdiff = root - buf; \
3579 root = buf + rootdiff; \
3583copy_home_path(
VALUE result,
const char *dir)
3586#if defined DOSISH || defined __CYGWIN__
3593 dirlen = strlen(dir);
3594 rb_str_resize(result, dirlen);
3595 memcpy(buf = RSTRING_PTR(result), dir, dirlen);
3596 encidx = rb_filesystem_encindex();
3597 rb_enc_associate_index(result, encidx);
3598#if defined DOSISH || defined __CYGWIN__
3599 enc = rb_enc_from_index(encidx);
3600 for (bend = (p = buf) + dirlen; p < bend; Inc(p, bend, enc)) {
3613 struct passwd *pwPtr;
3615 extern char *getlogin(
void);
3616 const char *pwPtr = 0;
3617 # define endpwent() ((void)0)
3619 const char *dir, *username = RSTRING_PTR(user);
3631 pwPtr = getpwnam(username);
3633 if (strcasecmp(username, getlogin()) == 0)
3634 dir = pwPtr = getenv(
"HOME");
3638 rb_raise(rb_eArgError,
"user %"PRIsVALUE
" doesn't exist", user);
3641 dir = pwPtr->pw_dir;
3643 copy_home_path(result, dir);
3650rb_default_home_dir(
VALUE result)
3652 const char *dir = getenv(
"HOME");
3654#if defined HAVE_PWD_H
3668 VALUE login_name = rb_getlogin();
3670# if !defined(HAVE_GETPWUID_R) && !defined(HAVE_GETPWUID)
3675 if (
NIL_P(login_name)) {
3676 rb_raise(rb_eArgError,
"couldn't find login name -- expanding `~'");
3680 VALUE pw_dir = rb_getpwdirnam_for_login(login_name);
3681 if (
NIL_P(pw_dir)) {
3682 pw_dir = rb_getpwdiruid();
3683 if (
NIL_P(pw_dir)) {
3684 rb_raise(rb_eArgError,
"couldn't find home for uid `%ld'", (
long)getuid());
3689 copy_home_path(result, RSTRING_PTR(pw_dir));
3690 rb_str_resize(pw_dir, 0);
3695 rb_raise(rb_eArgError,
"couldn't find HOME environment -- expanding `~'");
3697 return copy_home_path(result, dir);
3703#if NORMALIZE_UTF8PATH
3704 VALUE path = rb_str_normalize_ospath(ptr,
len);
3705 rb_enc_associate(path, fsenc);
3708 return rb_enc_str_new(ptr,
len, fsenc);
3715 char *buf, *cwdp = dir;
3719 if (NORMALIZE_UTF8PATH || *enc != fsenc) {
3720 rb_encoding *direnc = fs_enc_check(fname, dirname = ospath_new(dir, dirlen, fsenc));
3721 if (direnc != fsenc) {
3725 else if (NORMALIZE_UTF8PATH) {
3730 do {buflen *= 2;}
while (dirlen > buflen);
3731 rb_str_resize(result, buflen);
3732 buf = RSTRING_PTR(result);
3733 memcpy(buf, cwdp, dirlen);
3735 if (!
NIL_P(dirname)) rb_str_resize(dirname, 0);
3736 rb_enc_associate(result, *enc);
3737 return buf + dirlen;
3741rb_file_expand_path_internal(
VALUE fname,
VALUE dname,
int abs_mode,
int long_name,
VALUE result)
3743 const char *s, *b, *fend;
3744 char *buf, *p, *pend, *root;
3745 size_t buflen, bdiff;
3746 rb_encoding *enc, *fsenc = rb_filesystem_encoding();
3749 fend = s + RSTRING_LEN(fname);
3750 enc = rb_enc_get(fname);
3753 if (s[0] ==
'~' && abs_mode == 0) {
3755 if (isdirsep(s[1]) || s[1] ==
'\0') {
3758 rb_str_set_len(result, 0);
3760 rb_default_home_dir(result);
3763 s = nextdirsep(b = s, fend, enc);
3766 BUFCHECK(bdiff + userlen >= buflen);
3767 memcpy(p, b, userlen);
3769 rb_str_set_len(result, userlen);
3770 rb_enc_associate(result, enc);
3771 rb_home_dir_of(result, result);
3775 if (!rb_is_absolute_path(RSTRING_PTR(result))) {
3777 rb_enc_raise(enc, rb_eArgError,
"non-absolute home of %.*s%.0"PRIsVALUE,
3778 (
int)userlen, b, fname);
3781 rb_raise(rb_eArgError,
"non-absolute home");
3787#ifdef DOSISH_DRIVE_LETTER
3789 else if (has_drive_letter(s)) {
3790 if (isdirsep(s[2])) {
3793 BUFCHECK(bdiff + 2 >= buflen);
3797 rb_enc_copy(result, fname);
3802 if (!
NIL_P(dname) && !not_same_drive(dname, s[0])) {
3803 rb_file_expand_path_internal(dname,
Qnil, abs_mode, long_name, result);
3811 char *e = append_fspath(result, fname, getcwdofdrv(*s), &enc, fsenc);
3816 rb_enc_associate(result, enc = fs_enc_check(result, fname));
3819 p = chompdirsep(skiproot(buf, p, enc), p, enc);
3824 else if (!rb_is_absolute_path(s)) {
3825 if (!
NIL_P(dname)) {
3826 rb_file_expand_path_internal(dname,
Qnil, abs_mode, long_name, result);
3827 rb_enc_associate(result, fs_enc_check(result, fname));
3832 char *e = append_fspath(result, fname,
ruby_getcwd(), &enc, fsenc);
3836#if defined DOSISH || defined __CYGWIN__
3840 p = skipprefix(buf, p, enc);
3844 p = chompdirsep(skiproot(buf, p, enc), p, enc);
3849 do s++;
while (isdirsep(*s));
3852 BUFCHECK(bdiff >= buflen);
3853 memset(buf,
'/',
len);
3854 rb_str_set_len(result,
len);
3855 rb_enc_associate(result, fs_enc_check(result, fname));
3857 if (p > buf && p[-1] ==
'/')
3860 rb_str_set_len(result, p-buf);
3861 BUFCHECK(bdiff + 1 >= buflen);
3865 rb_str_set_len(result, p-buf+1);
3866 BUFCHECK(bdiff + 1 >= buflen);
3868 root = skipprefix(buf, p+1, enc);
3880 if (*(s+1) ==
'\0' || isdirsep(*(s+1))) {
3884 if (!(n = strrdirsep(root, p, enc))) {
3894 do ++s;
while (istrailinggarbage(*s));
3899#if defined DOSISH || defined __CYGWIN__
3914 while (s < fend && istrailinggarbage(*s)) s++;
3924#if defined DOSISH || defined __CYGWIN__
3928 WITH_ROOTDIFF(BUFCOPY(b, s-b));
3936 int n = ignored_char_p(s, fend, enc);
3939 WITH_ROOTDIFF(BUFCOPY(b, s-b));
3955 static const char prime[] =
":$DATA";
3956 enum {prime_len =
sizeof(prime) -1};
3960 if (s > b + prime_len && strncasecmp(s - prime_len, prime, prime_len) == 0) {
3963 if (isADS(*(s - (prime_len+1)))) {
3966 else if (memchr(b,
':', s - prime_len - b)) {
3973 rb_str_set_len(result, p-buf);
3975 if (p == skiproot(buf, p + !!*p, enc) - 1) p++;
3979 if ((s = strrdirsep(b = buf, p, enc)) != 0 && !strpbrk(s,
"*?")) {
3984 WIN32_FIND_DATAW wfd;
3987#ifdef HAVE_CYGWIN_CONV_PATH
3988 char *w32buf = NULL;
3989 const int flags = CCP_POSIX_TO_WIN_A | CCP_RELATIVE;
3991 char w32buf[MAXPATHLEN];
3995 int lnk_added = 0, is_symlink = 0;
3999 if (lstat_without_gvl(buf, &st) == 0 && S_ISLNK(st.st_mode)) {
4005 path = *buf ? buf :
"/";
4006#ifdef HAVE_CYGWIN_CONV_PATH
4007 bufsize = cygwin_conv_path(flags, path, NULL, 0);
4010 if (lnk_added) bufsize += 4;
4012 if (cygwin_conv_path(flags, path, w32buf, bufsize) == 0) {
4017 bufsize = MAXPATHLEN;
4018 if (cygwin_conv_to_win32_path(path, w32buf) == 0) {
4022 if (is_symlink && b == w32buf) {
4024 strlcat(w32buf, p, bufsize);
4026 strlcat(w32buf,
".lnk", bufsize);
4034 rb_str_set_len(result, p - buf + strlen(p));
4037 if (encidx != ENCINDEX_UTF_8 && !is_ascii_string(result)) {
4038 tmp = rb_str_encode_ospath(result);
4040 len = MultiByteToWideChar(CP_UTF8, 0, RSTRING_PTR(tmp), -1, NULL, 0);
4042 MultiByteToWideChar(CP_UTF8, 0, RSTRING_PTR(tmp), -1, wstr,
len);
4043 if (tmp != result) rb_str_set_len(tmp, 0);
4044 h = FindFirstFileW(wstr, &wfd);
4046 if (h != INVALID_HANDLE_VALUE) {
4049 len = lstrlenW(wfd.cFileName);
4051 if (lnk_added &&
len > 4 &&
4052 wcscasecmp(wfd.cFileName +
len - 4, L
".lnk") == 0) {
4053 wfd.cFileName[
len -= 4] = L
'\0';
4060 len = WideCharToMultiByte(CP_UTF8, 0, wfd.cFileName, wlen, NULL, 0, NULL, NULL);
4061 if (tmp == result) {
4062 BUFCHECK(bdiff +
len >= buflen);
4063 WideCharToMultiByte(CP_UTF8, 0, wfd.cFileName, wlen, p,
len + 1, NULL, NULL);
4067 WideCharToMultiByte(CP_UTF8, 0, wfd.cFileName, wlen, RSTRING_PTR(tmp),
len + 1, NULL, NULL);
4068 rb_str_cat_conv_enc_opts(result, bdiff, RSTRING_PTR(tmp),
len,
4069 rb_utf8_encoding(), 0,
Qnil);
4071 rb_str_resize(tmp, 0);
4083 rb_str_set_len(result, p - buf);
4084 rb_enc_check(fname, result);
4090#define EXPAND_PATH_BUFFER() rb_usascii_str_new(0, 1)
4093str_shrink(
VALUE str)
4095 rb_str_resize(str, RSTRING_LEN(str));
4099#define expand_path(fname, dname, abs_mode, long_name, result) \
4100 str_shrink(rb_file_expand_path_internal(fname, dname, abs_mode, long_name, result))
4102#define check_expand_path_args(fname, dname) \
4103 (((fname) = rb_get_path(fname)), \
4104 (void)(NIL_P(dname) ? (dname) : ((dname) = rb_get_path(dname))))
4107file_expand_path_1(
VALUE fname)
4109 return rb_file_expand_path_internal(fname,
Qnil, 0, 0, EXPAND_PATH_BUFFER());
4115 check_expand_path_args(fname, dname);
4116 return expand_path(fname, dname, 0, 1, EXPAND_PATH_BUFFER());
4120rb_file_expand_path_fast(
VALUE fname,
VALUE dname)
4122 return expand_path(fname, dname, 0, 0, EXPAND_PATH_BUFFER());
4126rb_file_s_expand_path(
int argc,
const VALUE *argv)
4129 return rb_file_expand_path(argv[0], argc > 1 ? argv[1] :
Qnil);
4163 return rb_file_s_expand_path(c, v);
4169 check_expand_path_args(fname, dname);
4170 return expand_path(fname, dname, 1, 1, EXPAND_PATH_BUFFER());
4174rb_file_s_absolute_path(
int argc,
const VALUE *argv)
4177 return rb_file_absolute_path(argv[0], argc > 1 ? argv[1] :
Qnil);
4196 return rb_file_s_absolute_path(c, v);
4212 VALUE path = rb_get_path(fname);
4214 if (!rb_is_absolute_path(RSTRING_PTR(path)))
return Qfalse;
4218enum rb_realpath_mode {
4222 RB_REALPATH_MODE_MAX
4226realpath_rec(
long *prefixlenp,
VALUE *resolvedp,
const char *unresolved,
VALUE fallback,
4227 VALUE loopcheck,
enum rb_realpath_mode mode,
int last)
4229 const char *pend = unresolved + strlen(unresolved);
4233 while (unresolved < pend) {
4234 const char *testname = unresolved;
4235 const char *unresolved_firstsep = rb_enc_path_next(unresolved, pend, enc);
4236 long testnamelen = unresolved_firstsep - unresolved;
4237 const char *unresolved_nextname = unresolved_firstsep;
4238 while (unresolved_nextname < pend && isdirsep(*unresolved_nextname))
4239 unresolved_nextname++;
4240 unresolved = unresolved_nextname;
4241 if (testnamelen == 1 && testname[0] ==
'.') {
4243 else if (testnamelen == 2 && testname[0] ==
'.' && testname[1] ==
'.') {
4244 if (*prefixlenp < RSTRING_LEN(*resolvedp)) {
4245 const char *resolved_str = RSTRING_PTR(*resolvedp);
4246 const char *resolved_names = resolved_str + *prefixlenp;
4247 const char *lastsep = strrdirsep(resolved_names, resolved_str + RSTRING_LEN(*resolvedp), enc);
4248 long len = lastsep ? lastsep - resolved_names : 0;
4249 rb_str_resize(*resolvedp, *prefixlenp +
len);
4254 VALUE testpath = rb_str_dup(*resolvedp);
4255 if (*prefixlenp < RSTRING_LEN(testpath))
4257#if defined(DOSISH_UNC) || defined(DOSISH_DRIVE_LETTER)
4258 if (*prefixlenp > 1 && *prefixlenp == RSTRING_LEN(testpath)) {
4259 const char *prefix = RSTRING_PTR(testpath);
4260 const char *last =
rb_enc_left_char_head(prefix, prefix + *prefixlenp - 1, prefix + *prefixlenp, enc);
4264 rb_str_cat(testpath, testname, testnamelen);
4265 checkval = rb_hash_aref(loopcheck, testpath);
4266 if (!
NIL_P(checkval)) {
4267 if (checkval ==
ID2SYM(resolving)) {
4268 if (mode == RB_REALPATH_CHECK) {
4272 rb_syserr_fail_path(ELOOP, testpath);
4275 *resolvedp = rb_str_dup(checkval);
4281 ret = lstat_without_gvl(RSTRING_PTR(testpath), &sbuf);
4284 if (e == ENOENT && !
NIL_P(fallback)) {
4285 if (stat_without_gvl(RSTRING_PTR(fallback), &sbuf) == 0) {
4290 if (mode == RB_REALPATH_CHECK)
return -1;
4292 if (mode == RB_REALPATH_STRICT || !last || *unresolved_firstsep)
4293 rb_syserr_fail_path(e, testpath);
4294 *resolvedp = testpath;
4298 rb_syserr_fail_path(e, testpath);
4302 if (S_ISLNK(sbuf.st_mode)) {
4305 const char *link_prefix, *link_names;
4306 long link_prefixlen;
4307 rb_hash_aset(loopcheck, testpath,
ID2SYM(resolving));
4308 link = rb_readlink(testpath, enc);
4309 link_prefix = RSTRING_PTR(link);
4310 link_names = skipprefixroot(link_prefix, link_prefix + RSTRING_LEN(link), rb_enc_get(link));
4311 link_prefixlen = link_names - link_prefix;
4312 if (link_prefixlen > 0) {
4315 link = rb_str_subseq(link, 0, link_prefixlen);
4316 tmpenc = fs_enc_check(*resolvedp, link);
4319 *prefixlenp = link_prefixlen;
4321 if (realpath_rec(prefixlenp, resolvedp, link_names, testpath,
4322 loopcheck, mode, !*unresolved_firstsep))
4331 rb_hash_aset(loopcheck, s, s);
4332 *resolvedp = testpath;
4341rb_check_realpath_emulate(
VALUE basedir,
VALUE path,
rb_encoding *origenc,
enum rb_realpath_mode mode)
4345 VALUE unresolved_path;
4350 char *path_names = NULL, *basedir_names = NULL, *curdir_names = NULL;
4351 char *ptr, *prefixptr = NULL, *pend;
4356 if (!
NIL_P(basedir)) {
4361 enc = rb_enc_get(unresolved_path);
4362 unresolved_path = TO_OSPATH(unresolved_path);
4364 path_names = skipprefixroot(ptr, ptr +
len, rb_enc_get(unresolved_path));
4365 if (ptr != path_names) {
4366 resolved = rb_str_subseq(unresolved_path, 0, path_names - ptr);
4370 if (!
NIL_P(basedir)) {
4372 basedir_names = skipprefixroot(ptr, ptr +
len, rb_enc_get(basedir));
4373 if (ptr != basedir_names) {
4374 resolved = rb_str_subseq(basedir, 0, basedir_names - ptr);
4379 curdir = rb_dir_getwd_ospath();
4381 curdir_names = skipprefixroot(ptr, ptr +
len, rb_enc_get(curdir));
4382 resolved = rb_str_subseq(curdir, 0, curdir_names - ptr);
4386 pend = prefixptr + prefixlen;
4387 ptr = chompdirsep(prefixptr, pend, enc);
4389 prefixlen = ++ptr - prefixptr;
4390 rb_str_set_len(resolved, prefixlen);
4392#ifdef FILE_ALT_SEPARATOR
4393 while (prefixptr < ptr) {
4394 if (*prefixptr == FILE_ALT_SEPARATOR) {
4397 Inc(prefixptr, pend, enc);
4401 switch (rb_enc_to_index(enc)) {
4402 case ENCINDEX_ASCII_8BIT:
4403 case ENCINDEX_US_ASCII:
4404 rb_enc_associate_index(resolved, rb_filesystem_encindex());
4407 loopcheck = rb_hash_new();
4409 if (realpath_rec(&prefixlen, &resolved, curdir_names,
Qnil, loopcheck, mode, 0))
4412 if (basedir_names) {
4413 if (realpath_rec(&prefixlen, &resolved, basedir_names,
Qnil, loopcheck, mode, 0))
4416 if (realpath_rec(&prefixlen, &resolved, path_names,
Qnil, loopcheck, mode, 1))
4419 if (origenc && origenc != rb_enc_get(resolved)) {
4421 rb_enc_associate(resolved, origenc);
4435#ifndef HAVE_REALPATH
4437rb_check_realpath_emulate_try(
VALUE arg)
4440 return rb_check_realpath_emulate(args[0], args[1], (
rb_encoding *)args[2], RB_REALPATH_CHECK);
4444rb_check_realpath_emulate_rescue(
VALUE arg,
VALUE exc)
4451rb_check_realpath_internal(
VALUE basedir,
VALUE path,
rb_encoding *origenc,
enum rb_realpath_mode mode)
4454 VALUE unresolved_path;
4455 char *resolved_ptr = NULL;
4458 if (mode == RB_REALPATH_DIR) {
4459 return rb_check_realpath_emulate(basedir, path, origenc, mode);
4463 if (*RSTRING_PTR(unresolved_path) !=
'/' && !
NIL_P(basedir)) {
4464 unresolved_path = rb_file_join(rb_assoc_new(basedir, unresolved_path));
4466 if (origenc) unresolved_path = TO_OSPATH(unresolved_path);
4468 if ((resolved_ptr = realpath(RSTRING_PTR(unresolved_path), NULL)) == NULL) {
4474 if (
errno == ENOTDIR ||
4475 (
errno == ENOENT && rb_file_exist_p(0, unresolved_path))) {
4476 return rb_check_realpath_emulate(basedir, path, origenc, mode);
4479 if (mode == RB_REALPATH_CHECK) {
4482 rb_sys_fail_path(unresolved_path);
4484 resolved = ospath_new(resolved_ptr, strlen(resolved_ptr), rb_filesystem_encoding());
4487# if !defined(__LINUX__) && !defined(__APPLE__)
4491 if (stat_without_gvl(RSTRING_PTR(resolved), &st) < 0) {
4492 if (mode == RB_REALPATH_CHECK) {
4495 rb_sys_fail_path(unresolved_path);
4499 if (origenc && origenc != rb_enc_get(resolved)) {
4503 rb_enc_associate(resolved, origenc);
4506 if (is_broken_string(resolved)) {
4507 rb_enc_associate(resolved, rb_filesystem_encoding());
4508 if (is_broken_string(resolved)) {
4509 rb_enc_associate(resolved, rb_ascii8bit_encoding());
4516 if (mode == RB_REALPATH_CHECK) {
4520 arg[2] = (
VALUE)origenc;
4523 rb_check_realpath_emulate_rescue,
Qnil);
4526 return rb_check_realpath_emulate(basedir, path, origenc, mode);
4532rb_realpath_internal(
VALUE basedir,
VALUE path,
int strict)
4534 const enum rb_realpath_mode mode =
4535 strict ? RB_REALPATH_STRICT : RB_REALPATH_DIR;
4536 return rb_check_realpath_internal(basedir, path, rb_enc_get(path), mode);
4542 return rb_check_realpath_internal(basedir, path, enc, RB_REALPATH_CHECK);
4559rb_file_s_realpath(
int argc,
VALUE *argv,
VALUE klass)
4562 VALUE path = argv[0];
4564 return rb_realpath_internal(basedir, path, 1);
4580rb_file_s_realdirpath(
int argc,
VALUE *argv,
VALUE klass)
4583 VALUE path = argv[0];
4585 return rb_realpath_internal(basedir, path, 0);
4589rmext(
const char *p,
long l0,
long l1,
const char *e,
long l2,
rb_encoding *enc)
4593 const char *s, *last;
4595 if (!e || !l2)
return 0;
4597 c = rb_enc_codepoint_len(e, e + l2, &len1, enc);
4598 if (rb_enc_ascget(e + len1, e + l2, &len2, enc) ==
'*' && len1 + len2 == l2) {
4599 if (c ==
'.')
return l0;
4604 if (rb_enc_codepoint_len(s, e, &len1, enc) == c) last = s;
4609 if (l1 < l2)
return l1;
4612 if (!at_char_boundary(p, s, p+l1, enc))
return 0;
4613#if CASEFOLD_FILESYSTEM
4614#define fncomp strncasecmp
4616#define fncomp strncmp
4618 if (fncomp(s, e, l2) == 0) {
4625ruby_enc_find_basename(
const char *name,
long *baselen,
long *alllen,
rb_encoding *enc)
4627 const char *p, *q, *e, *end;
4628#if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC
4633 end = name + (alllen ? (size_t)*alllen : strlen(name));
4634 name = skipprefix(name, end, enc);
4635#if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC
4638 while (isdirsep(*name))
4643#if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC
4647#ifdef DOSISH_DRIVE_LETTER
4648 else if (*p ==
':') {
4661 if (!(p = strrdirsep(name, end, enc))) {
4665 while (isdirsep(*p)) p++;
4668 n = ntfs_tail(p, end, enc) - p;
4670 n = chompdirsep(p, end, enc) - p;
4672 for (q = p; q - p < n && *q ==
'.'; q++);
4673 for (e = 0; q - p < n; Inc(q, end, enc)) {
4674 if (*q ==
'.') e = q;
4707 VALUE fname, fext, basename;
4708 const char *name, *p;
4716 enc = check_path_encoding(fext);
4720 if (
NIL_P(fext) || !(enc = rb_enc_compatible(fname, fext))) {
4721 enc = rb_enc_get(fname);
4724 if ((n = RSTRING_LEN(fname)) == 0 || !*(name = RSTRING_PTR(fname)))
4727 p = ruby_enc_find_basename(name, &f, &n, enc);
4735 if (!(f = rmext(p, f, n, fp, RSTRING_LEN(fext), enc))) {
4744 rb_enc_copy(basename, fname);
4748static VALUE rb_file_dirname_n(
VALUE fname,
int n);
4770rb_file_s_dirname(
int argc,
VALUE *argv,
VALUE klass)
4776 return rb_file_dirname_n(argv[0], n);
4782 return rb_file_dirname_n(fname, 1);
4786rb_file_dirname_n(
VALUE fname,
int n)
4788 const char *name, *root, *p, *end;
4794 if (n < 0) rb_raise(rb_eArgError,
"negative level: %d", n);
4797 end = name + RSTRING_LEN(fname);
4798 enc = rb_enc_get(fname);
4799 root = skiproot(name, end, enc);
4801 if (root > name + 1 && isdirsep(*name))
4802 root = skipprefix(name = root - 2, end, enc);
4804 if (root > name + 1)
4807 if (n > (end - root + 1) / 2) {
4817 if (!(p = strrdirsep(root, end, enc))) p = root;
4820 seps =
ALLOCV_N(
const char *, sepsv, n);
4821 for (i = 0; i < n; ++i) seps[i] = root;
4823 for (p = root; p < end; ) {
4825 const char *tmp = p++;
4826 while (p < end && isdirsep(*p)) p++;
4827 if (p >= end)
break;
4842#ifdef DOSISH_DRIVE_LETTER
4843 if (has_drive_letter(name) && isdirsep(*(name + 2))) {
4844 const char *top = skiproot(name + 2, end, enc);
4846 rb_str_cat(dirname, top, p - top);
4851#ifdef DOSISH_DRIVE_LETTER
4852 if (has_drive_letter(name) && root == name + 2 && p - name == 2)
4853 rb_str_cat(dirname,
".", 1);
4855 rb_enc_copy(dirname, fname);
4874 const char *p, *e, *end = name + (
len ? *
len : (long)strlen(name));
4876 p = strrdirsep(name, end, enc);
4880 do name = ++p;
while (isdirsep(*p));
4883 while (*p && *p ==
'.') p++;
4885 if (*p ==
'.' || istrailinggarbage(*p)) {
4887 const char *last = p++, *dot = last;
4888 while (istrailinggarbage(*p)) {
4889 if (*p ==
'.') dot = p;
4892 if (!*p || isADS(*p)) {
4896 if (*last ==
'.' || dot > last) e = dot;
4903 else if (isADS(*p)) {
4907 else if (isdirsep(*p))
4914 if (!e || e == name)
4953 const char *name, *e;
4959 len = RSTRING_LEN(fname);
4960 e = ruby_enc_find_extname(name, &
len, rb_enc_get(fname));
4963 extname = rb_str_subseq(fname, e - name,
len);
4981 return rb_get_path(fname);
4999 return rb_assoc_new(rb_file_dirname(path), rb_file_s_basename(1,&path,
Qundef));
5003file_inspect_join(
VALUE ary,
VALUE arg,
int recur)
5005 if (recur || ary == arg) rb_raise(rb_eArgError,
"recursive array");
5006 return rb_file_join(arg);
5010rb_file_join(
VALUE ary)
5014 const char *name, *tail;
5024 check_path_encoding(tmp);
5025 len += RSTRING_LEN(tmp);
5032 result = rb_str_buf_new(
len);
5033 RBASIC_CLEAR_CLASS(result);
5036 switch (OBJ_BUILTIN_TYPE(tmp)) {
5038 if (!checked) check_path_encoding(tmp);
5043 rb_raise(rb_eArgError,
"recursive array");
5055 rb_enc_copy(result, tmp);
5058 tail = chompdirsep(name, name +
len, rb_enc_get(result));
5059 if (RSTRING_PTR(tmp) && isdirsep(RSTRING_PTR(tmp)[0])) {
5060 rb_str_set_len(result, tail - name);
5063 rb_str_cat(result,
"/", 1);
5066 enc = fs_enc_check(result, tmp);
5067 rb_str_buf_append(result, tmp);
5068 rb_enc_associate(result, enc);
5089 return rb_file_join(args);
5092#if defined(HAVE_TRUNCATE)
5093struct truncate_arg {
5099nogvl_truncate(
void *ptr)
5101 struct truncate_arg *ta = ptr;
5102 return (
void *)(
VALUE)truncate(ta->path, ta->pos);
5123 struct truncate_arg ta;
5128 path = rb_str_encode_ospath(path);
5134 rb_sys_fail_path(path);
5138#define rb_file_s_truncate rb_f_notimplement
5141#if defined(HAVE_FTRUNCATE)
5142struct ftruncate_arg {
5148nogvl_ftruncate(
void *ptr)
5150 struct ftruncate_arg *fa = ptr;
5152 return (
VALUE)ftruncate(fa->fd, fa->pos);
5173 struct ftruncate_arg fa;
5180 rb_io_flush_raw(obj, 0);
5182 if ((
int)rb_thread_io_blocking_region(nogvl_ftruncate, &fa, fa.fd) < 0) {
5183 rb_sys_fail_path(fptr->
pathv);
5188#define rb_file_truncate rb_f_notimplement
5205#include <winerror.h>
5209rb_thread_flock(
void *data)
5212 int old_errno =
errno;
5214 int *op = data, ret = flock(op[0], op[1]);
5217 if (GetLastError() == ERROR_NOT_LOCKED) {
5304 op[1] = op1 =
NUM2INT(operation);
5309 rb_io_flush_raw(obj, 0);
5311 while ((
int)rb_thread_io_blocking_region(rb_thread_flock, op, fptr->
fd) < 0) {
5316#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
5319 if (op1 & LOCK_NB)
return Qfalse;
5322 time.tv_usec = 100 * 1000;
5328#if defined(ERESTART)
5334 rb_syserr_fail_path(e, fptr->
pathv);
5341test_check(
int n,
int argc,
VALUE *argv)
5347 for (i=1; i<n; i++) {
5348 if (!RB_TYPE_P(argv[i],
T_FILE)) {
5354#define CHECK(n) test_check((n), argc, argv)
5423 if (strchr(
"bcdefgGkloOprRsSuwWxXz", cmd)) {
5427 return rb_file_blockdev_p(0, argv[1]);
5430 return rb_file_chardev_p(0, argv[1]);
5433 return rb_file_directory_p(0, argv[1]);
5436 return rb_file_exist_p(0, argv[1]);
5439 return rb_file_file_p(0, argv[1]);
5442 return rb_file_sgid_p(0, argv[1]);
5445 return rb_file_grpowned_p(0, argv[1]);
5448 return rb_file_sticky_p(0, argv[1]);
5451 return rb_file_symlink_p(0, argv[1]);
5454 return rb_file_owned_p(0, argv[1]);
5457 return rb_file_rowned_p(0, argv[1]);
5460 return rb_file_pipe_p(0, argv[1]);
5463 return rb_file_readable_p(0, argv[1]);
5466 return rb_file_readable_real_p(0, argv[1]);
5469 return rb_file_size_p(0, argv[1]);
5472 return rb_file_socket_p(0, argv[1]);
5475 return rb_file_suid_p(0, argv[1]);
5478 return rb_file_writable_p(0, argv[1]);
5481 return rb_file_writable_real_p(0, argv[1]);
5484 return rb_file_executable_p(0, argv[1]);
5487 return rb_file_executable_real_p(0, argv[1]);
5490 return rb_file_zero_p(0, argv[1]);
5494 if (strchr(
"MAC", cmd)) {
5496 VALUE fname = argv[1];
5499 if (
rb_stat(fname, &st) == -1) {
5502 rb_syserr_fail_path(e, fname);
5507 return stat_atime(&st);
5509 return stat_mtime(&st);
5511 return stat_ctime(&st);
5517 return rb_file_identical_p(0, argv[1], argv[2]);
5520 if (strchr(
"=<>", cmd)) {
5521 struct stat st1, st2;
5528 t1 = stat_mtimespec(&st1);
5529 t2 = stat_mtimespec(&st2);
5533 if (t1.tv_sec == t2.tv_sec && t1.tv_nsec == t2.tv_nsec)
return Qtrue;
5537 if (t1.tv_sec > t2.tv_sec)
return Qtrue;
5538 if (t1.tv_sec == t2.tv_sec && t1.tv_nsec > t2.tv_nsec)
return Qtrue;
5542 if (t1.tv_sec < t2.tv_sec)
return Qtrue;
5543 if (t1.tv_sec == t2.tv_sec && t1.tv_nsec < t2.tv_nsec)
return Qtrue;
5550 rb_raise(rb_eArgError,
"unknown command '%s%c'", cmd ==
'\'' || cmd ==
'\\' ?
"\\" :
"", cmd);
5553 rb_raise(rb_eArgError,
"unknown command \"\\x%02X\"", cmd);
5572rb_stat_s_alloc(
VALUE klass)
5574 return stat_new_0(klass, 0);
5592 fname = rb_str_encode_ospath(fname);
5594 rb_sys_fail_path(fname);
5601 rb_st->initialized =
true;
5618 *copy_rb_st = *orig_rb_st;
5637rb_stat_ftype(
VALUE obj)
5639 return rb_file_ftype(get_stat(obj));
5656 if (S_ISDIR(get_stat(obj)->st_mode))
return Qtrue;
5672 if (S_ISFIFO(get_stat(obj)->st_mode))
return Qtrue;
5698 if (S_ISLNK(get_stat(obj)->st_mode))
return Qtrue;
5719 if (S_ISSOCK(get_stat(obj)->st_mode))
return Qtrue;
5742 if (S_ISBLK(get_stat(obj)->st_mode))
return Qtrue;
5763 if (S_ISCHR(get_stat(obj)->st_mode))
return Qtrue;
5781rb_stat_owned(
VALUE obj)
5783 if (get_stat(obj)->st_uid == geteuid())
return Qtrue;
5788rb_stat_rowned(
VALUE obj)
5790 if (get_stat(obj)->st_uid == getuid())
return Qtrue;
5807rb_stat_grpowned(
VALUE obj)
5810 if (rb_group_member(get_stat(obj)->st_gid))
return Qtrue;
5829 struct stat *st = get_stat(obj);
5832 if (geteuid() == 0)
return Qtrue;
5835 if (rb_stat_owned(obj))
5836 return RBOOL(st->st_mode & S_IRUSR);
5839 if (rb_stat_grpowned(obj))
5840 return RBOOL(st->st_mode & S_IRGRP);
5843 if (!(st->st_mode & S_IROTH))
return Qfalse;
5862 struct stat *st = get_stat(obj);
5865 if (getuid() == 0)
return Qtrue;
5868 if (rb_stat_rowned(obj))
5869 return RBOOL(st->st_mode & S_IRUSR);
5872 if (rb_group_member(get_stat(obj)->st_gid))
5873 return RBOOL(st->st_mode & S_IRGRP);
5876 if (!(st->st_mode & S_IROTH))
return Qfalse;
5895rb_stat_wr(
VALUE obj)
5898 struct stat *st = get_stat(obj);
5899 if ((st->st_mode & (S_IROTH)) == S_IROTH) {
5900 return UINT2NUM(st->st_mode & (S_IRUGO|S_IWUGO|S_IXUGO));
5920 struct stat *st = get_stat(obj);
5923 if (geteuid() == 0)
return Qtrue;
5926 if (rb_stat_owned(obj))
5927 return RBOOL(st->st_mode & S_IWUSR);
5930 if (rb_stat_grpowned(obj))
5931 return RBOOL(st->st_mode & S_IWGRP);
5934 if (!(st->st_mode & S_IWOTH))
return Qfalse;
5953 struct stat *st = get_stat(obj);
5956 if (getuid() == 0)
return Qtrue;
5959 if (rb_stat_rowned(obj))
5960 return RBOOL(st->st_mode & S_IWUSR);
5963 if (rb_group_member(get_stat(obj)->st_gid))
5964 return RBOOL(st->st_mode & S_IWGRP);
5967 if (!(st->st_mode & S_IWOTH))
return Qfalse;
5986rb_stat_ww(
VALUE obj)
5989 struct stat *st = get_stat(obj);
5990 if ((st->st_mode & (S_IWOTH)) == S_IWOTH) {
5991 return UINT2NUM(st->st_mode & (S_IRUGO|S_IWUGO|S_IXUGO));
6013 struct stat *st = get_stat(obj);
6016 if (geteuid() == 0) {
6017 return RBOOL(st->st_mode & S_IXUGO);
6021 if (rb_stat_owned(obj))
6022 return RBOOL(st->st_mode & S_IXUSR);
6025 if (rb_stat_grpowned(obj))
6026 return RBOOL(st->st_mode & S_IXGRP);
6029 if (!(st->st_mode & S_IXOTH))
return Qfalse;
6045 struct stat *st = get_stat(obj);
6048 if (getuid() == 0) {
6049 return RBOOL(st->st_mode & S_IXUGO);
6053 if (rb_stat_rowned(obj))
6054 return RBOOL(st->st_mode & S_IXUSR);
6057 if (rb_group_member(get_stat(obj)->st_gid))
6058 return RBOOL(st->st_mode & S_IXGRP);
6061 if (!(st->st_mode & S_IXOTH))
return Qfalse;
6080 if (S_ISREG(get_stat(obj)->st_mode))
return Qtrue;
6098 if (get_stat(obj)->st_size == 0)
return Qtrue;
6117 rb_off_t size = get_stat(obj)->st_size;
6119 if (size == 0)
return Qnil;
6135rb_stat_suid(
VALUE obj)
6138 if (get_stat(obj)->st_mode & S_ISUID)
return Qtrue;
6156rb_stat_sgid(
VALUE obj)
6159 if (get_stat(obj)->st_mode & S_ISGID)
return Qtrue;
6177rb_stat_sticky(
VALUE obj)
6180 if (get_stat(obj)->st_mode & S_ISVTX)
return Qtrue;
6185#if !defined HAVE_MKFIFO && defined HAVE_MKNOD && defined S_IFIFO
6186#define mkfifo(path, mode) mknod(path, (mode)&~S_IFMT|S_IFIFO, 0)
6197nogvl_mkfifo(
void *ptr)
6199 struct mkfifo_arg *ma = ptr;
6201 return (
void *)(
VALUE)mkfifo(ma->path, ma->mode);
6218 struct mkfifo_arg ma;
6227 path = rb_str_encode_ospath(path);
6228 ma.path = RSTRING_PTR(path);
6230 rb_sys_fail_path(path);
6235#define rb_file_s_mkfifo rb_f_notimplement
6238static VALUE rb_mFConst;
6241rb_file_const(
const char *name,
VALUE value)
6247rb_is_absolute_path(
const char *path)
6249#ifdef DOSISH_DRIVE_LETTER
6250 if (has_drive_letter(path) && isdirsep(path[2]))
return 1;
6253 if (isdirsep(path[0]) && isdirsep(path[1]))
return 1;
6256 if (path[0] ==
'/')
return 1;
6261#ifndef ENABLE_PATH_CHECK
6262# if defined DOSISH || defined __CYGWIN__
6263# define ENABLE_PATH_CHECK 0
6265# define ENABLE_PATH_CHECK 1
6269#if ENABLE_PATH_CHECK
6271path_check_0(
VALUE path)
6279 if (!rb_is_absolute_path(p0)) {
6289 p0 = RSTRING_PTR(path);
6291 e0 = p0 + RSTRING_LEN(path);
6292 enc = rb_enc_get(path);
6297 if (STAT(p0, &st) == 0 && S_ISDIR(st.st_mode) && (st.st_mode & S_IWOTH)
6299 && !(p && (st.st_mode & S_ISVTX))
6301 && !access(p0, W_OK)) {
6302 rb_enc_warn(enc,
"Insecure world writable dir %s in PATH, mode 0%"
6303#
if SIZEOF_DEV_T > SIZEOF_INT
6313 s = strrdirsep(p0, e0, enc);
6315 if (!s || s == p0)
return 1;
6324rb_path_check(
const char *path)
6326#if ENABLE_PATH_CHECK
6327 const char *p0, *p, *pend;
6330 if (!path)
return 1;
6332 pend = path + strlen(path);
6334 p = strchr(path, sep);
6342 if (p0 > pend)
break;
6343 p = strchr(p0, sep);
6351ruby_is_fd_loadable(
int fd)
6358 if (fstat(fd, &st) < 0)
6361 if (S_ISREG(st.st_mode))
6364 if (S_ISFIFO(st.st_mode) || S_ISCHR(st.st_mode))
6367 if (S_ISDIR(st.st_mode))
6378rb_file_load_ok(
const char *path)
6385 int mode = (O_RDONLY |
6386#if defined O_NONBLOCK
6388#elif defined O_NDELAY
6394 if (!rb_gc_for_fd(
errno))
return 0;
6396 if (fd < 0)
return 0;
6399 ret = ruby_is_fd_loadable(fd);
6406is_explicit_relative(
const char *path)
6408 if (*path++ !=
'.')
return 0;
6409 if (*path ==
'.') path++;
6410 return isdirsep(*path);
6416 int encidx = rb_enc_get_index(orig);
6417 if (encidx == ENCINDEX_ASCII_8BIT || encidx == ENCINDEX_US_ASCII)
6418 encidx = rb_filesystem_encindex();
6419 rb_enc_associate_index(path, encidx);
6427rb_find_file_ext(
VALUE *filep,
const char *
const *ext)
6430 VALUE fname = *filep, load_path, tmp;
6434 if (!ext[0])
return 0;
6437 fname = file_expand_path_1(fname);
6438 f = RSTRING_PTR(fname);
6443 if (expanded || rb_is_absolute_path(f) || is_explicit_relative(f)) {
6444 if (!expanded) fname = file_expand_path_1(fname);
6445 fnlen = RSTRING_LEN(fname);
6446 for (i=0; ext[i]; i++) {
6448 if (rb_file_load_ok(RSTRING_PTR(fname))) {
6449 *filep = copy_path_class(fname, *filep);
6452 rb_str_set_len(fname, fnlen);
6457 RB_GC_GUARD(load_path) = rb_get_expanded_load_path();
6458 if (!load_path)
return 0;
6460 fname = rb_str_dup(*filep);
6461 RBASIC_CLEAR_CLASS(fname);
6462 fnlen = RSTRING_LEN(fname);
6464 rb_enc_associate_index(tmp, rb_usascii_encindex());
6465 for (j=0; ext[j]; j++) {
6467 for (i = 0; i <
RARRAY_LEN(load_path); i++) {
6471 if (RSTRING_LEN(str) == 0)
continue;
6472 rb_file_expand_path_internal(fname, str, 0, 0, tmp);
6473 if (rb_file_load_ok(RSTRING_PTR(tmp))) {
6474 *filep = copy_path_class(tmp, *filep);
6478 rb_str_set_len(fname, fnlen);
6480 rb_str_resize(tmp, 0);
6488 VALUE tmp, load_path;
6493 tmp = file_expand_path_1(path);
6494 path = copy_path_class(tmp, path);
6495 f = RSTRING_PTR(path);
6499 if (expanded || rb_is_absolute_path(f) || is_explicit_relative(f)) {
6500 if (!rb_file_load_ok(f))
return 0;
6502 path = copy_path_class(file_expand_path_1(path), path);
6506 RB_GC_GUARD(load_path) = rb_get_expanded_load_path();
6511 rb_enc_associate_index(tmp, rb_usascii_encindex());
6512 for (i = 0; i <
RARRAY_LEN(load_path); i++) {
6515 if (RSTRING_LEN(str) > 0) {
6516 rb_file_expand_path_internal(path, str, 0, 0, tmp);
6517 f = RSTRING_PTR(tmp);
6518 if (rb_file_load_ok(f))
goto found;
6521 rb_str_resize(tmp, 0);
6529 return copy_path_class(tmp, path);
6532#define define_filetest_function(name, func, argc) do { \
6533 rb_define_module_function(rb_mFileTest, name, func, argc); \
6534 rb_define_singleton_method(rb_cFile, name, func, argc); \
6537const char ruby_null_device[] =
6540#elif defined AMIGA || defined __amigaos__
7344#if defined(__APPLE__) && defined(HAVE_WORKING_FORK)
7345 rb_CFString_class_initialize_before_fork();
7353 define_filetest_function(
"directory?", rb_file_directory_p, 1);
7354 define_filetest_function(
"exist?", rb_file_exist_p, 1);
7355 define_filetest_function(
"readable?", rb_file_readable_p, 1);
7356 define_filetest_function(
"readable_real?", rb_file_readable_real_p, 1);
7357 define_filetest_function(
"world_readable?", rb_file_world_readable_p, 1);
7358 define_filetest_function(
"writable?", rb_file_writable_p, 1);
7359 define_filetest_function(
"writable_real?", rb_file_writable_real_p, 1);
7360 define_filetest_function(
"world_writable?", rb_file_world_writable_p, 1);
7361 define_filetest_function(
"executable?", rb_file_executable_p, 1);
7362 define_filetest_function(
"executable_real?", rb_file_executable_real_p, 1);
7363 define_filetest_function(
"file?", rb_file_file_p, 1);
7364 define_filetest_function(
"zero?", rb_file_zero_p, 1);
7365 define_filetest_function(
"empty?", rb_file_zero_p, 1);
7366 define_filetest_function(
"size?", rb_file_size_p, 1);
7367 define_filetest_function(
"size", rb_file_s_size, 1);
7368 define_filetest_function(
"owned?", rb_file_owned_p, 1);
7369 define_filetest_function(
"grpowned?", rb_file_grpowned_p, 1);
7371 define_filetest_function(
"pipe?", rb_file_pipe_p, 1);
7372 define_filetest_function(
"symlink?", rb_file_symlink_p, 1);
7373 define_filetest_function(
"socket?", rb_file_socket_p, 1);
7375 define_filetest_function(
"blockdev?", rb_file_blockdev_p, 1);
7376 define_filetest_function(
"chardev?", rb_file_chardev_p, 1);
7378 define_filetest_function(
"setuid?", rb_file_suid_p, 1);
7379 define_filetest_function(
"setgid?", rb_file_sgid_p, 1);
7380 define_filetest_function(
"sticky?", rb_file_sticky_p, 1);
7382 define_filetest_function(
"identical?", rb_file_identical_p, 2);
7420 separator = rb_fstring_lit(
"/");
7783#if defined(O_NDELAY) || defined(O_NONBLOCK)
7785# define O_NONBLOCK O_NDELAY
7801#ifndef O_SHARE_DELETE
7802# define O_SHARE_DELETE 0
7845 rb_define_const(rb_mFConst,
"NULL", rb_fstring_cstr(ruby_null_device));
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
#define rb_define_global_function(mid, func, arity)
Defines rb_mKernel #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.
#define rb_str_new2
Old name of rb_str_new_cstr.
#define T_FILE
Old name of RUBY_T_FILE.
#define rb_str_buf_cat2
Old name of rb_usascii_str_new_cstr.
#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 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 rb_str_cat2
Old name of rb_str_cat_cstr.
#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 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 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.
VALUE rb_eNotImpError
NotImplementedError exception.
VALUE rb_eIOError
IOError exception.
VALUE rb_eTypeError
TypeError exception.
VALUE rb_eEncCompatError
Encoding::CompatibilityError exception.
void rb_enc_raise(rb_encoding *enc, VALUE exc, const char *fmt,...)
Identical to rb_raise(), except it additionally takes an encoding.
VALUE rb_eSystemCallError
SystemCallError exception.
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
VALUE rb_cStat
File::Stat class.
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
VALUE rb_mFileTest
FileTest module.
VALUE rb_equal(VALUE lhs, VALUE rhs)
This function is an optimised version of calling #==.
VALUE rb_obj_is_kind_of(VALUE obj, VALUE klass)
Queries if the given object is an instance (of possibly descendants) of the given class.
VALUE rb_mComparable
Comparable module.
VALUE rb_cFile
File class.
VALUE rb_cString
String class.
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.
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.
VALUE rb_str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to)
Encoding conversion main routine.
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.
#define INTEGER_PACK_NATIVE_BYTE_ORDER
Means either INTEGER_PACK_MSBYTE_FIRST or INTEGER_PACK_LSBYTE_FIRST, depending on the host processor'...
#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.
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_ellipsize(VALUE str, long len)
Shortens str and adds three dots, an ellipsis, if it is longer than len characters.
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
size_t rb_str_capacity(VALUE str)
Queries the capacity of the given 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_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).
#define rb_str_dup_frozen
Just another name of rb_str_new_frozen.
void rb_str_modify_expand(VALUE str, long capa)
Identical to rb_str_modify(), except it additionally expands the capacity of the receiver.
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
#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.
#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_closed(rb_io_t *fptr)
This badly named function asserts that the passed IO is open.
int len
Length of the buffer.
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.
#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.
VALUE rb_rescue(type *q, VALUE w, type *e, VALUE r)
An equivalent of rescue clause.
#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.
#define inline
Old Visual Studio versions do not support the inline keyword, so we need to define it to be __inline.
#define RARRAY_LEN
Just another name of rb_array_len.
#define RARRAY_AREF(a, i)
#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.
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
#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_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
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 errno
Ractor-aware version of errno.
#define FilePathStringValue(v)
This macro actually does the same thing as FilePathValue now.
#define _(args)
This was a transition path from K&R to ANSI.
This is the struct that holds necessary info for a struct.
Ruby's IO, metadata and buffers.
int mode
mode flags: FMODE_XXXs
VALUE pathv
pathname for file
#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 ID
Type that represents a Ruby identifier such as a variable name.
uintptr_t VALUE
Type that represents a Ruby object.
#define RBIMPL_WARNING_IGNORED(flag)
Suppresses a warning.
#define RBIMPL_WARNING_PUSH()
Pushes compiler warning state.
#define RBIMPL_WARNING_POP()
Pops compiler warning state.