00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #ifdef _WIN32
00015 #include "missing/file.h"
00016 #endif
00017 #ifdef __CYGWIN__
00018 #include <windows.h>
00019 #include <sys/cygwin.h>
00020 #endif
00021
00022 #include "ruby/ruby.h"
00023 #include "ruby/io.h"
00024 #include "ruby/util.h"
00025 #include "dln.h"
00026 #include "internal.h"
00027
00028 #ifdef HAVE_UNISTD_H
00029 #include <unistd.h>
00030 #endif
00031
00032 #ifdef HAVE_SYS_FILE_H
00033 # include <sys/file.h>
00034 #else
00035 int flock(int, int);
00036 #endif
00037
00038 #ifdef HAVE_SYS_PARAM_H
00039 # include <sys/param.h>
00040 #endif
00041 #ifndef MAXPATHLEN
00042 # define MAXPATHLEN 1024
00043 #endif
00044
00045 #include <ctype.h>
00046
00047 #include <time.h>
00048
00049 #ifdef HAVE_UTIME_H
00050 #include <utime.h>
00051 #elif defined HAVE_SYS_UTIME_H
00052 #include <sys/utime.h>
00053 #endif
00054
00055 #ifdef HAVE_PWD_H
00056 #include <pwd.h>
00057 #endif
00058
00059 #include <sys/types.h>
00060 #include <sys/stat.h>
00061
00062 #ifdef HAVE_SYS_MKDEV_H
00063 #include <sys/mkdev.h>
00064 #endif
00065
00066 #if defined(HAVE_FCNTL_H)
00067 #include <fcntl.h>
00068 #endif
00069
00070 #if !defined HAVE_LSTAT && !defined lstat
00071 #define lstat stat
00072 #endif
00073
00074
00075 #ifdef _WIN32
00076 #define STAT(p, s) rb_w32_ustati64((p), (s))
00077 #undef lstat
00078 #define lstat(p, s) rb_w32_ustati64((p), (s))
00079 #undef access
00080 #define access(p, m) rb_w32_uaccess((p), (m))
00081 #undef chmod
00082 #define chmod(p, m) rb_w32_uchmod((p), (m))
00083 #undef chown
00084 #define chown(p, o, g) rb_w32_uchown((p), (o), (g))
00085 #undef utime
00086 #define utime(p, t) rb_w32_uutime((p), (t))
00087 #undef link
00088 #define link(f, t) rb_w32_ulink((f), (t))
00089 #undef unlink
00090 #define unlink(p) rb_w32_uunlink(p)
00091 #undef rename
00092 #define rename(f, t) rb_w32_urename((f), (t))
00093 #else
00094 #define STAT(p, s) stat((p), (s))
00095 #endif
00096
00097 #define rb_sys_fail_path(path) rb_sys_fail_str(path)
00098
00099 #if defined(__BEOS__) || defined(__HAIKU__)
00100 static int
00101 be_chown(const char *path, uid_t owner, gid_t group)
00102 {
00103 if (owner == (uid_t)-1 || group == (gid_t)-1) {
00104 struct stat st;
00105 if (STAT(path, &st) < 0) return -1;
00106 if (owner == (uid_t)-1) owner = st.st_uid;
00107 if (group == (gid_t)-1) group = st.st_gid;
00108 }
00109 return chown(path, owner, group);
00110 }
00111 #define chown be_chown
00112 static int
00113 be_fchown(int fd, uid_t owner, gid_t group)
00114 {
00115 if (owner == (uid_t)-1 || group == (gid_t)-1) {
00116 struct stat st;
00117 if (fstat(fd, &st) < 0) return -1;
00118 if (owner == (uid_t)-1) owner = st.st_uid;
00119 if (group == (gid_t)-1) group = st.st_gid;
00120 }
00121 return fchown(fd, owner, group);
00122 }
00123 #define fchown be_fchown
00124 #endif
00125
00126 VALUE rb_cFile;
00127 VALUE rb_mFileTest;
00128 VALUE rb_cStat;
00129
00130 #define insecure_obj_p(obj, level) ((level) >= 4 || ((level) > 0 && OBJ_TAINTED(obj)))
00131
00132 static VALUE
00133 file_path_convert(VALUE name)
00134 {
00135 #ifndef _WIN32
00136 rb_encoding *fname_encoding = rb_enc_from_index(ENCODING_GET(name));
00137 rb_encoding *fs_encoding;
00138 if (rb_default_internal_encoding() != NULL
00139 && rb_usascii_encoding() != fname_encoding
00140 && rb_ascii8bit_encoding() != fname_encoding
00141 && (fs_encoding = rb_filesystem_encoding()) != fname_encoding) {
00142
00143 name = rb_str_conv_enc(name, fname_encoding, fs_encoding);
00144 }
00145 #endif
00146 return name;
00147 }
00148
00149 static VALUE
00150 rb_get_path_check(VALUE obj, int level)
00151 {
00152 VALUE tmp;
00153 ID to_path;
00154 rb_encoding *enc;
00155
00156 if (insecure_obj_p(obj, level)) {
00157 rb_insecure_operation();
00158 }
00159
00160 CONST_ID(to_path, "to_path");
00161 tmp = rb_check_funcall(obj, to_path, 0, 0);
00162 if (tmp == Qundef) {
00163 tmp = obj;
00164 }
00165 StringValue(tmp);
00166
00167 tmp = file_path_convert(tmp);
00168 if (obj != tmp && insecure_obj_p(tmp, level)) {
00169 rb_insecure_operation();
00170 }
00171 enc = rb_enc_get(tmp);
00172 if (!rb_enc_asciicompat(enc)) {
00173 tmp = rb_str_inspect(tmp);
00174 rb_raise(rb_eEncCompatError, "path name must be ASCII-compatible (%s): %s",
00175 rb_enc_name(enc), RSTRING_PTR(tmp));
00176 }
00177 return rb_str_new4(tmp);
00178 }
00179
00180 VALUE
00181 rb_get_path_no_checksafe(VALUE obj)
00182 {
00183 return rb_get_path_check(obj, 0);
00184 }
00185
00186 VALUE
00187 rb_get_path(VALUE obj)
00188 {
00189 return rb_get_path_check(obj, rb_safe_level());
00190 }
00191
00192 VALUE
00193 rb_str_encode_ospath(VALUE path)
00194 {
00195 #ifdef _WIN32
00196 rb_encoding *enc = rb_enc_get(path);
00197 if (enc != rb_ascii8bit_encoding()) {
00198 rb_encoding *utf8 = rb_utf8_encoding();
00199 if (enc != utf8)
00200 path = rb_str_encode(path, rb_enc_from_encoding(utf8), 0, Qnil);
00201 }
00202 else if (RSTRING_LEN(path) > 0) {
00203 path = rb_str_dup(path);
00204 rb_enc_associate(path, rb_filesystem_encoding());
00205 path = rb_str_encode(path, rb_enc_from_encoding(rb_utf8_encoding()), 0, Qnil);
00206 }
00207 #endif
00208 return path;
00209 }
00210
00211 static long
00212 apply2files(void (*func)(const char *, VALUE, void *), VALUE vargs, void *arg)
00213 {
00214 long i;
00215 volatile VALUE path;
00216
00217 rb_secure(4);
00218 for (i=0; i<RARRAY_LEN(vargs); i++) {
00219 const char *s;
00220 path = rb_get_path(RARRAY_PTR(vargs)[i]);
00221 path = rb_str_encode_ospath(path);
00222 s = RSTRING_PTR(path);
00223 (*func)(s, path, arg);
00224 }
00225
00226 return RARRAY_LEN(vargs);
00227 }
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241 static VALUE
00242 rb_file_path(VALUE obj)
00243 {
00244 rb_io_t *fptr;
00245
00246 fptr = RFILE(rb_io_taint_check(obj))->fptr;
00247 rb_io_check_initialized(fptr);
00248 if (NIL_P(fptr->pathv)) return Qnil;
00249 return rb_obj_taint(rb_str_dup(fptr->pathv));
00250 }
00251
00252 static size_t
00253 stat_memsize(const void *p)
00254 {
00255 return p ? sizeof(struct stat) : 0;
00256 }
00257
00258 static const rb_data_type_t stat_data_type = {
00259 "stat",
00260 {NULL, RUBY_TYPED_DEFAULT_FREE, stat_memsize,},
00261 };
00262
00263 static VALUE
00264 stat_new_0(VALUE klass, struct stat *st)
00265 {
00266 struct stat *nst = 0;
00267
00268 if (st) {
00269 nst = ALLOC(struct stat);
00270 *nst = *st;
00271 }
00272 return TypedData_Wrap_Struct(klass, &stat_data_type, nst);
00273 }
00274
00275 static VALUE
00276 stat_new(struct stat *st)
00277 {
00278 return stat_new_0(rb_cStat, st);
00279 }
00280
00281 static struct stat*
00282 get_stat(VALUE self)
00283 {
00284 struct stat* st;
00285 TypedData_Get_Struct(self, struct stat, &stat_data_type, st);
00286 if (!st) rb_raise(rb_eTypeError, "uninitialized File::Stat");
00287 return st;
00288 }
00289
00290 static struct timespec stat_mtimespec(struct stat *st);
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305 static VALUE
00306 rb_stat_cmp(VALUE self, VALUE other)
00307 {
00308 if (rb_obj_is_kind_of(other, rb_obj_class(self))) {
00309 struct timespec ts1 = stat_mtimespec(get_stat(self));
00310 struct timespec ts2 = stat_mtimespec(get_stat(other));
00311 if (ts1.tv_sec == ts2.tv_sec) {
00312 if (ts1.tv_nsec == ts2.tv_nsec) return INT2FIX(0);
00313 if (ts1.tv_nsec < ts2.tv_nsec) return INT2FIX(-1);
00314 return INT2FIX(1);
00315 }
00316 if (ts1.tv_sec < ts2.tv_sec) return INT2FIX(-1);
00317 return INT2FIX(1);
00318 }
00319 return Qnil;
00320 }
00321
00322 #define ST2UINT(val) ((val) & ~(~1UL << (sizeof(val) * CHAR_BIT - 1)))
00323
00324 #ifndef NUM2DEVT
00325 # define NUM2DEVT(v) NUM2UINT(v)
00326 #endif
00327 #ifndef DEVT2NUM
00328 # define DEVT2NUM(v) UINT2NUM(v)
00329 #endif
00330 #ifndef PRI_DEVT_PREFIX
00331 # define PRI_DEVT_PREFIX ""
00332 #endif
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344 static VALUE
00345 rb_stat_dev(VALUE self)
00346 {
00347 return DEVT2NUM(get_stat(self)->st_dev);
00348 }
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361 static VALUE
00362 rb_stat_dev_major(VALUE self)
00363 {
00364 #if defined(major)
00365 return INT2NUM(major(get_stat(self)->st_dev));
00366 #else
00367 return Qnil;
00368 #endif
00369 }
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382 static VALUE
00383 rb_stat_dev_minor(VALUE self)
00384 {
00385 #if defined(minor)
00386 return INT2NUM(minor(get_stat(self)->st_dev));
00387 #else
00388 return Qnil;
00389 #endif
00390 }
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402 static VALUE
00403 rb_stat_ino(VALUE self)
00404 {
00405 #if SIZEOF_STRUCT_STAT_ST_INO > SIZEOF_LONG
00406 return ULL2NUM(get_stat(self)->st_ino);
00407 #else
00408 return ULONG2NUM(get_stat(self)->st_ino);
00409 #endif
00410 }
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425 static VALUE
00426 rb_stat_mode(VALUE self)
00427 {
00428 return UINT2NUM(ST2UINT(get_stat(self)->st_mode));
00429 }
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443 static VALUE
00444 rb_stat_nlink(VALUE self)
00445 {
00446 return UINT2NUM(get_stat(self)->st_nlink);
00447 }
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459 static VALUE
00460 rb_stat_uid(VALUE self)
00461 {
00462 return UIDT2NUM(get_stat(self)->st_uid);
00463 }
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475 static VALUE
00476 rb_stat_gid(VALUE self)
00477 {
00478 return GIDT2NUM(get_stat(self)->st_gid);
00479 }
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493 static VALUE
00494 rb_stat_rdev(VALUE self)
00495 {
00496 #ifdef HAVE_ST_RDEV
00497 return DEVT2NUM(get_stat(self)->st_rdev);
00498 #else
00499 return Qnil;
00500 #endif
00501 }
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514 static VALUE
00515 rb_stat_rdev_major(VALUE self)
00516 {
00517 #if defined(HAVE_ST_RDEV) && defined(major)
00518 return DEVT2NUM(major(get_stat(self)->st_rdev));
00519 #else
00520 return Qnil;
00521 #endif
00522 }
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535 static VALUE
00536 rb_stat_rdev_minor(VALUE self)
00537 {
00538 #if defined(HAVE_ST_RDEV) && defined(minor)
00539 return DEVT2NUM(minor(get_stat(self)->st_rdev));
00540 #else
00541 return Qnil;
00542 #endif
00543 }
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554 static VALUE
00555 rb_stat_size(VALUE self)
00556 {
00557 return OFFT2NUM(get_stat(self)->st_size);
00558 }
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571 static VALUE
00572 rb_stat_blksize(VALUE self)
00573 {
00574 #ifdef HAVE_ST_BLKSIZE
00575 return ULONG2NUM(get_stat(self)->st_blksize);
00576 #else
00577 return Qnil;
00578 #endif
00579 }
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592 static VALUE
00593 rb_stat_blocks(VALUE self)
00594 {
00595 #ifdef HAVE_STRUCT_STAT_ST_BLOCKS
00596 # if SIZEOF_STRUCT_STAT_ST_BLOCKS > SIZEOF_LONG
00597 return ULL2NUM(get_stat(self)->st_blocks);
00598 # else
00599 return ULONG2NUM(get_stat(self)->st_blocks);
00600 # endif
00601 #else
00602 return Qnil;
00603 #endif
00604 }
00605
00606 static struct timespec
00607 stat_atimespec(struct stat *st)
00608 {
00609 struct timespec ts;
00610 ts.tv_sec = st->st_atime;
00611 #if defined(HAVE_STRUCT_STAT_ST_ATIM)
00612 ts.tv_nsec = st->st_atim.tv_nsec;
00613 #elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC)
00614 ts.tv_nsec = st->st_atimespec.tv_nsec;
00615 #elif defined(HAVE_STRUCT_STAT_ST_ATIMENSEC)
00616 ts.tv_nsec = st->st_atimensec;
00617 #else
00618 ts.tv_nsec = 0;
00619 #endif
00620 return ts;
00621 }
00622
00623 static VALUE
00624 stat_atime(struct stat *st)
00625 {
00626 struct timespec ts = stat_atimespec(st);
00627 return rb_time_nano_new(ts.tv_sec, ts.tv_nsec);
00628 }
00629
00630 static struct timespec
00631 stat_mtimespec(struct stat *st)
00632 {
00633 struct timespec ts;
00634 ts.tv_sec = st->st_mtime;
00635 #if defined(HAVE_STRUCT_STAT_ST_MTIM)
00636 ts.tv_nsec = st->st_mtim.tv_nsec;
00637 #elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC)
00638 ts.tv_nsec = st->st_mtimespec.tv_nsec;
00639 #elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC)
00640 ts.tv_nsec = st->st_mtimensec;
00641 #else
00642 ts.tv_nsec = 0;
00643 #endif
00644 return ts;
00645 }
00646
00647 static VALUE
00648 stat_mtime(struct stat *st)
00649 {
00650 struct timespec ts = stat_mtimespec(st);
00651 return rb_time_nano_new(ts.tv_sec, ts.tv_nsec);
00652 }
00653
00654 static struct timespec
00655 stat_ctimespec(struct stat *st)
00656 {
00657 struct timespec ts;
00658 ts.tv_sec = st->st_ctime;
00659 #if defined(HAVE_STRUCT_STAT_ST_CTIM)
00660 ts.tv_nsec = st->st_ctim.tv_nsec;
00661 #elif defined(HAVE_STRUCT_STAT_ST_CTIMESPEC)
00662 ts.tv_nsec = st->st_ctimespec.tv_nsec;
00663 #elif defined(HAVE_STRUCT_STAT_ST_CTIMENSEC)
00664 ts.tv_nsec = st->st_ctimensec;
00665 #else
00666 ts.tv_nsec = 0;
00667 #endif
00668 return ts;
00669 }
00670
00671 static VALUE
00672 stat_ctime(struct stat *st)
00673 {
00674 struct timespec ts = stat_ctimespec(st);
00675 return rb_time_nano_new(ts.tv_sec, ts.tv_nsec);
00676 }
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689 static VALUE
00690 rb_stat_atime(VALUE self)
00691 {
00692 return stat_atime(get_stat(self));
00693 }
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705 static VALUE
00706 rb_stat_mtime(VALUE self)
00707 {
00708 return stat_mtime(get_stat(self));
00709 }
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725 static VALUE
00726 rb_stat_ctime(VALUE self)
00727 {
00728 return stat_ctime(get_stat(self));
00729 }
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745 static VALUE
00746 rb_stat_inspect(VALUE self)
00747 {
00748 VALUE str;
00749 size_t i;
00750 static const struct {
00751 const char *name;
00752 VALUE (*func)(VALUE);
00753 } member[] = {
00754 {"dev", rb_stat_dev},
00755 {"ino", rb_stat_ino},
00756 {"mode", rb_stat_mode},
00757 {"nlink", rb_stat_nlink},
00758 {"uid", rb_stat_uid},
00759 {"gid", rb_stat_gid},
00760 {"rdev", rb_stat_rdev},
00761 {"size", rb_stat_size},
00762 {"blksize", rb_stat_blksize},
00763 {"blocks", rb_stat_blocks},
00764 {"atime", rb_stat_atime},
00765 {"mtime", rb_stat_mtime},
00766 {"ctime", rb_stat_ctime},
00767 };
00768
00769 struct stat* st;
00770 TypedData_Get_Struct(self, struct stat, &stat_data_type, st);
00771 if (!st) {
00772 return rb_sprintf("#<%s: uninitialized>", rb_obj_classname(self));
00773 }
00774
00775 str = rb_str_buf_new2("#<");
00776 rb_str_buf_cat2(str, rb_obj_classname(self));
00777 rb_str_buf_cat2(str, " ");
00778
00779 for (i = 0; i < sizeof(member)/sizeof(member[0]); i++) {
00780 VALUE v;
00781
00782 if (i > 0) {
00783 rb_str_buf_cat2(str, ", ");
00784 }
00785 rb_str_buf_cat2(str, member[i].name);
00786 rb_str_buf_cat2(str, "=");
00787 v = (*member[i].func)(self);
00788 if (i == 2) {
00789 rb_str_catf(str, "0%lo", (unsigned long)NUM2ULONG(v));
00790 }
00791 else if (i == 0 || i == 6) {
00792 rb_str_catf(str, "0x%"PRI_DEVT_PREFIX"x", NUM2DEVT(v));
00793 }
00794 else {
00795 rb_str_append(str, rb_inspect(v));
00796 }
00797 }
00798 rb_str_buf_cat2(str, ">");
00799 OBJ_INFECT(str, self);
00800
00801 return str;
00802 }
00803
00804 static int
00805 rb_stat(VALUE file, struct stat *st)
00806 {
00807 VALUE tmp;
00808
00809 rb_secure(2);
00810 tmp = rb_check_convert_type(file, T_FILE, "IO", "to_io");
00811 if (!NIL_P(tmp)) {
00812 rb_io_t *fptr;
00813
00814 GetOpenFile(tmp, fptr);
00815 return fstat(fptr->fd, st);
00816 }
00817 FilePathValue(file);
00818 file = rb_str_encode_ospath(file);
00819 return STAT(StringValueCStr(file), st);
00820 }
00821
00822 #ifdef _WIN32
00823 static HANDLE
00824 w32_io_info(VALUE *file, BY_HANDLE_FILE_INFORMATION *st)
00825 {
00826 VALUE tmp;
00827 HANDLE f, ret = 0;
00828
00829 tmp = rb_check_convert_type(*file, T_FILE, "IO", "to_io");
00830 if (!NIL_P(tmp)) {
00831 rb_io_t *fptr;
00832
00833 GetOpenFile(tmp, fptr);
00834 f = (HANDLE)rb_w32_get_osfhandle(fptr->fd);
00835 if (f == (HANDLE)-1) return INVALID_HANDLE_VALUE;
00836 }
00837 else {
00838 VALUE tmp;
00839 WCHAR *ptr;
00840 int len;
00841 VALUE v;
00842
00843 FilePathValue(*file);
00844 tmp = rb_str_encode_ospath(*file);
00845 len = MultiByteToWideChar(CP_UTF8, 0, RSTRING_PTR(tmp), -1, NULL, 0);
00846 ptr = ALLOCV_N(WCHAR, v, len);
00847 MultiByteToWideChar(CP_UTF8, 0, RSTRING_PTR(tmp), -1, ptr, len);
00848 f = CreateFileW(ptr, 0,
00849 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
00850 rb_w32_iswin95() ? 0 : FILE_FLAG_BACKUP_SEMANTICS,
00851 NULL);
00852 ALLOCV_END(v);
00853 if (f == INVALID_HANDLE_VALUE) return f;
00854 ret = f;
00855 }
00856 if (GetFileType(f) == FILE_TYPE_DISK) {
00857 ZeroMemory(st, sizeof(*st));
00858 if (GetFileInformationByHandle(f, st)) return ret;
00859 }
00860 if (ret) CloseHandle(ret);
00861 return INVALID_HANDLE_VALUE;
00862 }
00863 #endif
00864
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874
00875
00876 static VALUE
00877 rb_file_s_stat(VALUE klass, VALUE fname)
00878 {
00879 struct stat st;
00880
00881 rb_secure(4);
00882 FilePathValue(fname);
00883 if (rb_stat(fname, &st) < 0) {
00884 rb_sys_fail_path(fname);
00885 }
00886 return stat_new(&st);
00887 }
00888
00889
00890
00891
00892
00893
00894
00895
00896
00897
00898
00899
00900
00901
00902
00903
00904 static VALUE
00905 rb_io_stat(VALUE obj)
00906 {
00907 rb_io_t *fptr;
00908 struct stat st;
00909
00910 GetOpenFile(obj, fptr);
00911 if (fstat(fptr->fd, &st) == -1) {
00912 rb_sys_fail_path(fptr->pathv);
00913 }
00914 return stat_new(&st);
00915 }
00916
00917
00918
00919
00920
00921
00922
00923
00924
00925
00926
00927
00928
00929
00930
00931 static VALUE
00932 rb_file_s_lstat(VALUE klass, VALUE fname)
00933 {
00934 #ifdef HAVE_LSTAT
00935 struct stat st;
00936
00937 rb_secure(2);
00938 FilePathValue(fname);
00939 fname = rb_str_encode_ospath(fname);
00940 if (lstat(StringValueCStr(fname), &st) == -1) {
00941 rb_sys_fail_path(fname);
00942 }
00943 return stat_new(&st);
00944 #else
00945 return rb_file_s_stat(klass, fname);
00946 #endif
00947 }
00948
00949
00950
00951
00952
00953
00954
00955
00956
00957
00958
00959
00960
00961
00962
00963 static VALUE
00964 rb_file_lstat(VALUE obj)
00965 {
00966 #ifdef HAVE_LSTAT
00967 rb_io_t *fptr;
00968 struct stat st;
00969 VALUE path;
00970
00971 rb_secure(2);
00972 GetOpenFile(obj, fptr);
00973 if (NIL_P(fptr->pathv)) return Qnil;
00974 path = rb_str_encode_ospath(fptr->pathv);
00975 if (lstat(RSTRING_PTR(path), &st) == -1) {
00976 rb_sys_fail_path(fptr->pathv);
00977 }
00978 return stat_new(&st);
00979 #else
00980 return rb_io_stat(obj);
00981 #endif
00982 }
00983
00984 static int
00985 rb_group_member(GETGROUPS_T gid)
00986 {
00987 int rv = FALSE;
00988 #ifndef _WIN32
00989 if (getgid() == gid || getegid() == gid)
00990 return TRUE;
00991
00992 # ifdef HAVE_GETGROUPS
00993 # ifndef NGROUPS
00994 # ifdef NGROUPS_MAX
00995 # define NGROUPS NGROUPS_MAX
00996 # else
00997 # define NGROUPS 32
00998 # endif
00999 # endif
01000 {
01001 GETGROUPS_T *gary;
01002 int anum;
01003
01004 gary = xmalloc(NGROUPS * sizeof(GETGROUPS_T));
01005 anum = getgroups(NGROUPS, gary);
01006 while (--anum >= 0) {
01007 if (gary[anum] == gid) {
01008 rv = TRUE;
01009 break;
01010 }
01011 }
01012 xfree(gary);
01013 }
01014 # endif
01015 #endif
01016 return rv;
01017 }
01018
01019 #ifndef S_IXUGO
01020 # define S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH)
01021 #endif
01022
01023 #if defined(S_IXGRP) && !defined(_WIN32) && !defined(__CYGWIN__)
01024 #define USE_GETEUID 1
01025 #endif
01026
01027 #ifndef HAVE_EACCESS
01028 int
01029 eaccess(const char *path, int mode)
01030 {
01031 #ifdef USE_GETEUID
01032 struct stat st;
01033 rb_uid_t euid;
01034
01035 if (STAT(path, &st) < 0)
01036 return -1;
01037
01038 euid = geteuid();
01039
01040 if (euid == 0) {
01041
01042 if (!(mode & X_OK))
01043 return 0;
01044
01045
01046
01047 if (st.st_mode & S_IXUGO)
01048 return 0;
01049
01050 return -1;
01051 }
01052
01053 if (st.st_uid == euid)
01054 mode <<= 6;
01055 else if (rb_group_member(st.st_gid))
01056 mode <<= 3;
01057
01058 if ((int)(st.st_mode & mode) == mode) return 0;
01059
01060 return -1;
01061 #else
01062 return access(path, mode);
01063 #endif
01064 }
01065 #endif
01066
01067 static inline int
01068 access_internal(const char *path, int mode)
01069 {
01070 return access(path, mode);
01071 }
01072
01073
01074
01075
01076
01077
01078
01079
01080
01081
01082
01083
01084
01085
01086
01087
01088
01089
01090
01091
01092
01093
01094
01095
01096
01097
01098
01099
01100
01101
01102
01103
01104
01105
01106
01107
01108
01109 VALUE
01110 rb_file_directory_p(VALUE obj, VALUE fname)
01111 {
01112 #ifndef S_ISDIR
01113 # define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
01114 #endif
01115
01116 struct stat st;
01117
01118 if (rb_stat(fname, &st) < 0) return Qfalse;
01119 if (S_ISDIR(st.st_mode)) return Qtrue;
01120 return Qfalse;
01121 }
01122
01123
01124
01125
01126
01127
01128
01129
01130 static VALUE
01131 rb_file_pipe_p(VALUE obj, VALUE fname)
01132 {
01133 #ifdef S_IFIFO
01134 # ifndef S_ISFIFO
01135 # define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
01136 # endif
01137
01138 struct stat st;
01139
01140 if (rb_stat(fname, &st) < 0) return Qfalse;
01141 if (S_ISFIFO(st.st_mode)) return Qtrue;
01142
01143 #endif
01144 return Qfalse;
01145 }
01146
01147
01148
01149
01150
01151
01152
01153
01154 static VALUE
01155 rb_file_symlink_p(VALUE obj, VALUE fname)
01156 {
01157 #ifndef S_ISLNK
01158 # ifdef _S_ISLNK
01159 # define S_ISLNK(m) _S_ISLNK(m)
01160 # else
01161 # ifdef _S_IFLNK
01162 # define S_ISLNK(m) (((m) & S_IFMT) == _S_IFLNK)
01163 # else
01164 # ifdef S_IFLNK
01165 # define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
01166 # endif
01167 # endif
01168 # endif
01169 #endif
01170
01171 #ifdef S_ISLNK
01172 struct stat st;
01173
01174 rb_secure(2);
01175 FilePathValue(fname);
01176 fname = rb_str_encode_ospath(fname);
01177 if (lstat(StringValueCStr(fname), &st) < 0) return Qfalse;
01178 if (S_ISLNK(st.st_mode)) return Qtrue;
01179 #endif
01180
01181 return Qfalse;
01182 }
01183
01184
01185
01186
01187
01188
01189
01190
01191 static VALUE
01192 rb_file_socket_p(VALUE obj, VALUE fname)
01193 {
01194 #ifndef S_ISSOCK
01195 # ifdef _S_ISSOCK
01196 # define S_ISSOCK(m) _S_ISSOCK(m)
01197 # else
01198 # ifdef _S_IFSOCK
01199 # define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
01200 # else
01201 # ifdef S_IFSOCK
01202 # define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
01203 # endif
01204 # endif
01205 # endif
01206 #endif
01207
01208 #ifdef S_ISSOCK
01209 struct stat st;
01210
01211 if (rb_stat(fname, &st) < 0) return Qfalse;
01212 if (S_ISSOCK(st.st_mode)) return Qtrue;
01213
01214 #endif
01215 return Qfalse;
01216 }
01217
01218
01219
01220
01221
01222
01223
01224
01225 static VALUE
01226 rb_file_blockdev_p(VALUE obj, VALUE fname)
01227 {
01228 #ifndef S_ISBLK
01229 # ifdef S_IFBLK
01230 # define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
01231 # else
01232 # define S_ISBLK(m) (0)
01233 # endif
01234 #endif
01235
01236 #ifdef S_ISBLK
01237 struct stat st;
01238
01239 if (rb_stat(fname, &st) < 0) return Qfalse;
01240 if (S_ISBLK(st.st_mode)) return Qtrue;
01241
01242 #endif
01243 return Qfalse;
01244 }
01245
01246
01247
01248
01249
01250
01251
01252 static VALUE
01253 rb_file_chardev_p(VALUE obj, VALUE fname)
01254 {
01255 #ifndef S_ISCHR
01256 # define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
01257 #endif
01258
01259 struct stat st;
01260
01261 if (rb_stat(fname, &st) < 0) return Qfalse;
01262 if (S_ISCHR(st.st_mode)) return Qtrue;
01263
01264 return Qfalse;
01265 }
01266
01267
01268
01269
01270
01271
01272
01273
01274
01275 static VALUE
01276 rb_file_exist_p(VALUE obj, VALUE fname)
01277 {
01278 struct stat st;
01279
01280 if (rb_stat(fname, &st) < 0) return Qfalse;
01281 return Qtrue;
01282 }
01283
01284
01285
01286
01287
01288
01289
01290
01291
01292 static VALUE
01293 rb_file_readable_p(VALUE obj, VALUE fname)
01294 {
01295 rb_secure(2);
01296 FilePathValue(fname);
01297 fname = rb_str_encode_ospath(fname);
01298 if (eaccess(StringValueCStr(fname), R_OK) < 0) return Qfalse;
01299 return Qtrue;
01300 }
01301
01302
01303
01304
01305
01306
01307
01308
01309
01310 static VALUE
01311 rb_file_readable_real_p(VALUE obj, VALUE fname)
01312 {
01313 rb_secure(2);
01314 FilePathValue(fname);
01315 fname = rb_str_encode_ospath(fname);
01316 if (access_internal(StringValueCStr(fname), R_OK) < 0) return Qfalse;
01317 return Qtrue;
01318 }
01319
01320 #ifndef S_IRUGO
01321 # define S_IRUGO (S_IRUSR | S_IRGRP | S_IROTH)
01322 #endif
01323
01324 #ifndef S_IWUGO
01325 # define S_IWUGO (S_IWUSR | S_IWGRP | S_IWOTH)
01326 #endif
01327
01328
01329
01330
01331
01332
01333
01334
01335
01336
01337
01338
01339
01340
01341
01342 static VALUE
01343 rb_file_world_readable_p(VALUE obj, VALUE fname)
01344 {
01345 #ifdef S_IROTH
01346 struct stat st;
01347
01348 if (rb_stat(fname, &st) < 0) return Qnil;
01349 if ((st.st_mode & (S_IROTH)) == S_IROTH) {
01350 return UINT2NUM(st.st_mode & (S_IRUGO|S_IWUGO|S_IXUGO));
01351 }
01352 #endif
01353 return Qnil;
01354 }
01355
01356
01357
01358
01359
01360
01361
01362
01363
01364 static VALUE
01365 rb_file_writable_p(VALUE obj, VALUE fname)
01366 {
01367 rb_secure(2);
01368 FilePathValue(fname);
01369 fname = rb_str_encode_ospath(fname);
01370 if (eaccess(StringValueCStr(fname), W_OK) < 0) return Qfalse;
01371 return Qtrue;
01372 }
01373
01374
01375
01376
01377
01378
01379
01380
01381
01382 static VALUE
01383 rb_file_writable_real_p(VALUE obj, VALUE fname)
01384 {
01385 rb_secure(2);
01386 FilePathValue(fname);
01387 fname = rb_str_encode_ospath(fname);
01388 if (access_internal(StringValueCStr(fname), W_OK) < 0) return Qfalse;
01389 return Qtrue;
01390 }
01391
01392
01393
01394
01395
01396
01397
01398
01399
01400
01401
01402
01403
01404
01405
01406 static VALUE
01407 rb_file_world_writable_p(VALUE obj, VALUE fname)
01408 {
01409 #ifdef S_IWOTH
01410 struct stat st;
01411
01412 if (rb_stat(fname, &st) < 0) return Qnil;
01413 if ((st.st_mode & (S_IWOTH)) == S_IWOTH) {
01414 return UINT2NUM(st.st_mode & (S_IRUGO|S_IWUGO|S_IXUGO));
01415 }
01416 #endif
01417 return Qnil;
01418 }
01419
01420
01421
01422
01423
01424
01425
01426
01427
01428 static VALUE
01429 rb_file_executable_p(VALUE obj, VALUE fname)
01430 {
01431 rb_secure(2);
01432 FilePathValue(fname);
01433 fname = rb_str_encode_ospath(fname);
01434 if (eaccess(StringValueCStr(fname), X_OK) < 0) return Qfalse;
01435 return Qtrue;
01436 }
01437
01438
01439
01440
01441
01442
01443
01444
01445
01446 static VALUE
01447 rb_file_executable_real_p(VALUE obj, VALUE fname)
01448 {
01449 rb_secure(2);
01450 FilePathValue(fname);
01451 fname = rb_str_encode_ospath(fname);
01452 if (access_internal(StringValueCStr(fname), X_OK) < 0) return Qfalse;
01453 return Qtrue;
01454 }
01455
01456 #ifndef S_ISREG
01457 # define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
01458 #endif
01459
01460
01461
01462
01463
01464
01465
01466
01467
01468 static VALUE
01469 rb_file_file_p(VALUE obj, VALUE fname)
01470 {
01471 struct stat st;
01472
01473 if (rb_stat(fname, &st) < 0) return Qfalse;
01474 if (S_ISREG(st.st_mode)) return Qtrue;
01475 return Qfalse;
01476 }
01477
01478
01479
01480
01481
01482
01483
01484
01485
01486 static VALUE
01487 rb_file_zero_p(VALUE obj, VALUE fname)
01488 {
01489 struct stat st;
01490
01491 if (rb_stat(fname, &st) < 0) return Qfalse;
01492 if (st.st_size == 0) return Qtrue;
01493 return Qfalse;
01494 }
01495
01496
01497
01498
01499
01500
01501
01502
01503
01504 static VALUE
01505 rb_file_size_p(VALUE obj, VALUE fname)
01506 {
01507 struct stat st;
01508
01509 if (rb_stat(fname, &st) < 0) return Qnil;
01510 if (st.st_size == 0) return Qnil;
01511 return OFFT2NUM(st.st_size);
01512 }
01513
01514
01515
01516
01517
01518
01519
01520
01521
01522
01523 static VALUE
01524 rb_file_owned_p(VALUE obj, VALUE fname)
01525 {
01526 struct stat st;
01527
01528 if (rb_stat(fname, &st) < 0) return Qfalse;
01529 if (st.st_uid == geteuid()) return Qtrue;
01530 return Qfalse;
01531 }
01532
01533 static VALUE
01534 rb_file_rowned_p(VALUE obj, VALUE fname)
01535 {
01536 struct stat st;
01537
01538 if (rb_stat(fname, &st) < 0) return Qfalse;
01539 if (st.st_uid == getuid()) return Qtrue;
01540 return Qfalse;
01541 }
01542
01543
01544
01545
01546
01547
01548
01549
01550
01551
01552 static VALUE
01553 rb_file_grpowned_p(VALUE obj, VALUE fname)
01554 {
01555 #ifndef _WIN32
01556 struct stat st;
01557
01558 if (rb_stat(fname, &st) < 0) return Qfalse;
01559 if (rb_group_member(st.st_gid)) return Qtrue;
01560 #endif
01561 return Qfalse;
01562 }
01563
01564 #if defined(S_ISUID) || defined(S_ISGID) || defined(S_ISVTX)
01565 static VALUE
01566 check3rdbyte(VALUE fname, int mode)
01567 {
01568 struct stat st;
01569
01570 rb_secure(2);
01571 FilePathValue(fname);
01572 fname = rb_str_encode_ospath(fname);
01573 if (STAT(StringValueCStr(fname), &st) < 0) return Qfalse;
01574 if (st.st_mode & mode) return Qtrue;
01575 return Qfalse;
01576 }
01577 #endif
01578
01579
01580
01581
01582
01583
01584
01585
01586 static VALUE
01587 rb_file_suid_p(VALUE obj, VALUE fname)
01588 {
01589 #ifdef S_ISUID
01590 return check3rdbyte(fname, S_ISUID);
01591 #else
01592 return Qfalse;
01593 #endif
01594 }
01595
01596
01597
01598
01599
01600
01601
01602
01603 static VALUE
01604 rb_file_sgid_p(VALUE obj, VALUE fname)
01605 {
01606 #ifdef S_ISGID
01607 return check3rdbyte(fname, S_ISGID);
01608 #else
01609 return Qfalse;
01610 #endif
01611 }
01612
01613
01614
01615
01616
01617
01618
01619
01620 static VALUE
01621 rb_file_sticky_p(VALUE obj, VALUE fname)
01622 {
01623 #ifdef S_ISVTX
01624 return check3rdbyte(fname, S_ISVTX);
01625 #else
01626 return Qnil;
01627 #endif
01628 }
01629
01630
01631
01632
01633
01634
01635
01636
01637
01638
01639
01640
01641
01642
01643
01644
01645
01646
01647 static VALUE
01648 rb_file_identical_p(VALUE obj, VALUE fname1, VALUE fname2)
01649 {
01650 #ifndef DOSISH
01651 struct stat st1, st2;
01652
01653 if (rb_stat(fname1, &st1) < 0) return Qfalse;
01654 if (rb_stat(fname2, &st2) < 0) return Qfalse;
01655 if (st1.st_dev != st2.st_dev) return Qfalse;
01656 if (st1.st_ino != st2.st_ino) return Qfalse;
01657 #else
01658 # ifdef _WIN32
01659 BY_HANDLE_FILE_INFORMATION st1, st2;
01660 HANDLE f1 = 0, f2 = 0;
01661 # endif
01662
01663 rb_secure(2);
01664 # ifdef _WIN32
01665 f1 = w32_io_info(&fname1, &st1);
01666 if (f1 == INVALID_HANDLE_VALUE) return Qfalse;
01667 f2 = w32_io_info(&fname2, &st2);
01668 if (f1) CloseHandle(f1);
01669 if (f2 == INVALID_HANDLE_VALUE) return Qfalse;
01670 if (f2) CloseHandle(f2);
01671
01672 if (st1.dwVolumeSerialNumber == st2.dwVolumeSerialNumber &&
01673 st1.nFileIndexHigh == st2.nFileIndexHigh &&
01674 st1.nFileIndexLow == st2.nFileIndexLow)
01675 return Qtrue;
01676 if (!f1 || !f2) return Qfalse;
01677 if (rb_w32_iswin95()) return Qfalse;
01678 # else
01679 FilePathValue(fname1);
01680 fname1 = rb_str_new4(fname1);
01681 fname1 = rb_str_encode_ospath(fname1);
01682 FilePathValue(fname2);
01683 fname2 = rb_str_encode_ospath(fname2);
01684 if (access(RSTRING_PTR(fname1), 0)) return Qfalse;
01685 if (access(RSTRING_PTR(fname2), 0)) return Qfalse;
01686 # endif
01687 fname1 = rb_file_expand_path(fname1, Qnil);
01688 fname2 = rb_file_expand_path(fname2, Qnil);
01689 if (RSTRING_LEN(fname1) != RSTRING_LEN(fname2)) return Qfalse;
01690 if (rb_memcicmp(RSTRING_PTR(fname1), RSTRING_PTR(fname2), RSTRING_LEN(fname1)))
01691 return Qfalse;
01692 #endif
01693 return Qtrue;
01694 }
01695
01696
01697
01698
01699
01700
01701
01702
01703 static VALUE
01704 rb_file_s_size(VALUE klass, VALUE fname)
01705 {
01706 struct stat st;
01707
01708 if (rb_stat(fname, &st) < 0) {
01709 FilePathValue(fname);
01710 rb_sys_fail_path(fname);
01711 }
01712 return OFFT2NUM(st.st_size);
01713 }
01714
01715 static VALUE
01716 rb_file_ftype(const struct stat *st)
01717 {
01718 const char *t;
01719
01720 if (S_ISREG(st->st_mode)) {
01721 t = "file";
01722 }
01723 else if (S_ISDIR(st->st_mode)) {
01724 t = "directory";
01725 }
01726 else if (S_ISCHR(st->st_mode)) {
01727 t = "characterSpecial";
01728 }
01729 #ifdef S_ISBLK
01730 else if (S_ISBLK(st->st_mode)) {
01731 t = "blockSpecial";
01732 }
01733 #endif
01734 #ifdef S_ISFIFO
01735 else if (S_ISFIFO(st->st_mode)) {
01736 t = "fifo";
01737 }
01738 #endif
01739 #ifdef S_ISLNK
01740 else if (S_ISLNK(st->st_mode)) {
01741 t = "link";
01742 }
01743 #endif
01744 #ifdef S_ISSOCK
01745 else if (S_ISSOCK(st->st_mode)) {
01746 t = "socket";
01747 }
01748 #endif
01749 else {
01750 t = "unknown";
01751 }
01752
01753 return rb_usascii_str_new2(t);
01754 }
01755
01756
01757
01758
01759
01760
01761
01762
01763
01764
01765
01766
01767
01768
01769
01770
01771 static VALUE
01772 rb_file_s_ftype(VALUE klass, VALUE fname)
01773 {
01774 struct stat st;
01775
01776 rb_secure(2);
01777 FilePathValue(fname);
01778 fname = rb_str_encode_ospath(fname);
01779 if (lstat(StringValueCStr(fname), &st) == -1) {
01780 rb_sys_fail_path(fname);
01781 }
01782
01783 return rb_file_ftype(&st);
01784 }
01785
01786
01787
01788
01789
01790
01791
01792
01793
01794
01795
01796 static VALUE
01797 rb_file_s_atime(VALUE klass, VALUE fname)
01798 {
01799 struct stat st;
01800
01801 if (rb_stat(fname, &st) < 0) {
01802 FilePathValue(fname);
01803 rb_sys_fail_path(fname);
01804 }
01805 return stat_atime(&st);
01806 }
01807
01808
01809
01810
01811
01812
01813
01814
01815
01816
01817
01818
01819 static VALUE
01820 rb_file_atime(VALUE obj)
01821 {
01822 rb_io_t *fptr;
01823 struct stat st;
01824
01825 GetOpenFile(obj, fptr);
01826 if (fstat(fptr->fd, &st) == -1) {
01827 rb_sys_fail_path(fptr->pathv);
01828 }
01829 return stat_atime(&st);
01830 }
01831
01832
01833
01834
01835
01836
01837
01838
01839
01840
01841
01842 static VALUE
01843 rb_file_s_mtime(VALUE klass, VALUE fname)
01844 {
01845 struct stat st;
01846
01847 if (rb_stat(fname, &st) < 0) {
01848 FilePathValue(fname);
01849 rb_sys_fail_path(fname);
01850 }
01851 return stat_mtime(&st);
01852 }
01853
01854
01855
01856
01857
01858
01859
01860
01861
01862
01863
01864 static VALUE
01865 rb_file_mtime(VALUE obj)
01866 {
01867 rb_io_t *fptr;
01868 struct stat st;
01869
01870 GetOpenFile(obj, fptr);
01871 if (fstat(fptr->fd, &st) == -1) {
01872 rb_sys_fail_path(fptr->pathv);
01873 }
01874 return stat_mtime(&st);
01875 }
01876
01877
01878
01879
01880
01881
01882
01883
01884
01885
01886
01887
01888
01889
01890
01891 static VALUE
01892 rb_file_s_ctime(VALUE klass, VALUE fname)
01893 {
01894 struct stat st;
01895
01896 if (rb_stat(fname, &st) < 0) {
01897 FilePathValue(fname);
01898 rb_sys_fail_path(fname);
01899 }
01900 return stat_ctime(&st);
01901 }
01902
01903
01904
01905
01906
01907
01908
01909
01910
01911
01912
01913
01914
01915
01916 static VALUE
01917 rb_file_ctime(VALUE obj)
01918 {
01919 rb_io_t *fptr;
01920 struct stat st;
01921
01922 GetOpenFile(obj, fptr);
01923 if (fstat(fptr->fd, &st) == -1) {
01924 rb_sys_fail_path(fptr->pathv);
01925 }
01926 return stat_ctime(&st);
01927 }
01928
01929
01930
01931
01932
01933
01934
01935
01936
01937
01938
01939 static VALUE
01940 rb_file_size(VALUE obj)
01941 {
01942 rb_io_t *fptr;
01943 struct stat st;
01944
01945 GetOpenFile(obj, fptr);
01946 if (fptr->mode & FMODE_WRITABLE) {
01947 rb_io_flush(obj);
01948 }
01949 if (fstat(fptr->fd, &st) == -1) {
01950 rb_sys_fail_path(fptr->pathv);
01951 }
01952 return OFFT2NUM(st.st_size);
01953 }
01954
01955 static void
01956 chmod_internal(const char *path, VALUE pathv, void *mode)
01957 {
01958 if (chmod(path, *(int *)mode) < 0)
01959 rb_sys_fail_path(pathv);
01960 }
01961
01962
01963
01964
01965
01966
01967
01968
01969
01970
01971
01972
01973
01974
01975 static VALUE
01976 rb_file_s_chmod(int argc, VALUE *argv)
01977 {
01978 VALUE vmode;
01979 VALUE rest;
01980 int mode;
01981 long n;
01982
01983 rb_secure(2);
01984 rb_scan_args(argc, argv, "1*", &vmode, &rest);
01985 mode = NUM2INT(vmode);
01986
01987 n = apply2files(chmod_internal, rest, &mode);
01988 return LONG2FIX(n);
01989 }
01990
01991
01992
01993
01994
01995
01996
01997
01998
01999
02000
02001
02002
02003
02004 static VALUE
02005 rb_file_chmod(VALUE obj, VALUE vmode)
02006 {
02007 rb_io_t *fptr;
02008 int mode;
02009 #ifndef HAVE_FCHMOD
02010 VALUE path;
02011 #endif
02012
02013 rb_secure(2);
02014 mode = NUM2INT(vmode);
02015
02016 GetOpenFile(obj, fptr);
02017 #ifdef HAVE_FCHMOD
02018 if (fchmod(fptr->fd, mode) == -1)
02019 rb_sys_fail_path(fptr->pathv);
02020 #else
02021 if (NIL_P(fptr->pathv)) return Qnil;
02022 path = rb_str_encode_ospath(fptr->pathv);
02023 if (chmod(RSTRING_PTR(path), mode) == -1)
02024 rb_sys_fail_path(fptr->pathv);
02025 #endif
02026
02027 return INT2FIX(0);
02028 }
02029
02030 #if defined(HAVE_LCHMOD)
02031 static void
02032 lchmod_internal(const char *path, VALUE pathv, void *mode)
02033 {
02034 if (lchmod(path, (int)(VALUE)mode) < 0)
02035 rb_sys_fail_path(pathv);
02036 }
02037
02038
02039
02040
02041
02042
02043
02044
02045
02046
02047
02048 static VALUE
02049 rb_file_s_lchmod(int argc, VALUE *argv)
02050 {
02051 VALUE vmode;
02052 VALUE rest;
02053 long mode, n;
02054
02055 rb_secure(2);
02056 rb_scan_args(argc, argv, "1*", &vmode, &rest);
02057 mode = NUM2INT(vmode);
02058
02059 n = apply2files(lchmod_internal, rest, (void *)(long)mode);
02060 return LONG2FIX(n);
02061 }
02062 #else
02063 #define rb_file_s_lchmod rb_f_notimplement
02064 #endif
02065
02066 struct chown_args {
02067 rb_uid_t owner;
02068 rb_gid_t group;
02069 };
02070
02071 static void
02072 chown_internal(const char *path, VALUE pathv, void *arg)
02073 {
02074 struct chown_args *args = arg;
02075 if (chown(path, args->owner, args->group) < 0)
02076 rb_sys_fail_path(pathv);
02077 }
02078
02079
02080
02081
02082
02083
02084
02085
02086
02087
02088
02089
02090
02091
02092
02093
02094 static VALUE
02095 rb_file_s_chown(int argc, VALUE *argv)
02096 {
02097 VALUE o, g, rest;
02098 struct chown_args arg;
02099 long n;
02100
02101 rb_secure(2);
02102 rb_scan_args(argc, argv, "2*", &o, &g, &rest);
02103 if (NIL_P(o)) {
02104 arg.owner = -1;
02105 }
02106 else {
02107 arg.owner = NUM2UIDT(o);
02108 }
02109 if (NIL_P(g)) {
02110 arg.group = -1;
02111 }
02112 else {
02113 arg.group = NUM2GIDT(g);
02114 }
02115
02116 n = apply2files(chown_internal, rest, &arg);
02117 return LONG2FIX(n);
02118 }
02119
02120
02121
02122
02123
02124
02125
02126
02127
02128
02129
02130
02131
02132
02133
02134
02135 static VALUE
02136 rb_file_chown(VALUE obj, VALUE owner, VALUE group)
02137 {
02138 rb_io_t *fptr;
02139 int o, g;
02140 #ifndef HAVE_FCHOWN
02141 VALUE path;
02142 #endif
02143
02144 rb_secure(2);
02145 o = NIL_P(owner) ? -1 : NUM2INT(owner);
02146 g = NIL_P(group) ? -1 : NUM2INT(group);
02147 GetOpenFile(obj, fptr);
02148 #ifndef HAVE_FCHOWN
02149 if (NIL_P(fptr->pathv)) return Qnil;
02150 path = rb_str_encode_ospath(fptr->pathv);
02151 if (chown(RSTRING_PTR(path), o, g) == -1)
02152 rb_sys_fail_path(fptr->pathv);
02153 #else
02154 if (fchown(fptr->fd, o, g) == -1)
02155 rb_sys_fail_path(fptr->pathv);
02156 #endif
02157
02158 return INT2FIX(0);
02159 }
02160
02161 #if defined(HAVE_LCHOWN)
02162 static void
02163 lchown_internal(const char *path, VALUE pathv, void *arg)
02164 {
02165 struct chown_args *args = arg;
02166 if (lchown(path, args->owner, args->group) < 0)
02167 rb_sys_fail_path(pathv);
02168 }
02169
02170
02171
02172
02173
02174
02175
02176
02177
02178
02179
02180
02181 static VALUE
02182 rb_file_s_lchown(int argc, VALUE *argv)
02183 {
02184 VALUE o, g, rest;
02185 struct chown_args arg;
02186 long n;
02187
02188 rb_secure(2);
02189 rb_scan_args(argc, argv, "2*", &o, &g, &rest);
02190 if (NIL_P(o)) {
02191 arg.owner = -1;
02192 }
02193 else {
02194 arg.owner = NUM2UIDT(o);
02195 }
02196 if (NIL_P(g)) {
02197 arg.group = -1;
02198 }
02199 else {
02200 arg.group = NUM2GIDT(g);
02201 }
02202
02203 n = apply2files(lchown_internal, rest, &arg);
02204 return LONG2FIX(n);
02205 }
02206 #else
02207 #define rb_file_s_lchown rb_f_notimplement
02208 #endif
02209
02210 struct utime_args {
02211 const struct timespec* tsp;
02212 VALUE atime, mtime;
02213 };
02214
02215 #if defined DOSISH || defined __CYGWIN__
02216 NORETURN(static void utime_failed(VALUE, const struct timespec *, VALUE, VALUE));
02217
02218 static void
02219 utime_failed(VALUE path, const struct timespec *tsp, VALUE atime, VALUE mtime)
02220 {
02221 if (tsp && errno == EINVAL) {
02222 VALUE e[2], a = Qnil, m = Qnil;
02223 int d = 0;
02224 if (!NIL_P(atime)) {
02225 a = rb_inspect(atime);
02226 }
02227 if (!NIL_P(mtime) && mtime != atime && !rb_equal(atime, mtime)) {
02228 m = rb_inspect(mtime);
02229 }
02230 if (NIL_P(a)) e[0] = m;
02231 else if (NIL_P(m) || rb_str_cmp(a, m) == 0) e[0] = a;
02232 else {
02233 e[0] = rb_str_plus(a, rb_str_new_cstr(" or "));
02234 rb_str_append(e[0], m);
02235 d = 1;
02236 }
02237 if (!NIL_P(e[0])) {
02238 if (path) {
02239 if (!d) e[0] = rb_str_dup(e[0]);
02240 rb_str_append(rb_str_cat2(e[0], " for "), path);
02241 }
02242 e[1] = INT2FIX(EINVAL);
02243 rb_exc_raise(rb_class_new_instance(2, e, rb_eSystemCallError));
02244 }
02245 errno = EINVAL;
02246 }
02247 rb_sys_fail_path(path);
02248 }
02249 #else
02250 #define utime_failed(path, tsp, atime, mtime) rb_sys_fail_path(path)
02251 #endif
02252
02253 #if defined(HAVE_UTIMES)
02254
02255 static void
02256 utime_internal(const char *path, VALUE pathv, void *arg)
02257 {
02258 struct utime_args *v = arg;
02259 const struct timespec *tsp = v->tsp;
02260 struct timeval tvbuf[2], *tvp = NULL;
02261
02262 #ifdef HAVE_UTIMENSAT
02263 static int try_utimensat = 1;
02264
02265 if (try_utimensat) {
02266 if (utimensat(AT_FDCWD, path, tsp, 0) < 0) {
02267 if (errno == ENOSYS) {
02268 try_utimensat = 0;
02269 goto no_utimensat;
02270 }
02271 utime_failed(pathv, tsp, v->atime, v->mtime);
02272 }
02273 return;
02274 }
02275 no_utimensat:
02276 #endif
02277
02278 if (tsp) {
02279 tvbuf[0].tv_sec = tsp[0].tv_sec;
02280 tvbuf[0].tv_usec = (int)(tsp[0].tv_nsec / 1000);
02281 tvbuf[1].tv_sec = tsp[1].tv_sec;
02282 tvbuf[1].tv_usec = (int)(tsp[1].tv_nsec / 1000);
02283 tvp = tvbuf;
02284 }
02285 if (utimes(path, tvp) < 0)
02286 utime_failed(pathv, tsp, v->atime, v->mtime);
02287 }
02288
02289 #else
02290
02291 #if !defined HAVE_UTIME_H && !defined HAVE_SYS_UTIME_H
02292 struct utimbuf {
02293 long actime;
02294 long modtime;
02295 };
02296 #endif
02297
02298 static void
02299 utime_internal(const char *path, VALUE pathv, void *arg)
02300 {
02301 struct utime_args *v = arg;
02302 const struct timespec *tsp = v->tsp;
02303 struct utimbuf utbuf, *utp = NULL;
02304 if (tsp) {
02305 utbuf.actime = tsp[0].tv_sec;
02306 utbuf.modtime = tsp[1].tv_sec;
02307 utp = &utbuf;
02308 }
02309 if (utime(path, utp) < 0)
02310 utime_failed(pathv, tsp, v->atime, v->mtime);
02311 }
02312
02313 #endif
02314
02315
02316
02317
02318
02319
02320
02321
02322
02323
02324 static VALUE
02325 rb_file_s_utime(int argc, VALUE *argv)
02326 {
02327 VALUE rest;
02328 struct utime_args args;
02329 struct timespec tss[2], *tsp = NULL;
02330 long n;
02331
02332 rb_secure(2);
02333 rb_scan_args(argc, argv, "2*", &args.atime, &args.mtime, &rest);
02334
02335 if (!NIL_P(args.atime) || !NIL_P(args.mtime)) {
02336 tsp = tss;
02337 tsp[0] = rb_time_timespec(args.atime);
02338 tsp[1] = rb_time_timespec(args.mtime);
02339 }
02340 args.tsp = tsp;
02341
02342 n = apply2files(utime_internal, rest, &args);
02343 return LONG2FIX(n);
02344 }
02345
02346 NORETURN(static void sys_fail2(VALUE,VALUE));
02347 static void
02348 sys_fail2(VALUE s1, VALUE s2)
02349 {
02350 VALUE str;
02351 #ifdef MAX_PATH
02352 const int max_pathlen = MAX_PATH;
02353 #else
02354 const int max_pathlen = MAXPATHLEN;
02355 #endif
02356
02357 str = rb_str_new_cstr("(");
02358 rb_str_append(str, rb_str_ellipsize(s1, max_pathlen));
02359 rb_str_cat2(str, ", ");
02360 rb_str_append(str, rb_str_ellipsize(s2, max_pathlen));
02361 rb_str_cat2(str, ")");
02362 rb_sys_fail_path(str);
02363 }
02364
02365 #ifdef HAVE_LINK
02366
02367
02368
02369
02370
02371
02372
02373
02374
02375
02376
02377
02378 static VALUE
02379 rb_file_s_link(VALUE klass, VALUE from, VALUE to)
02380 {
02381 rb_secure(2);
02382 FilePathValue(from);
02383 FilePathValue(to);
02384 from = rb_str_encode_ospath(from);
02385 to = rb_str_encode_ospath(to);
02386
02387 if (link(StringValueCStr(from), StringValueCStr(to)) < 0) {
02388 sys_fail2(from, to);
02389 }
02390 return INT2FIX(0);
02391 }
02392 #else
02393 #define rb_file_s_link rb_f_notimplement
02394 #endif
02395
02396 #ifdef HAVE_SYMLINK
02397
02398
02399
02400
02401
02402
02403
02404
02405
02406
02407
02408
02409 static VALUE
02410 rb_file_s_symlink(VALUE klass, VALUE from, VALUE to)
02411 {
02412 rb_secure(2);
02413 FilePathValue(from);
02414 FilePathValue(to);
02415 from = rb_str_encode_ospath(from);
02416 to = rb_str_encode_ospath(to);
02417
02418 if (symlink(StringValueCStr(from), StringValueCStr(to)) < 0) {
02419 sys_fail2(from, to);
02420 }
02421 return INT2FIX(0);
02422 }
02423 #else
02424 #define rb_file_s_symlink rb_f_notimplement
02425 #endif
02426
02427 #ifdef HAVE_READLINK
02428
02429
02430
02431
02432
02433
02434
02435
02436
02437
02438
02439 static VALUE
02440 rb_file_s_readlink(VALUE klass, VALUE path)
02441 {
02442 char *buf;
02443 int size = 100;
02444 ssize_t rv;
02445 VALUE v;
02446
02447 rb_secure(2);
02448 FilePathValue(path);
02449 path = rb_str_encode_ospath(path);
02450 buf = xmalloc(size);
02451 while ((rv = readlink(RSTRING_PTR(path), buf, size)) == size
02452 #ifdef _AIX
02453 || (rv < 0 && errno == ERANGE)
02454 #endif
02455 ) {
02456 size *= 2;
02457 buf = xrealloc(buf, size);
02458 }
02459 if (rv < 0) {
02460 xfree(buf);
02461 rb_sys_fail_path(path);
02462 }
02463 v = rb_filesystem_str_new(buf, rv);
02464 xfree(buf);
02465
02466 return v;
02467 }
02468 #else
02469 #define rb_file_s_readlink rb_f_notimplement
02470 #endif
02471
02472 static void
02473 unlink_internal(const char *path, VALUE pathv, void *arg)
02474 {
02475 if (unlink(path) < 0)
02476 rb_sys_fail_path(pathv);
02477 }
02478
02479
02480
02481
02482
02483
02484
02485
02486
02487
02488
02489 static VALUE
02490 rb_file_s_unlink(VALUE klass, VALUE args)
02491 {
02492 long n;
02493
02494 rb_secure(2);
02495 n = apply2files(unlink_internal, args, 0);
02496 return LONG2FIX(n);
02497 }
02498
02499
02500
02501
02502
02503
02504
02505
02506
02507
02508
02509 static VALUE
02510 rb_file_s_rename(VALUE klass, VALUE from, VALUE to)
02511 {
02512 const char *src, *dst;
02513 VALUE f, t;
02514
02515 rb_secure(2);
02516 FilePathValue(from);
02517 FilePathValue(to);
02518 f = rb_str_encode_ospath(from);
02519 t = rb_str_encode_ospath(to);
02520 src = StringValueCStr(f);
02521 dst = StringValueCStr(t);
02522 #if defined __CYGWIN__
02523 errno = 0;
02524 #endif
02525 if (rename(src, dst) < 0) {
02526 #if defined DOSISH
02527 switch (errno) {
02528 case EEXIST:
02529 #if defined (__EMX__)
02530 case EACCES:
02531 #endif
02532 if (chmod(dst, 0666) == 0 &&
02533 unlink(dst) == 0 &&
02534 rename(src, dst) == 0)
02535 return INT2FIX(0);
02536 }
02537 #endif
02538 sys_fail2(from, to);
02539 }
02540
02541 return INT2FIX(0);
02542 }
02543
02544
02545
02546
02547
02548
02549
02550
02551
02552
02553
02554
02555
02556
02557
02558
02559 static VALUE
02560 rb_file_s_umask(int argc, VALUE *argv)
02561 {
02562 int omask = 0;
02563
02564 rb_secure(2);
02565 if (argc == 0) {
02566 omask = umask(0);
02567 umask(omask);
02568 }
02569 else if (argc == 1) {
02570 omask = umask(NUM2INT(argv[0]));
02571 }
02572 else {
02573 rb_raise(rb_eArgError, "wrong number of arguments (%d for 0..1)", argc);
02574 }
02575 return INT2FIX(omask);
02576 }
02577
02578 #ifdef __CYGWIN__
02579 #undef DOSISH
02580 #endif
02581 #if defined __CYGWIN__ || defined DOSISH
02582 #define DOSISH_UNC
02583 #define DOSISH_DRIVE_LETTER
02584 #define FILE_ALT_SEPARATOR '\\'
02585 #endif
02586 #ifdef FILE_ALT_SEPARATOR
02587 #define isdirsep(x) ((x) == '/' || (x) == FILE_ALT_SEPARATOR)
02588 static const char file_alt_separator[] = {FILE_ALT_SEPARATOR, '\0'};
02589 #else
02590 #define isdirsep(x) ((x) == '/')
02591 #endif
02592
02593 #ifndef USE_NTFS
02594 #if defined _WIN32 || defined __CYGWIN__
02595 #define USE_NTFS 1
02596 #else
02597 #define USE_NTFS 0
02598 #endif
02599 #endif
02600
02601 #if USE_NTFS
02602 #define istrailinggarbage(x) ((x) == '.' || (x) == ' ')
02603 #else
02604 #define istrailinggarbage(x) 0
02605 #endif
02606
02607 #ifndef CharNext
02608 # define CharNext(p) ((p) + 1)
02609 #endif
02610
02611 #if defined(DOSISH_UNC)
02612 #define has_unc(buf) (isdirsep((buf)[0]) && isdirsep((buf)[1]))
02613 #else
02614 #define has_unc(buf) 0
02615 #endif
02616
02617 #ifdef DOSISH_DRIVE_LETTER
02618 static inline int
02619 has_drive_letter(const char *buf)
02620 {
02621 if (ISALPHA(buf[0]) && buf[1] == ':') {
02622 return 1;
02623 }
02624 else {
02625 return 0;
02626 }
02627 }
02628
02629 static char*
02630 getcwdofdrv(int drv)
02631 {
02632 char drive[4];
02633 char *drvcwd, *oldcwd;
02634
02635 drive[0] = drv;
02636 drive[1] = ':';
02637 drive[2] = '\0';
02638
02639
02640
02641
02642
02643 oldcwd = my_getcwd();
02644 if (chdir(drive) == 0) {
02645 drvcwd = my_getcwd();
02646 chdir(oldcwd);
02647 xfree(oldcwd);
02648 }
02649 else {
02650
02651 drvcwd = strdup(drive);
02652 }
02653 return drvcwd;
02654 }
02655
02656 static inline int
02657 not_same_drive(VALUE path, int drive)
02658 {
02659 const char *p = RSTRING_PTR(path);
02660 if (RSTRING_LEN(path) < 2) return 0;
02661 if (has_drive_letter(p)) {
02662 return TOLOWER(p[0]) != TOLOWER(drive);
02663 }
02664 else {
02665 return has_unc(p);
02666 }
02667 }
02668 #endif
02669
02670 static inline char *
02671 skiproot(const char *path)
02672 {
02673 #ifdef DOSISH_DRIVE_LETTER
02674 if (has_drive_letter(path)) path += 2;
02675 #endif
02676 while (isdirsep(*path)) path++;
02677 return (char *)path;
02678 }
02679
02680 #define nextdirsep rb_path_next
02681 char *
02682 rb_path_next(const char *s)
02683 {
02684 while (*s && !isdirsep(*s)) {
02685 s = CharNext(s);
02686 }
02687 return (char *)s;
02688 }
02689
02690 #if defined(DOSISH_UNC) || defined(DOSISH_DRIVE_LETTER)
02691 #define skipprefix rb_path_skip_prefix
02692 #else
02693 #define skipprefix(path) (path)
02694 #endif
02695 char *
02696 rb_path_skip_prefix(const char *path)
02697 {
02698 #if defined(DOSISH_UNC) || defined(DOSISH_DRIVE_LETTER)
02699 #ifdef DOSISH_UNC
02700 if (isdirsep(path[0]) && isdirsep(path[1])) {
02701 path += 2;
02702 while (isdirsep(*path)) path++;
02703 if (*(path = nextdirsep(path)) && path[1] && !isdirsep(path[1]))
02704 path = nextdirsep(path + 1);
02705 return (char *)path;
02706 }
02707 #endif
02708 #ifdef DOSISH_DRIVE_LETTER
02709 if (has_drive_letter(path))
02710 return (char *)(path + 2);
02711 #endif
02712 #endif
02713 return (char *)path;
02714 }
02715
02716 static inline char *
02717 skipprefixroot(const char *path)
02718 {
02719 #if defined(DOSISH_UNC) || defined(DOSISH_DRIVE_LETTER)
02720 char *p = skipprefix(path);
02721 while (isdirsep(*p)) p++;
02722 return p;
02723 #else
02724 return skiproot(path);
02725 #endif
02726 }
02727
02728 #define strrdirsep rb_path_last_separator
02729 char *
02730 rb_path_last_separator(const char *path)
02731 {
02732 char *last = NULL;
02733 while (*path) {
02734 if (isdirsep(*path)) {
02735 const char *tmp = path++;
02736 while (isdirsep(*path)) path++;
02737 if (!*path) break;
02738 last = (char *)tmp;
02739 }
02740 else {
02741 path = CharNext(path);
02742 }
02743 }
02744 return last;
02745 }
02746
02747 static char *
02748 chompdirsep(const char *path)
02749 {
02750 while (*path) {
02751 if (isdirsep(*path)) {
02752 const char *last = path++;
02753 while (isdirsep(*path)) path++;
02754 if (!*path) return (char *)last;
02755 }
02756 else {
02757 path = CharNext(path);
02758 }
02759 }
02760 return (char *)path;
02761 }
02762
02763 char *
02764 rb_path_end(const char *path)
02765 {
02766 if (isdirsep(*path)) path++;
02767 return chompdirsep(path);
02768 }
02769
02770 #if USE_NTFS
02771 static char *
02772 ntfs_tail(const char *path)
02773 {
02774 while (*path == '.') path++;
02775 while (*path && *path != ':') {
02776 if (istrailinggarbage(*path)) {
02777 const char *last = path++;
02778 while (istrailinggarbage(*path)) path++;
02779 if (!*path || *path == ':') return (char *)last;
02780 }
02781 else if (isdirsep(*path)) {
02782 const char *last = path++;
02783 while (isdirsep(*path)) path++;
02784 if (!*path) return (char *)last;
02785 if (*path == ':') path++;
02786 }
02787 else {
02788 path = CharNext(path);
02789 }
02790 }
02791 return (char *)path;
02792 }
02793 #endif
02794
02795 #define BUFCHECK(cond) do {\
02796 bdiff = p - buf;\
02797 if (cond) {\
02798 do {buflen *= 2;} while (cond);\
02799 rb_str_resize(result, buflen);\
02800 buf = RSTRING_PTR(result);\
02801 p = buf + bdiff;\
02802 pend = buf + buflen;\
02803 }\
02804 } while (0)
02805
02806 #define BUFINIT() (\
02807 p = buf = RSTRING_PTR(result),\
02808 buflen = RSTRING_LEN(result),\
02809 pend = p + buflen)
02810
02811 VALUE
02812 rb_home_dir(const char *user, VALUE result)
02813 {
02814 const char *dir;
02815 char *buf;
02816 #if defined DOSISH || defined __CYGWIN__
02817 char *p;
02818 #endif
02819 long dirlen;
02820
02821 if (!user || !*user) {
02822 if (!(dir = getenv("HOME"))) {
02823 rb_raise(rb_eArgError, "couldn't find HOME environment -- expanding `~'");
02824 }
02825 dirlen = strlen(dir);
02826 rb_str_resize(result, dirlen);
02827 memcpy(buf = RSTRING_PTR(result), dir, dirlen);
02828 }
02829 else {
02830 #ifdef HAVE_PWD_H
02831 struct passwd *pwPtr = getpwnam(user);
02832 if (!pwPtr) {
02833 endpwent();
02834 rb_raise(rb_eArgError, "user %s doesn't exist", user);
02835 }
02836 dirlen = strlen(pwPtr->pw_dir);
02837 rb_str_resize(result, dirlen);
02838 strcpy(buf = RSTRING_PTR(result), pwPtr->pw_dir);
02839 endpwent();
02840 #else
02841 return Qnil;
02842 #endif
02843 }
02844 #if defined DOSISH || defined __CYGWIN__
02845 for (p = buf; *p; p = CharNext(p)) {
02846 if (*p == '\\') {
02847 *p = '/';
02848 }
02849 }
02850 #endif
02851 rb_enc_associate_index(result, rb_filesystem_encindex());
02852 return result;
02853 }
02854
02855 static VALUE
02856 file_expand_path(VALUE fname, VALUE dname, int abs_mode, VALUE result)
02857 {
02858 const char *s, *b;
02859 char *buf, *p, *pend, *root;
02860 size_t buflen, dirlen, bdiff;
02861 int tainted;
02862
02863 s = StringValuePtr(fname);
02864 BUFINIT();
02865 tainted = OBJ_TAINTED(fname);
02866
02867 if (s[0] == '~' && abs_mode == 0) {
02868 long userlen = 0;
02869 tainted = 1;
02870 if (isdirsep(s[1]) || s[1] == '\0') {
02871 buf = 0;
02872 b = 0;
02873 rb_str_set_len(result, 0);
02874 if (*++s) ++s;
02875 }
02876 else {
02877 s = nextdirsep(b = s);
02878 userlen = s - b;
02879 BUFCHECK(bdiff + userlen >= buflen);
02880 memcpy(p, b, userlen);
02881 rb_str_set_len(result, userlen);
02882 buf = p + 1;
02883 p += userlen;
02884 }
02885 if (NIL_P(rb_home_dir(buf, result))) {
02886 rb_raise(rb_eArgError, "can't find user %s", buf);
02887 }
02888 if (!rb_is_absolute_path(RSTRING_PTR(result))) {
02889 if (userlen) {
02890 rb_raise(rb_eArgError, "non-absolute home of %.*s", (int)userlen, b);
02891 }
02892 else {
02893 rb_raise(rb_eArgError, "non-absolute home");
02894 }
02895 }
02896 BUFINIT();
02897 p = pend;
02898 }
02899 #ifdef DOSISH_DRIVE_LETTER
02900
02901 else if (has_drive_letter(s)) {
02902 if (isdirsep(s[2])) {
02903
02904
02905 BUFCHECK(bdiff + 2 >= buflen);
02906 memcpy(p, s, 2);
02907 p += 2;
02908 s += 2;
02909 rb_enc_copy(result, fname);
02910 }
02911 else {
02912
02913 int same = 0;
02914 if (!NIL_P(dname) && !not_same_drive(dname, s[0])) {
02915 file_expand_path(dname, Qnil, abs_mode, result);
02916 BUFINIT();
02917 if (has_drive_letter(p) && TOLOWER(p[0]) == TOLOWER(s[0])) {
02918
02919 same = 1;
02920 }
02921 }
02922 if (!same) {
02923 char *dir = getcwdofdrv(*s);
02924
02925 tainted = 1;
02926 dirlen = strlen(dir);
02927 BUFCHECK(dirlen > buflen);
02928 strcpy(buf, dir);
02929 xfree(dir);
02930 rb_enc_associate_index(result, rb_filesystem_encindex());
02931 }
02932 else
02933 rb_enc_associate(result, rb_enc_check(result, fname));
02934 p = chompdirsep(skiproot(buf));
02935 s += 2;
02936 }
02937 }
02938 #endif
02939 else if (!rb_is_absolute_path(s)) {
02940 if (!NIL_P(dname)) {
02941 file_expand_path(dname, Qnil, abs_mode, result);
02942 BUFINIT();
02943 rb_enc_associate(result, rb_enc_check(result, fname));
02944 }
02945 else {
02946 char *dir = my_getcwd();
02947
02948 tainted = 1;
02949 dirlen = strlen(dir);
02950 BUFCHECK(dirlen > buflen);
02951 strcpy(buf, dir);
02952 xfree(dir);
02953 rb_enc_associate_index(result, rb_filesystem_encindex());
02954 }
02955 #if defined DOSISH || defined __CYGWIN__
02956 if (isdirsep(*s)) {
02957
02958
02959 p = skipprefix(buf);
02960 }
02961 else
02962 #endif
02963 p = chompdirsep(skiproot(buf));
02964 }
02965 else {
02966 size_t len;
02967 b = s;
02968 do s++; while (isdirsep(*s));
02969 len = s - b;
02970 p = buf + len;
02971 BUFCHECK(bdiff >= buflen);
02972 memset(buf, '/', len);
02973 rb_str_set_len(result, len);
02974 rb_enc_associate(result, rb_enc_check(result, fname));
02975 }
02976 if (p > buf && p[-1] == '/')
02977 --p;
02978 else {
02979 rb_str_set_len(result, p-buf);
02980 BUFCHECK(bdiff + 1 >= buflen);
02981 *p = '/';
02982 }
02983
02984 rb_str_set_len(result, p-buf+1);
02985 BUFCHECK(bdiff + 1 >= buflen);
02986 p[1] = 0;
02987 root = skipprefix(buf);
02988
02989 b = s;
02990 while (*s) {
02991 switch (*s) {
02992 case '.':
02993 if (b == s++) {
02994 switch (*s) {
02995 case '\0':
02996 b = s;
02997 break;
02998 case '.':
02999 if (*(s+1) == '\0' || isdirsep(*(s+1))) {
03000
03001 char *n;
03002 *p = '\0';
03003 if (!(n = strrdirsep(root))) {
03004 *p = '/';
03005 }
03006 else {
03007 p = n;
03008 }
03009 b = ++s;
03010 }
03011 #if USE_NTFS
03012 else {
03013 do ++s; while (istrailinggarbage(*s));
03014 }
03015 #endif
03016 break;
03017 case '/':
03018 #if defined DOSISH || defined __CYGWIN__
03019 case '\\':
03020 #endif
03021 b = ++s;
03022 break;
03023 default:
03024
03025 break;
03026 }
03027 }
03028 #if USE_NTFS
03029 else {
03030 --s;
03031 case ' ': {
03032 const char *e = s;
03033 while (istrailinggarbage(*s)) s++;
03034 if (!*s) {
03035 s = e;
03036 goto endpath;
03037 }
03038 }
03039 }
03040 #endif
03041 break;
03042 case '/':
03043 #if defined DOSISH || defined __CYGWIN__
03044 case '\\':
03045 #endif
03046 if (s > b) {
03047 long rootdiff = root - buf;
03048 rb_str_set_len(result, p-buf+1);
03049 BUFCHECK(bdiff + (s-b+1) >= buflen);
03050 root = buf + rootdiff;
03051 memcpy(++p, b, s-b);
03052 p += s-b;
03053 *p = '/';
03054 }
03055 b = ++s;
03056 break;
03057 default:
03058 s = CharNext(s);
03059 break;
03060 }
03061 }
03062
03063 if (s > b) {
03064 #if USE_NTFS
03065 static const char prime[] = ":$DATA";
03066 enum {prime_len = sizeof(prime) -1};
03067 endpath:
03068 if (s > b + prime_len && strncasecmp(s - prime_len, prime, prime_len) == 0) {
03069
03070
03071 if (*(s - (prime_len+1)) == ':') {
03072 s -= prime_len + 1;
03073 }
03074 else if (memchr(b, ':', s - prime_len - b)) {
03075 s -= prime_len;
03076 }
03077 }
03078 #endif
03079 rb_str_set_len(result, p-buf+1);
03080 BUFCHECK(bdiff + (s-b) >= buflen);
03081 memcpy(++p, b, s-b);
03082 p += s-b;
03083 }
03084 if (p == skiproot(buf) - 1) p++;
03085
03086 #if USE_NTFS
03087 *p = '\0';
03088 if ((s = strrdirsep(b = buf)) != 0 && !strpbrk(s, "*?")) {
03089 size_t len;
03090 WIN32_FIND_DATA wfd;
03091 HANDLE h;
03092 #ifdef __CYGWIN__
03093 #ifdef HAVE_CYGWIN_CONV_PATH
03094 char *w32buf = NULL;
03095 const int flags = CCP_POSIX_TO_WIN_A | CCP_RELATIVE;
03096 #else
03097 char w32buf[MAXPATHLEN];
03098 #endif
03099 const char *path;
03100 ssize_t bufsize;
03101 int lnk_added = 0, is_symlink = 0;
03102 struct stat st;
03103 p = (char *)s;
03104 len = strlen(p);
03105 if (lstat(buf, &st) == 0 && S_ISLNK(st.st_mode)) {
03106 is_symlink = 1;
03107 if (len > 4 && STRCASECMP(p + len - 4, ".lnk") != 0) {
03108 lnk_added = 1;
03109 }
03110 }
03111 path = *buf ? buf : "/";
03112 #ifdef HAVE_CYGWIN_CONV_PATH
03113 bufsize = cygwin_conv_path(flags, path, NULL, 0);
03114 if (bufsize > 0) {
03115 bufsize += len;
03116 if (lnk_added) bufsize += 4;
03117 w32buf = ALLOCA_N(char, bufsize);
03118 if (cygwin_conv_path(flags, path, w32buf, bufsize) == 0) {
03119 b = w32buf;
03120 }
03121 }
03122 #else
03123 bufsize = MAXPATHLEN;
03124 if (cygwin_conv_to_win32_path(path, w32buf) == 0) {
03125 b = w32buf;
03126 }
03127 #endif
03128 if (is_symlink && b == w32buf) {
03129 *p = '\\';
03130 strlcat(w32buf, p, bufsize);
03131 if (lnk_added) {
03132 strlcat(w32buf, ".lnk", bufsize);
03133 }
03134 }
03135 else {
03136 lnk_added = 0;
03137 }
03138 *p = '/';
03139 #endif
03140 h = FindFirstFile(b, &wfd);
03141 if (h != INVALID_HANDLE_VALUE) {
03142 FindClose(h);
03143 len = strlen(wfd.cFileName);
03144 #ifdef __CYGWIN__
03145 if (lnk_added && len > 4 &&
03146 STRCASECMP(wfd.cFileName + len - 4, ".lnk") == 0) {
03147 wfd.cFileName[len -= 4] = '\0';
03148 }
03149 #else
03150 p = (char *)s;
03151 #endif
03152 ++p;
03153 BUFCHECK(bdiff + len >= buflen);
03154 memcpy(p, wfd.cFileName, len + 1);
03155 p += len;
03156 }
03157 #ifdef __CYGWIN__
03158 else {
03159 p += strlen(p);
03160 }
03161 #endif
03162 }
03163 #endif
03164
03165 if (tainted) OBJ_TAINT(result);
03166 rb_str_set_len(result, p - buf);
03167 rb_enc_check(fname, result);
03168 ENC_CODERANGE_CLEAR(result);
03169 return result;
03170 }
03171
03172 #define EXPAND_PATH_BUFFER() rb_usascii_str_new(0, MAXPATHLEN + 2)
03173
03174 #define check_expand_path_args(fname, dname) \
03175 (((fname) = rb_get_path(fname)), \
03176 (void)(NIL_P(dname) ? (dname) : ((dname) = rb_get_path(dname))))
03177
03178 static VALUE
03179 file_expand_path_1(VALUE fname)
03180 {
03181 return file_expand_path(fname, Qnil, 0, EXPAND_PATH_BUFFER());
03182 }
03183
03184 VALUE
03185 rb_file_expand_path(VALUE fname, VALUE dname)
03186 {
03187 check_expand_path_args(fname, dname);
03188 return file_expand_path(fname, dname, 0, EXPAND_PATH_BUFFER());
03189 }
03190
03191
03192
03193
03194
03195
03196
03197
03198
03199
03200
03201
03202
03203
03204
03205
03206
03207
03208 VALUE
03209 rb_file_s_expand_path(int argc, VALUE *argv)
03210 {
03211 VALUE fname, dname;
03212
03213 if (argc == 1) {
03214 return rb_file_expand_path(argv[0], Qnil);
03215 }
03216 rb_scan_args(argc, argv, "11", &fname, &dname);
03217
03218 return rb_file_expand_path(fname, dname);
03219 }
03220
03221 VALUE
03222 rb_file_absolute_path(VALUE fname, VALUE dname)
03223 {
03224 check_expand_path_args(fname, dname);
03225 return file_expand_path(fname, dname, 1, EXPAND_PATH_BUFFER());
03226 }
03227
03228
03229
03230
03231
03232
03233
03234
03235
03236
03237
03238
03239
03240
03241 VALUE
03242 rb_file_s_absolute_path(int argc, VALUE *argv)
03243 {
03244 VALUE fname, dname;
03245
03246 if (argc == 1) {
03247 return rb_file_absolute_path(argv[0], Qnil);
03248 }
03249 rb_scan_args(argc, argv, "11", &fname, &dname);
03250
03251 return rb_file_absolute_path(fname, dname);
03252 }
03253
03254 static void
03255 realpath_rec(long *prefixlenp, VALUE *resolvedp, char *unresolved, VALUE loopcheck, int strict, int last)
03256 {
03257 ID resolving;
03258 CONST_ID(resolving, "resolving");
03259 while (*unresolved) {
03260 char *testname = unresolved;
03261 char *unresolved_firstsep = rb_path_next(unresolved);
03262 long testnamelen = unresolved_firstsep - unresolved;
03263 char *unresolved_nextname = unresolved_firstsep;
03264 while (isdirsep(*unresolved_nextname)) unresolved_nextname++;
03265 unresolved = unresolved_nextname;
03266 if (testnamelen == 1 && testname[0] == '.') {
03267 }
03268 else if (testnamelen == 2 && testname[0] == '.' && testname[1] == '.') {
03269 if (*prefixlenp < RSTRING_LEN(*resolvedp)) {
03270 char *resolved_names = RSTRING_PTR(*resolvedp) + *prefixlenp;
03271 char *lastsep = rb_path_last_separator(resolved_names);
03272 long len = lastsep ? lastsep - resolved_names : 0;
03273 rb_str_resize(*resolvedp, *prefixlenp + len);
03274 }
03275 }
03276 else {
03277 VALUE checkval;
03278 VALUE testpath = rb_str_dup(*resolvedp);
03279 if (*prefixlenp < RSTRING_LEN(testpath))
03280 rb_str_cat2(testpath, "/");
03281 rb_str_cat(testpath, testname, testnamelen);
03282 checkval = rb_hash_aref(loopcheck, testpath);
03283 if (!NIL_P(checkval)) {
03284 if (checkval == ID2SYM(resolving)) {
03285 errno = ELOOP;
03286 rb_sys_fail_path(testpath);
03287 }
03288 else {
03289 *resolvedp = rb_str_dup(checkval);
03290 }
03291 }
03292 else {
03293 struct stat sbuf;
03294 int ret;
03295 VALUE testpath2 = rb_str_encode_ospath(testpath);
03296 ret = lstat(RSTRING_PTR(testpath2), &sbuf);
03297 if (ret == -1) {
03298 if (errno == ENOENT) {
03299 if (strict || !last || *unresolved_firstsep)
03300 rb_sys_fail_path(testpath);
03301 *resolvedp = testpath;
03302 break;
03303 }
03304 else {
03305 rb_sys_fail_path(testpath);
03306 }
03307 }
03308 #ifdef HAVE_READLINK
03309 if (S_ISLNK(sbuf.st_mode)) {
03310 volatile VALUE link;
03311 char *link_prefix, *link_names;
03312 long link_prefixlen;
03313 rb_hash_aset(loopcheck, testpath, ID2SYM(resolving));
03314 link = rb_file_s_readlink(rb_cFile, testpath);
03315 link_prefix = RSTRING_PTR(link);
03316 link_names = skipprefixroot(link_prefix);
03317 link_prefixlen = link_names - link_prefix;
03318 if (link_prefixlen == 0) {
03319 realpath_rec(prefixlenp, resolvedp, link_names, loopcheck, strict, *unresolved_firstsep == '\0');
03320 }
03321 else {
03322 *resolvedp = rb_str_new(link_prefix, link_prefixlen);
03323 *prefixlenp = link_prefixlen;
03324 realpath_rec(prefixlenp, resolvedp, link_names, loopcheck, strict, *unresolved_firstsep == '\0');
03325 }
03326 rb_hash_aset(loopcheck, testpath, rb_str_dup_frozen(*resolvedp));
03327 }
03328 else
03329 #endif
03330 {
03331 VALUE s = rb_str_dup_frozen(testpath);
03332 rb_hash_aset(loopcheck, s, s);
03333 *resolvedp = testpath;
03334 }
03335 }
03336 }
03337 }
03338 }
03339
03340 VALUE
03341 rb_realpath_internal(VALUE basedir, VALUE path, int strict)
03342 {
03343 long prefixlen;
03344 VALUE resolved;
03345 volatile VALUE unresolved_path;
03346 VALUE loopcheck;
03347 volatile VALUE curdir = Qnil;
03348
03349 char *path_names = NULL, *basedir_names = NULL, *curdir_names = NULL;
03350 char *ptr, *prefixptr = NULL;
03351
03352 rb_secure(2);
03353
03354 FilePathValue(path);
03355 unresolved_path = rb_str_dup_frozen(path);
03356
03357 if (!NIL_P(basedir)) {
03358 FilePathValue(basedir);
03359 basedir = rb_str_dup_frozen(basedir);
03360 }
03361
03362 ptr = RSTRING_PTR(unresolved_path);
03363 path_names = skipprefixroot(ptr);
03364 if (ptr != path_names) {
03365 resolved = rb_enc_str_new(ptr, path_names - ptr,
03366 rb_enc_get(unresolved_path));
03367 goto root_found;
03368 }
03369
03370 if (!NIL_P(basedir)) {
03371 ptr = RSTRING_PTR(basedir);
03372 basedir_names = skipprefixroot(ptr);
03373 if (ptr != basedir_names) {
03374 resolved = rb_enc_str_new(ptr, basedir_names - ptr,
03375 rb_enc_get(basedir));
03376 goto root_found;
03377 }
03378 }
03379
03380 curdir = rb_dir_getwd();
03381 ptr = RSTRING_PTR(curdir);
03382 curdir_names = skipprefixroot(ptr);
03383 resolved = rb_enc_str_new(ptr, curdir_names - ptr, rb_enc_get(curdir));
03384
03385 root_found:
03386 prefixptr = RSTRING_PTR(resolved);
03387 prefixlen = RSTRING_LEN(resolved);
03388 ptr = chompdirsep(prefixptr);
03389 if (*ptr) {
03390 prefixlen = ++ptr - prefixptr;
03391 rb_str_set_len(resolved, prefixlen);
03392 }
03393 #ifdef FILE_ALT_SEPARATOR
03394 while (prefixptr < ptr) {
03395 if (*prefixptr == FILE_ALT_SEPARATOR) {
03396 *prefixptr = '/';
03397 }
03398 prefixptr = CharNext(prefixptr);
03399 }
03400 #endif
03401
03402 loopcheck = rb_hash_new();
03403 if (curdir_names)
03404 realpath_rec(&prefixlen, &resolved, curdir_names, loopcheck, 1, 0);
03405 if (basedir_names)
03406 realpath_rec(&prefixlen, &resolved, basedir_names, loopcheck, 1, 0);
03407 realpath_rec(&prefixlen, &resolved, path_names, loopcheck, strict, 1);
03408
03409 OBJ_TAINT(resolved);
03410 return resolved;
03411 }
03412
03413
03414
03415
03416
03417
03418
03419
03420
03421
03422
03423
03424
03425
03426 static VALUE
03427 rb_file_s_realpath(int argc, VALUE *argv, VALUE klass)
03428 {
03429 VALUE path, basedir;
03430 rb_scan_args(argc, argv, "11", &path, &basedir);
03431 return rb_realpath_internal(basedir, path, 1);
03432 }
03433
03434
03435
03436
03437
03438
03439
03440
03441
03442
03443
03444
03445
03446 static VALUE
03447 rb_file_s_realdirpath(int argc, VALUE *argv, VALUE klass)
03448 {
03449 VALUE path, basedir;
03450 rb_scan_args(argc, argv, "11", &path, &basedir);
03451 return rb_realpath_internal(basedir, path, 0);
03452 }
03453
03454 static size_t
03455 rmext(const char *p, long l0, long l1, const char *e)
03456 {
03457 long l2;
03458
03459 if (!e) return 0;
03460
03461 l2 = strlen(e);
03462 if (l2 == 2 && e[1] == '*') {
03463 unsigned char c = *e;
03464 e = p + l1;
03465 do {
03466 if (e <= p + l0) return 0;
03467 } while (*--e != c);
03468 return e - p;
03469 }
03470 if (l1 < l2) return l1;
03471
03472 #if CASEFOLD_FILESYSTEM
03473 #define fncomp strncasecmp
03474 #else
03475 #define fncomp strncmp
03476 #endif
03477 if (fncomp(p+l1-l2, e, l2) == 0) {
03478 return l1-l2;
03479 }
03480 return 0;
03481 }
03482
03483 const char *
03484 ruby_find_basename(const char *name, long *baselen, long *alllen)
03485 {
03486 const char *p, *q, *e;
03487 #if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC
03488 const char *root;
03489 #endif
03490 long f = 0, n = -1;
03491
03492 name = skipprefix(name);
03493 #if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC
03494 root = name;
03495 #endif
03496 while (isdirsep(*name))
03497 name++;
03498 if (!*name) {
03499 p = name - 1;
03500 f = 1;
03501 #if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC
03502 if (name != root) {
03503
03504 }
03505 #ifdef DOSISH_DRIVE_LETTER
03506 else if (*p == ':') {
03507 p++;
03508 f = 0;
03509 }
03510 #endif
03511 #ifdef DOSISH_UNC
03512 else {
03513 p = "/";
03514 }
03515 #endif
03516 #endif
03517 }
03518 else {
03519 if (!(p = strrdirsep(name))) {
03520 p = name;
03521 }
03522 else {
03523 while (isdirsep(*p)) p++;
03524 }
03525 #if USE_NTFS
03526 n = ntfs_tail(p) - p;
03527 #else
03528 n = chompdirsep(p) - p;
03529 #endif
03530 for (q = p; q - p < n && *q == '.'; q++);
03531 for (e = 0; q - p < n; q = CharNext(q)) {
03532 if (*q == '.') e = q;
03533 }
03534 if (e) f = e - p;
03535 else f = n;
03536 }
03537
03538 if (baselen)
03539 *baselen = f;
03540 if (alllen)
03541 *alllen = n;
03542 return p;
03543 }
03544
03545
03546
03547
03548
03549
03550
03551
03552
03553
03554
03555
03556
03557
03558
03559 static VALUE
03560 rb_file_s_basename(int argc, VALUE *argv)
03561 {
03562 VALUE fname, fext, basename;
03563 const char *name, *p;
03564 long f, n;
03565
03566 if (rb_scan_args(argc, argv, "11", &fname, &fext) == 2) {
03567 rb_encoding *enc;
03568 StringValue(fext);
03569 if (!rb_enc_asciicompat(enc = rb_enc_get(fext))) {
03570 rb_raise(rb_eEncCompatError, "ascii incompatible character encodings: %s",
03571 rb_enc_name(enc));
03572 }
03573 }
03574 FilePathStringValue(fname);
03575 if (!NIL_P(fext)) rb_enc_check(fname, fext);
03576 if (RSTRING_LEN(fname) == 0 || !*(name = RSTRING_PTR(fname)))
03577 return rb_str_new_shared(fname);
03578
03579 p = ruby_find_basename(name, &f, &n);
03580 if (n >= 0) {
03581 if (NIL_P(fext) || !(f = rmext(p, f, n, StringValueCStr(fext)))) {
03582 f = n;
03583 }
03584 if (f == RSTRING_LEN(fname)) return rb_str_new_shared(fname);
03585 }
03586
03587 basename = rb_str_new(p, f);
03588 rb_enc_copy(basename, fname);
03589 OBJ_INFECT(basename, fname);
03590 return basename;
03591 }
03592
03593
03594
03595
03596
03597
03598
03599
03600
03601
03602
03603
03604
03605 static VALUE
03606 rb_file_s_dirname(VALUE klass, VALUE fname)
03607 {
03608 return rb_file_dirname(fname);
03609 }
03610
03611 VALUE
03612 rb_file_dirname(VALUE fname)
03613 {
03614 const char *name, *root, *p;
03615 VALUE dirname;
03616
03617 FilePathStringValue(fname);
03618 name = StringValueCStr(fname);
03619 root = skiproot(name);
03620 #ifdef DOSISH_UNC
03621 if (root > name + 1 && isdirsep(*name))
03622 root = skipprefix(name = root - 2);
03623 #else
03624 if (root > name + 1)
03625 name = root - 1;
03626 #endif
03627 p = strrdirsep(root);
03628 if (!p) {
03629 p = root;
03630 }
03631 if (p == name)
03632 return rb_usascii_str_new2(".");
03633 #ifdef DOSISH_DRIVE_LETTER
03634 if (has_drive_letter(name) && isdirsep(*(name + 2))) {
03635 const char *top = skiproot(name + 2);
03636 dirname = rb_str_new(name, 3);
03637 rb_str_cat(dirname, top, p - top);
03638 }
03639 else
03640 #endif
03641 dirname = rb_str_new(name, p - name);
03642 #ifdef DOSISH_DRIVE_LETTER
03643 if (has_drive_letter(name) && root == name + 2 && p - name == 2)
03644 rb_str_cat(dirname, ".", 1);
03645 #endif
03646 rb_enc_copy(dirname, fname);
03647 OBJ_INFECT(dirname, fname);
03648 return dirname;
03649 }
03650
03651
03652
03653
03654
03655
03656
03657
03658
03659
03660
03661
03662
03663 const char *
03664 ruby_find_extname(const char *name, long *len)
03665 {
03666 const char *p, *e;
03667
03668 p = strrdirsep(name);
03669 if (!p)
03670 p = name;
03671 else
03672 do name = ++p; while (isdirsep(*p));
03673
03674 e = 0;
03675 while (*p && *p == '.') p++;
03676 while (*p) {
03677 if (*p == '.' || istrailinggarbage(*p)) {
03678 #if USE_NTFS
03679 const char *last = p++, *dot = last;
03680 while (istrailinggarbage(*p)) {
03681 if (*p == '.') dot = p;
03682 p++;
03683 }
03684 if (!*p || *p == ':') {
03685 p = last;
03686 break;
03687 }
03688 if (*last == '.' || dot > last) e = dot;
03689 continue;
03690 #else
03691 e = p;
03692 #endif
03693 }
03694 #if USE_NTFS
03695 else if (*p == ':') {
03696 break;
03697 }
03698 #endif
03699 else if (isdirsep(*p))
03700 break;
03701 p = CharNext(p);
03702 }
03703
03704 if (len) {
03705
03706 if (!e || e == name)
03707 *len = 0;
03708 else if (e+1 == p)
03709 *len = 1;
03710 else
03711 *len = p - e;
03712 }
03713 return e;
03714 }
03715
03716
03717
03718
03719
03720
03721
03722
03723
03724
03725
03726
03727
03728
03729
03730 static VALUE
03731 rb_file_s_extname(VALUE klass, VALUE fname)
03732 {
03733 const char *name, *e;
03734 long len;
03735 VALUE extname;
03736
03737 FilePathStringValue(fname);
03738 name = StringValueCStr(fname);
03739 e = ruby_find_extname(name, &len);
03740 if (len <= 1)
03741 return rb_str_new(0, 0);
03742 extname = rb_str_new(e, len);
03743 rb_enc_copy(extname, fname);
03744 OBJ_INFECT(extname, fname);
03745 return extname;
03746 }
03747
03748
03749
03750
03751
03752
03753
03754
03755
03756
03757
03758
03759 static VALUE
03760 rb_file_s_path(VALUE klass, VALUE fname)
03761 {
03762 return rb_get_path(fname);
03763 }
03764
03765
03766
03767
03768
03769
03770
03771
03772
03773
03774
03775
03776 static VALUE
03777 rb_file_s_split(VALUE klass, VALUE path)
03778 {
03779 FilePathStringValue(path);
03780 return rb_assoc_new(rb_file_s_dirname(Qnil, path), rb_file_s_basename(1,&path));
03781 }
03782
03783 static VALUE separator;
03784
03785 static VALUE rb_file_join(VALUE ary, VALUE sep);
03786
03787 static VALUE
03788 file_inspect_join(VALUE ary, VALUE argp, int recur)
03789 {
03790 VALUE *arg = (VALUE *)argp;
03791 if (recur || ary == arg[0]) rb_raise(rb_eArgError, "recursive array");
03792 return rb_file_join(arg[0], arg[1]);
03793 }
03794
03795 static VALUE
03796 rb_file_join(VALUE ary, VALUE sep)
03797 {
03798 long len, i;
03799 VALUE result, tmp;
03800 const char *name, *tail;
03801
03802 if (RARRAY_LEN(ary) == 0) return rb_str_new(0, 0);
03803
03804 len = 1;
03805 for (i=0; i<RARRAY_LEN(ary); i++) {
03806 if (TYPE(RARRAY_PTR(ary)[i]) == T_STRING) {
03807 len += RSTRING_LEN(RARRAY_PTR(ary)[i]);
03808 }
03809 else {
03810 len += 10;
03811 }
03812 }
03813 if (!NIL_P(sep)) {
03814 StringValue(sep);
03815 len += RSTRING_LEN(sep) * RARRAY_LEN(ary) - 1;
03816 }
03817 result = rb_str_buf_new(len);
03818 OBJ_INFECT(result, ary);
03819 for (i=0; i<RARRAY_LEN(ary); i++) {
03820 tmp = RARRAY_PTR(ary)[i];
03821 switch (TYPE(tmp)) {
03822 case T_STRING:
03823 break;
03824 case T_ARRAY:
03825 if (ary == tmp) {
03826 rb_raise(rb_eArgError, "recursive array");
03827 }
03828 else {
03829 VALUE args[2];
03830
03831 args[0] = tmp;
03832 args[1] = sep;
03833 tmp = rb_exec_recursive(file_inspect_join, ary, (VALUE)args);
03834 }
03835 break;
03836 default:
03837 FilePathStringValue(tmp);
03838 }
03839 name = StringValueCStr(result);
03840 if (i == 0) {
03841 rb_enc_copy(result, tmp);
03842 }
03843 else if (!NIL_P(sep)) {
03844 tail = chompdirsep(name);
03845 if (RSTRING_PTR(tmp) && isdirsep(RSTRING_PTR(tmp)[0])) {
03846 rb_str_set_len(result, tail - name);
03847 }
03848 else if (!*tail) {
03849 rb_str_buf_append(result, sep);
03850 }
03851 }
03852 rb_str_buf_append(result, tmp);
03853 }
03854
03855 return result;
03856 }
03857
03858
03859
03860
03861
03862
03863
03864
03865
03866
03867
03868
03869 static VALUE
03870 rb_file_s_join(VALUE klass, VALUE args)
03871 {
03872 return rb_file_join(args, separator);
03873 }
03874
03875 #if defined(HAVE_TRUNCATE) || defined(HAVE_CHSIZE)
03876
03877
03878
03879
03880
03881
03882
03883
03884
03885
03886
03887
03888
03889
03890
03891 static VALUE
03892 rb_file_s_truncate(VALUE klass, VALUE path, VALUE len)
03893 {
03894 off_t pos;
03895
03896 rb_secure(2);
03897 pos = NUM2OFFT(len);
03898 FilePathValue(path);
03899 path = rb_str_encode_ospath(path);
03900 #ifdef HAVE_TRUNCATE
03901 if (truncate(StringValueCStr(path), pos) < 0)
03902 rb_sys_fail_path(path);
03903 #else
03904 {
03905 int tmpfd;
03906
03907 if ((tmpfd = open(StringValueCStr(path), 0)) < 0) {
03908 rb_sys_fail_path(path);
03909 }
03910 rb_update_max_fd(tmpfd);
03911 if (chsize(tmpfd, pos) < 0) {
03912 close(tmpfd);
03913 rb_sys_fail_path(path);
03914 }
03915 close(tmpfd);
03916 }
03917 #endif
03918 return INT2FIX(0);
03919 }
03920 #else
03921 #define rb_file_s_truncate rb_f_notimplement
03922 #endif
03923
03924 #if defined(HAVE_FTRUNCATE) || defined(HAVE_CHSIZE)
03925
03926
03927
03928
03929
03930
03931
03932
03933
03934
03935
03936
03937
03938
03939 static VALUE
03940 rb_file_truncate(VALUE obj, VALUE len)
03941 {
03942 rb_io_t *fptr;
03943 off_t pos;
03944
03945 rb_secure(2);
03946 pos = NUM2OFFT(len);
03947 GetOpenFile(obj, fptr);
03948 if (!(fptr->mode & FMODE_WRITABLE)) {
03949 rb_raise(rb_eIOError, "not opened for writing");
03950 }
03951 rb_io_flush(obj);
03952 #ifdef HAVE_FTRUNCATE
03953 if (ftruncate(fptr->fd, pos) < 0)
03954 rb_sys_fail_path(fptr->pathv);
03955 #else
03956 if (chsize(fptr->fd, pos) < 0)
03957 rb_sys_fail_path(fptr->pathv);
03958 #endif
03959 return INT2FIX(0);
03960 }
03961 #else
03962 #define rb_file_truncate rb_f_notimplement
03963 #endif
03964
03965 # ifndef LOCK_SH
03966 # define LOCK_SH 1
03967 # endif
03968 # ifndef LOCK_EX
03969 # define LOCK_EX 2
03970 # endif
03971 # ifndef LOCK_NB
03972 # define LOCK_NB 4
03973 # endif
03974 # ifndef LOCK_UN
03975 # define LOCK_UN 8
03976 # endif
03977
03978 #ifdef __CYGWIN__
03979 #include <winerror.h>
03980 extern unsigned long __attribute__((stdcall)) GetLastError(void);
03981 #endif
03982
03983 static VALUE
03984 rb_thread_flock(void *data)
03985 {
03986 #ifdef __CYGWIN__
03987 int old_errno = errno;
03988 #endif
03989 int *op = data, ret = flock(op[0], op[1]);
03990
03991 #ifdef __CYGWIN__
03992 if (GetLastError() == ERROR_NOT_LOCKED) {
03993 ret = 0;
03994 errno = old_errno;
03995 }
03996 #endif
03997 return (VALUE)ret;
03998 }
03999
04000
04001
04002
04003
04004
04005
04006
04007
04008
04009
04010
04011
04012
04013
04014
04015
04016
04017
04018
04019
04020
04021
04022
04023
04024
04025
04026
04027
04028
04029
04030
04031
04032
04033
04034
04035
04036
04037
04038
04039
04040
04041
04042
04043
04044 static VALUE
04045 rb_file_flock(VALUE obj, VALUE operation)
04046 {
04047 rb_io_t *fptr;
04048 int op[2], op1;
04049
04050 rb_secure(2);
04051 op[1] = op1 = NUM2INT(operation);
04052 GetOpenFile(obj, fptr);
04053 op[0] = fptr->fd;
04054
04055 if (fptr->mode & FMODE_WRITABLE) {
04056 rb_io_flush(obj);
04057 }
04058 while ((int)rb_thread_io_blocking_region(rb_thread_flock, op, fptr->fd) < 0) {
04059 switch (errno) {
04060 case EAGAIN:
04061 case EACCES:
04062 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
04063 case EWOULDBLOCK:
04064 #endif
04065 if (op1 & LOCK_NB) return Qfalse;
04066 rb_thread_polling();
04067 rb_io_check_closed(fptr);
04068 continue;
04069
04070 case EINTR:
04071 #if defined(ERESTART)
04072 case ERESTART:
04073 #endif
04074 break;
04075
04076 default:
04077 rb_sys_fail_path(fptr->pathv);
04078 }
04079 }
04080 return INT2FIX(0);
04081 }
04082 #undef flock
04083
04084 static void
04085 test_check(int n, int argc, VALUE *argv)
04086 {
04087 int i;
04088
04089 rb_secure(2);
04090 n+=1;
04091 if (n != argc) rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", argc, n);
04092 for (i=1; i<n; i++) {
04093 switch (TYPE(argv[i])) {
04094 case T_STRING:
04095 default:
04096 FilePathValue(argv[i]);
04097 break;
04098 case T_FILE:
04099 break;
04100 }
04101 }
04102 }
04103
04104 #define CHECK(n) test_check((n), argc, argv)
04105
04106
04107
04108
04109
04110
04111
04112
04113
04114
04115
04116
04117
04118
04119
04120
04121
04122
04123
04124
04125
04126
04127
04128
04129
04130
04131
04132
04133
04134
04135
04136
04137
04138
04139
04140
04141
04142
04143
04144
04145
04146
04147
04148
04149
04150
04151
04152
04153
04154
04155
04156
04157
04158
04159
04160
04161
04162
04163
04164
04165 static VALUE
04166 rb_f_test(int argc, VALUE *argv)
04167 {
04168 int cmd;
04169
04170 if (argc == 0) rb_raise(rb_eArgError, "wrong number of arguments (0 for 2..3)");
04171 cmd = NUM2CHR(argv[0]);
04172 if (cmd == 0) goto unknown;
04173 if (strchr("bcdefgGkloOprRsSuwWxXz", cmd)) {
04174 CHECK(1);
04175 switch (cmd) {
04176 case 'b':
04177 return rb_file_blockdev_p(0, argv[1]);
04178
04179 case 'c':
04180 return rb_file_chardev_p(0, argv[1]);
04181
04182 case 'd':
04183 return rb_file_directory_p(0, argv[1]);
04184
04185 case 'a':
04186 case 'e':
04187 return rb_file_exist_p(0, argv[1]);
04188
04189 case 'f':
04190 return rb_file_file_p(0, argv[1]);
04191
04192 case 'g':
04193 return rb_file_sgid_p(0, argv[1]);
04194
04195 case 'G':
04196 return rb_file_grpowned_p(0, argv[1]);
04197
04198 case 'k':
04199 return rb_file_sticky_p(0, argv[1]);
04200
04201 case 'l':
04202 return rb_file_symlink_p(0, argv[1]);
04203
04204 case 'o':
04205 return rb_file_owned_p(0, argv[1]);
04206
04207 case 'O':
04208 return rb_file_rowned_p(0, argv[1]);
04209
04210 case 'p':
04211 return rb_file_pipe_p(0, argv[1]);
04212
04213 case 'r':
04214 return rb_file_readable_p(0, argv[1]);
04215
04216 case 'R':
04217 return rb_file_readable_real_p(0, argv[1]);
04218
04219 case 's':
04220 return rb_file_size_p(0, argv[1]);
04221
04222 case 'S':
04223 return rb_file_socket_p(0, argv[1]);
04224
04225 case 'u':
04226 return rb_file_suid_p(0, argv[1]);
04227
04228 case 'w':
04229 return rb_file_writable_p(0, argv[1]);
04230
04231 case 'W':
04232 return rb_file_writable_real_p(0, argv[1]);
04233
04234 case 'x':
04235 return rb_file_executable_p(0, argv[1]);
04236
04237 case 'X':
04238 return rb_file_executable_real_p(0, argv[1]);
04239
04240 case 'z':
04241 return rb_file_zero_p(0, argv[1]);
04242 }
04243 }
04244
04245 if (strchr("MAC", cmd)) {
04246 struct stat st;
04247 VALUE fname = argv[1];
04248
04249 CHECK(1);
04250 if (rb_stat(fname, &st) == -1) {
04251 FilePathValue(fname);
04252 rb_sys_fail_path(fname);
04253 }
04254
04255 switch (cmd) {
04256 case 'A':
04257 return stat_atime(&st);
04258 case 'M':
04259 return stat_mtime(&st);
04260 case 'C':
04261 return stat_ctime(&st);
04262 }
04263 }
04264
04265 if (cmd == '-') {
04266 CHECK(2);
04267 return rb_file_identical_p(0, argv[1], argv[2]);
04268 }
04269
04270 if (strchr("=<>", cmd)) {
04271 struct stat st1, st2;
04272
04273 CHECK(2);
04274 if (rb_stat(argv[1], &st1) < 0) return Qfalse;
04275 if (rb_stat(argv[2], &st2) < 0) return Qfalse;
04276
04277 switch (cmd) {
04278 case '=':
04279 if (st1.st_mtime == st2.st_mtime) return Qtrue;
04280 return Qfalse;
04281
04282 case '>':
04283 if (st1.st_mtime > st2.st_mtime) return Qtrue;
04284 return Qfalse;
04285
04286 case '<':
04287 if (st1.st_mtime < st2.st_mtime) return Qtrue;
04288 return Qfalse;
04289 }
04290 }
04291 unknown:
04292
04293 if (ISPRINT(cmd)) {
04294 rb_raise(rb_eArgError, "unknown command '%s%c'", cmd == '\'' || cmd == '\\' ? "\\" : "", cmd);
04295 }
04296 else {
04297 rb_raise(rb_eArgError, "unknown command \"\\x%02X\"", cmd);
04298 }
04299 return Qnil;
04300 }
04301
04302
04303
04304
04305
04306
04307
04308
04309
04310
04311
04312
04313
04314
04315
04316
04317 static VALUE
04318 rb_stat_s_alloc(VALUE klass)
04319 {
04320 return stat_new_0(klass, 0);
04321 }
04322
04323
04324
04325
04326
04327
04328
04329
04330
04331
04332 static VALUE
04333 rb_stat_init(VALUE obj, VALUE fname)
04334 {
04335 struct stat st, *nst;
04336
04337 rb_secure(2);
04338 FilePathValue(fname);
04339 fname = rb_str_encode_ospath(fname);
04340 if (STAT(StringValueCStr(fname), &st) == -1) {
04341 rb_sys_fail_path(fname);
04342 }
04343 if (DATA_PTR(obj)) {
04344 xfree(DATA_PTR(obj));
04345 DATA_PTR(obj) = NULL;
04346 }
04347 nst = ALLOC(struct stat);
04348 *nst = st;
04349 DATA_PTR(obj) = nst;
04350
04351 return Qnil;
04352 }
04353
04354
04355 static VALUE
04356 rb_stat_init_copy(VALUE copy, VALUE orig)
04357 {
04358 struct stat *nst;
04359
04360 if (copy == orig) return orig;
04361 rb_check_frozen(copy);
04362
04363 if (!rb_obj_is_instance_of(orig, rb_obj_class(copy))) {
04364 rb_raise(rb_eTypeError, "wrong argument class");
04365 }
04366 if (DATA_PTR(copy)) {
04367 xfree(DATA_PTR(copy));
04368 DATA_PTR(copy) = 0;
04369 }
04370 if (DATA_PTR(orig)) {
04371 nst = ALLOC(struct stat);
04372 *nst = *(struct stat*)DATA_PTR(orig);
04373 DATA_PTR(copy) = nst;
04374 }
04375
04376 return copy;
04377 }
04378
04379
04380
04381
04382
04383
04384
04385
04386
04387
04388
04389
04390
04391
04392
04393 static VALUE
04394 rb_stat_ftype(VALUE obj)
04395 {
04396 return rb_file_ftype(get_stat(obj));
04397 }
04398
04399
04400
04401
04402
04403
04404
04405
04406
04407
04408
04409
04410 static VALUE
04411 rb_stat_d(VALUE obj)
04412 {
04413 if (S_ISDIR(get_stat(obj)->st_mode)) return Qtrue;
04414 return Qfalse;
04415 }
04416
04417
04418
04419
04420
04421
04422
04423
04424
04425 static VALUE
04426 rb_stat_p(VALUE obj)
04427 {
04428 #ifdef S_IFIFO
04429 if (S_ISFIFO(get_stat(obj)->st_mode)) return Qtrue;
04430
04431 #endif
04432 return Qfalse;
04433 }
04434
04435
04436
04437
04438
04439
04440
04441
04442
04443
04444
04445
04446
04447
04448
04449
04450
04451
04452 static VALUE
04453 rb_stat_l(VALUE obj)
04454 {
04455 #ifdef S_ISLNK
04456 if (S_ISLNK(get_stat(obj)->st_mode)) return Qtrue;
04457 #endif
04458 return Qfalse;
04459 }
04460
04461
04462
04463
04464
04465
04466
04467
04468
04469
04470
04471
04472
04473 static VALUE
04474 rb_stat_S(VALUE obj)
04475 {
04476 #ifdef S_ISSOCK
04477 if (S_ISSOCK(get_stat(obj)->st_mode)) return Qtrue;
04478
04479 #endif
04480 return Qfalse;
04481 }
04482
04483
04484
04485
04486
04487
04488
04489
04490
04491
04492
04493
04494
04495
04496 static VALUE
04497 rb_stat_b(VALUE obj)
04498 {
04499 #ifdef S_ISBLK
04500 if (S_ISBLK(get_stat(obj)->st_mode)) return Qtrue;
04501
04502 #endif
04503 return Qfalse;
04504 }
04505
04506
04507
04508
04509
04510
04511
04512
04513
04514
04515
04516
04517
04518 static VALUE
04519 rb_stat_c(VALUE obj)
04520 {
04521 if (S_ISCHR(get_stat(obj)->st_mode)) return Qtrue;
04522
04523 return Qfalse;
04524 }
04525
04526
04527
04528
04529
04530
04531
04532
04533
04534
04535
04536
04537
04538 static VALUE
04539 rb_stat_owned(VALUE obj)
04540 {
04541 if (get_stat(obj)->st_uid == geteuid()) return Qtrue;
04542 return Qfalse;
04543 }
04544
04545 static VALUE
04546 rb_stat_rowned(VALUE obj)
04547 {
04548 if (get_stat(obj)->st_uid == getuid()) return Qtrue;
04549 return Qfalse;
04550 }
04551
04552
04553
04554
04555
04556
04557
04558
04559
04560
04561
04562
04563
04564 static VALUE
04565 rb_stat_grpowned(VALUE obj)
04566 {
04567 #ifndef _WIN32
04568 if (rb_group_member(get_stat(obj)->st_gid)) return Qtrue;
04569 #endif
04570 return Qfalse;
04571 }
04572
04573
04574
04575
04576
04577
04578
04579
04580
04581
04582
04583
04584 static VALUE
04585 rb_stat_r(VALUE obj)
04586 {
04587 struct stat *st = get_stat(obj);
04588
04589 #ifdef USE_GETEUID
04590 if (geteuid() == 0) return Qtrue;
04591 #endif
04592 #ifdef S_IRUSR
04593 if (rb_stat_owned(obj))
04594 return st->st_mode & S_IRUSR ? Qtrue : Qfalse;
04595 #endif
04596 #ifdef S_IRGRP
04597 if (rb_stat_grpowned(obj))
04598 return st->st_mode & S_IRGRP ? Qtrue : Qfalse;
04599 #endif
04600 #ifdef S_IROTH
04601 if (!(st->st_mode & S_IROTH)) return Qfalse;
04602 #endif
04603 return Qtrue;
04604 }
04605
04606
04607
04608
04609
04610
04611
04612
04613
04614
04615
04616
04617 static VALUE
04618 rb_stat_R(VALUE obj)
04619 {
04620 struct stat *st = get_stat(obj);
04621
04622 #ifdef USE_GETEUID
04623 if (getuid() == 0) return Qtrue;
04624 #endif
04625 #ifdef S_IRUSR
04626 if (rb_stat_rowned(obj))
04627 return st->st_mode & S_IRUSR ? Qtrue : Qfalse;
04628 #endif
04629 #ifdef S_IRGRP
04630 if (rb_group_member(get_stat(obj)->st_gid))
04631 return st->st_mode & S_IRGRP ? Qtrue : Qfalse;
04632 #endif
04633 #ifdef S_IROTH
04634 if (!(st->st_mode & S_IROTH)) return Qfalse;
04635 #endif
04636 return Qtrue;
04637 }
04638
04639
04640
04641
04642
04643
04644
04645
04646
04647
04648
04649
04650
04651
04652 static VALUE
04653 rb_stat_wr(VALUE obj)
04654 {
04655 #ifdef S_IROTH
04656 if ((get_stat(obj)->st_mode & (S_IROTH)) == S_IROTH) {
04657 return UINT2NUM(get_stat(obj)->st_mode & (S_IRUGO|S_IWUGO|S_IXUGO));
04658 }
04659 else {
04660 return Qnil;
04661 }
04662 #endif
04663 }
04664
04665
04666
04667
04668
04669
04670
04671
04672
04673
04674
04675
04676 static VALUE
04677 rb_stat_w(VALUE obj)
04678 {
04679 struct stat *st = get_stat(obj);
04680
04681 #ifdef USE_GETEUID
04682 if (geteuid() == 0) return Qtrue;
04683 #endif
04684 #ifdef S_IWUSR
04685 if (rb_stat_owned(obj))
04686 return st->st_mode & S_IWUSR ? Qtrue : Qfalse;
04687 #endif
04688 #ifdef S_IWGRP
04689 if (rb_stat_grpowned(obj))
04690 return st->st_mode & S_IWGRP ? Qtrue : Qfalse;
04691 #endif
04692 #ifdef S_IWOTH
04693 if (!(st->st_mode & S_IWOTH)) return Qfalse;
04694 #endif
04695 return Qtrue;
04696 }
04697
04698
04699
04700
04701
04702
04703
04704
04705
04706
04707
04708
04709 static VALUE
04710 rb_stat_W(VALUE obj)
04711 {
04712 struct stat *st = get_stat(obj);
04713
04714 #ifdef USE_GETEUID
04715 if (getuid() == 0) return Qtrue;
04716 #endif
04717 #ifdef S_IWUSR
04718 if (rb_stat_rowned(obj))
04719 return st->st_mode & S_IWUSR ? Qtrue : Qfalse;
04720 #endif
04721 #ifdef S_IWGRP
04722 if (rb_group_member(get_stat(obj)->st_gid))
04723 return st->st_mode & S_IWGRP ? Qtrue : Qfalse;
04724 #endif
04725 #ifdef S_IWOTH
04726 if (!(st->st_mode & S_IWOTH)) return Qfalse;
04727 #endif
04728 return Qtrue;
04729 }
04730
04731
04732
04733
04734
04735
04736
04737
04738
04739
04740
04741
04742
04743
04744 static VALUE
04745 rb_stat_ww(VALUE obj)
04746 {
04747 #ifdef S_IROTH
04748 if ((get_stat(obj)->st_mode & (S_IWOTH)) == S_IWOTH) {
04749 return UINT2NUM(get_stat(obj)->st_mode & (S_IRUGO|S_IWUGO|S_IXUGO));
04750 }
04751 else {
04752 return Qnil;
04753 }
04754 #endif
04755 }
04756
04757
04758
04759
04760
04761
04762
04763
04764
04765
04766
04767
04768
04769
04770 static VALUE
04771 rb_stat_x(VALUE obj)
04772 {
04773 struct stat *st = get_stat(obj);
04774
04775 #ifdef USE_GETEUID
04776 if (geteuid() == 0) {
04777 return st->st_mode & S_IXUGO ? Qtrue : Qfalse;
04778 }
04779 #endif
04780 #ifdef S_IXUSR
04781 if (rb_stat_owned(obj))
04782 return st->st_mode & S_IXUSR ? Qtrue : Qfalse;
04783 #endif
04784 #ifdef S_IXGRP
04785 if (rb_stat_grpowned(obj))
04786 return st->st_mode & S_IXGRP ? Qtrue : Qfalse;
04787 #endif
04788 #ifdef S_IXOTH
04789 if (!(st->st_mode & S_IXOTH)) return Qfalse;
04790 #endif
04791 return Qtrue;
04792 }
04793
04794
04795
04796
04797
04798
04799
04800
04801
04802 static VALUE
04803 rb_stat_X(VALUE obj)
04804 {
04805 struct stat *st = get_stat(obj);
04806
04807 #ifdef USE_GETEUID
04808 if (getuid() == 0) {
04809 return st->st_mode & S_IXUGO ? Qtrue : Qfalse;
04810 }
04811 #endif
04812 #ifdef S_IXUSR
04813 if (rb_stat_rowned(obj))
04814 return st->st_mode & S_IXUSR ? Qtrue : Qfalse;
04815 #endif
04816 #ifdef S_IXGRP
04817 if (rb_group_member(get_stat(obj)->st_gid))
04818 return st->st_mode & S_IXGRP ? Qtrue : Qfalse;
04819 #endif
04820 #ifdef S_IXOTH
04821 if (!(st->st_mode & S_IXOTH)) return Qfalse;
04822 #endif
04823 return Qtrue;
04824 }
04825
04826
04827
04828
04829
04830
04831
04832
04833
04834
04835
04836
04837 static VALUE
04838 rb_stat_f(VALUE obj)
04839 {
04840 if (S_ISREG(get_stat(obj)->st_mode)) return Qtrue;
04841 return Qfalse;
04842 }
04843
04844
04845
04846
04847
04848
04849
04850
04851
04852
04853
04854
04855 static VALUE
04856 rb_stat_z(VALUE obj)
04857 {
04858 if (get_stat(obj)->st_size == 0) return Qtrue;
04859 return Qfalse;
04860 }
04861
04862
04863
04864
04865
04866
04867
04868
04869
04870
04871
04872 static VALUE
04873 rb_stat_s(VALUE obj)
04874 {
04875 off_t size = get_stat(obj)->st_size;
04876
04877 if (size == 0) return Qnil;
04878 return OFFT2NUM(size);
04879 }
04880
04881
04882
04883
04884
04885
04886
04887
04888
04889
04890
04891
04892 static VALUE
04893 rb_stat_suid(VALUE obj)
04894 {
04895 #ifdef S_ISUID
04896 if (get_stat(obj)->st_mode & S_ISUID) return Qtrue;
04897 #endif
04898 return Qfalse;
04899 }
04900
04901
04902
04903
04904
04905
04906
04907
04908
04909
04910
04911
04912
04913 static VALUE
04914 rb_stat_sgid(VALUE obj)
04915 {
04916 #ifdef S_ISGID
04917 if (get_stat(obj)->st_mode & S_ISGID) return Qtrue;
04918 #endif
04919 return Qfalse;
04920 }
04921
04922
04923
04924
04925
04926
04927
04928
04929
04930
04931
04932
04933
04934 static VALUE
04935 rb_stat_sticky(VALUE obj)
04936 {
04937 #ifdef S_ISVTX
04938 if (get_stat(obj)->st_mode & S_ISVTX) return Qtrue;
04939 #endif
04940 return Qfalse;
04941 }
04942
04943 VALUE rb_mFConst;
04944
04945 void
04946 rb_file_const(const char *name, VALUE value)
04947 {
04948 rb_define_const(rb_mFConst, name, value);
04949 }
04950
04951 int
04952 rb_is_absolute_path(const char *path)
04953 {
04954 #ifdef DOSISH_DRIVE_LETTER
04955 if (has_drive_letter(path) && isdirsep(path[2])) return 1;
04956 #endif
04957 #ifdef DOSISH_UNC
04958 if (isdirsep(path[0]) && isdirsep(path[1])) return 1;
04959 #endif
04960 #ifndef DOSISH
04961 if (path[0] == '/') return 1;
04962 #endif
04963 return 0;
04964 }
04965
04966 #ifndef ENABLE_PATH_CHECK
04967 # if defined DOSISH || defined __CYGWIN__
04968 # define ENABLE_PATH_CHECK 0
04969 # else
04970 # define ENABLE_PATH_CHECK 1
04971 # endif
04972 #endif
04973
04974 #if ENABLE_PATH_CHECK
04975 static int
04976 path_check_0(VALUE path, int execpath)
04977 {
04978 struct stat st;
04979 const char *p0 = StringValueCStr(path);
04980 char *p = 0, *s;
04981
04982 if (!rb_is_absolute_path(p0)) {
04983 char *buf = my_getcwd();
04984 VALUE newpath;
04985
04986 newpath = rb_str_new2(buf);
04987 xfree(buf);
04988
04989 rb_str_cat2(newpath, "/");
04990 rb_str_cat2(newpath, p0);
04991 path = newpath;
04992 p0 = RSTRING_PTR(path);
04993 }
04994 for (;;) {
04995 #ifndef S_IWOTH
04996 # define S_IWOTH 002
04997 #endif
04998 if (STAT(p0, &st) == 0 && S_ISDIR(st.st_mode) && (st.st_mode & S_IWOTH)
04999 #ifdef S_ISVTX
05000 && !(p && execpath && (st.st_mode & S_ISVTX))
05001 #endif
05002 && !access(p0, W_OK)) {
05003 rb_warn("Insecure world writable dir %s in %sPATH, mode 0%"
05004 PRI_MODET_PREFIX"o",
05005 p0, (execpath ? "" : "LOAD_"), st.st_mode);
05006 if (p) *p = '/';
05007 RB_GC_GUARD(path);
05008 return 0;
05009 }
05010 s = strrdirsep(p0);
05011 if (p) *p = '/';
05012 if (!s || s == p0) return 1;
05013 p = s;
05014 *p = '\0';
05015 }
05016 }
05017 #endif
05018
05019 #if ENABLE_PATH_CHECK
05020 #define fpath_check(path) path_check_0((path), FALSE)
05021 #else
05022 #define fpath_check(path) 1
05023 #endif
05024
05025 int
05026 rb_path_check(const char *path)
05027 {
05028 #if ENABLE_PATH_CHECK
05029 const char *p0, *p, *pend;
05030 const char sep = PATH_SEP_CHAR;
05031
05032 if (!path) return 1;
05033
05034 pend = path + strlen(path);
05035 p0 = path;
05036 p = strchr(path, sep);
05037 if (!p) p = pend;
05038
05039 for (;;) {
05040 if (!path_check_0(rb_str_new(p0, p - p0), TRUE)) {
05041 return 0;
05042 }
05043 p0 = p + 1;
05044 if (p0 > pend) break;
05045 p = strchr(p0, sep);
05046 if (!p) p = pend;
05047 }
05048 #endif
05049 return 1;
05050 }
05051
05052 static int
05053 file_load_ok(const char *path)
05054 {
05055 int ret = 1;
05056 int fd = open(path, O_RDONLY);
05057 if (fd == -1) return 0;
05058 rb_update_max_fd(fd);
05059 #if !defined DOSISH
05060 {
05061 struct stat st;
05062 if (fstat(fd, &st) || !S_ISREG(st.st_mode)) {
05063 ret = 0;
05064 }
05065 }
05066 #endif
05067 (void)close(fd);
05068 return ret;
05069 }
05070
05071 int
05072 rb_file_load_ok(const char *path)
05073 {
05074 return file_load_ok(path);
05075 }
05076
05077 static int
05078 is_explicit_relative(const char *path)
05079 {
05080 if (*path++ != '.') return 0;
05081 if (*path == '.') path++;
05082 return isdirsep(*path);
05083 }
05084
05085 static VALUE
05086 copy_path_class(VALUE path, VALUE orig)
05087 {
05088 RBASIC(path)->klass = rb_obj_class(orig);
05089 OBJ_FREEZE(path);
05090 return path;
05091 }
05092
05093 int
05094 rb_find_file_ext(VALUE *filep, const char *const *ext)
05095 {
05096 return rb_find_file_ext_safe(filep, ext, rb_safe_level());
05097 }
05098
05099 int
05100 rb_find_file_ext_safe(VALUE *filep, const char *const *ext, int safe_level)
05101 {
05102 const char *f = StringValueCStr(*filep);
05103 VALUE fname = *filep, load_path, tmp;
05104 long i, j, fnlen;
05105 int expanded = 0;
05106
05107 if (!ext[0]) return 0;
05108
05109 if (f[0] == '~') {
05110 fname = file_expand_path_1(fname);
05111 if (safe_level >= 1 && OBJ_TAINTED(fname)) {
05112 rb_raise(rb_eSecurityError, "loading from unsafe file %s", f);
05113 }
05114 f = RSTRING_PTR(fname);
05115 *filep = fname;
05116 expanded = 1;
05117 }
05118
05119 if (expanded || rb_is_absolute_path(f) || is_explicit_relative(f)) {
05120 if (safe_level >= 1 && !fpath_check(fname)) {
05121 rb_raise(rb_eSecurityError, "loading from unsafe path %s", f);
05122 }
05123 if (!expanded) fname = file_expand_path_1(fname);
05124 fnlen = RSTRING_LEN(fname);
05125 for (i=0; ext[i]; i++) {
05126 rb_str_cat2(fname, ext[i]);
05127 if (file_load_ok(RSTRING_PTR(fname))) {
05128 *filep = copy_path_class(fname, *filep);
05129 return (int)(i+1);
05130 }
05131 rb_str_set_len(fname, fnlen);
05132 }
05133 return 0;
05134 }
05135
05136 if (safe_level >= 4) {
05137 rb_raise(rb_eSecurityError, "loading from non-absolute path %s", f);
05138 }
05139
05140 RB_GC_GUARD(load_path) = rb_get_load_path();
05141 if (!load_path) return 0;
05142
05143 fname = rb_str_dup(*filep);
05144 RBASIC(fname)->klass = 0;
05145 fnlen = RSTRING_LEN(fname);
05146 tmp = rb_str_tmp_new(MAXPATHLEN + 2);
05147 for (j=0; ext[j]; j++) {
05148 rb_str_cat2(fname, ext[j]);
05149 for (i = 0; i < RARRAY_LEN(load_path); i++) {
05150 VALUE str = RARRAY_PTR(load_path)[i];
05151
05152 RB_GC_GUARD(str) = rb_get_path_check(str, safe_level);
05153 if (RSTRING_LEN(str) == 0) continue;
05154 file_expand_path(fname, str, 0, tmp);
05155 if (file_load_ok(RSTRING_PTR(tmp))) {
05156 *filep = copy_path_class(tmp, *filep);
05157 return (int)(j+1);
05158 }
05159 FL_UNSET(tmp, FL_TAINT | FL_UNTRUSTED);
05160 }
05161 rb_str_set_len(fname, fnlen);
05162 }
05163 RB_GC_GUARD(load_path);
05164 return 0;
05165 }
05166
05167 VALUE
05168 rb_find_file(VALUE path)
05169 {
05170 return rb_find_file_safe(path, rb_safe_level());
05171 }
05172
05173 VALUE
05174 rb_find_file_safe(VALUE path, int safe_level)
05175 {
05176 VALUE tmp, load_path;
05177 const char *f = StringValueCStr(path);
05178 int expanded = 0;
05179
05180 if (f[0] == '~') {
05181 tmp = file_expand_path_1(path);
05182 if (safe_level >= 1 && OBJ_TAINTED(tmp)) {
05183 rb_raise(rb_eSecurityError, "loading from unsafe file %s", f);
05184 }
05185 path = copy_path_class(tmp, path);
05186 f = RSTRING_PTR(path);
05187 expanded = 1;
05188 }
05189
05190 if (expanded || rb_is_absolute_path(f) || is_explicit_relative(f)) {
05191 if (safe_level >= 1 && !fpath_check(path)) {
05192 rb_raise(rb_eSecurityError, "loading from unsafe path %s", f);
05193 }
05194 if (!file_load_ok(f)) return 0;
05195 if (!expanded)
05196 path = copy_path_class(file_expand_path_1(path), path);
05197 return path;
05198 }
05199
05200 if (safe_level >= 4) {
05201 rb_raise(rb_eSecurityError, "loading from non-absolute path %s", f);
05202 }
05203
05204 RB_GC_GUARD(load_path) = rb_get_load_path();
05205 if (load_path) {
05206 long i;
05207
05208 tmp = rb_str_tmp_new(MAXPATHLEN + 2);
05209 for (i = 0; i < RARRAY_LEN(load_path); i++) {
05210 VALUE str = RARRAY_PTR(load_path)[i];
05211 RB_GC_GUARD(str) = rb_get_path_check(str, safe_level);
05212 if (RSTRING_LEN(str) > 0) {
05213 file_expand_path(path, str, 0, tmp);
05214 f = RSTRING_PTR(tmp);
05215 if (file_load_ok(f)) goto found;
05216 }
05217 }
05218 return 0;
05219 }
05220 else {
05221 return 0;
05222 }
05223
05224 found:
05225 if (safe_level >= 1 && !fpath_check(tmp)) {
05226 rb_raise(rb_eSecurityError, "loading from unsafe file %s", f);
05227 }
05228
05229 return copy_path_class(tmp, path);
05230 }
05231
05232 static void
05233 define_filetest_function(const char *name, VALUE (*func)(ANYARGS), int argc)
05234 {
05235 rb_define_module_function(rb_mFileTest, name, func, argc);
05236 rb_define_singleton_method(rb_cFile, name, func, argc);
05237 }
05238
05239 static const char null_device[] =
05240 #if defined DOSISH
05241 "NUL"
05242 #elif defined AMIGA || defined __amigaos__
05243 "NIL"
05244 #elif defined __VMS
05245 "NL:"
05246 #else
05247 "/dev/null"
05248 #endif
05249 ;
05250
05251
05252
05253
05254
05255
05256
05257
05258
05259
05260
05261
05262
05263
05264
05265
05266
05267
05268
05269
05270
05271
05272
05273
05274
05275
05276
05277
05278
05279
05280
05281
05282
05283 void
05284 Init_File(void)
05285 {
05286 rb_mFileTest = rb_define_module("FileTest");
05287 rb_cFile = rb_define_class("File", rb_cIO);
05288
05289 define_filetest_function("directory?", rb_file_directory_p, 1);
05290 define_filetest_function("exist?", rb_file_exist_p, 1);
05291 define_filetest_function("exists?", rb_file_exist_p, 1);
05292 define_filetest_function("readable?", rb_file_readable_p, 1);
05293 define_filetest_function("readable_real?", rb_file_readable_real_p, 1);
05294 define_filetest_function("world_readable?", rb_file_world_readable_p, 1);
05295 define_filetest_function("writable?", rb_file_writable_p, 1);
05296 define_filetest_function("writable_real?", rb_file_writable_real_p, 1);
05297 define_filetest_function("world_writable?", rb_file_world_writable_p, 1);
05298 define_filetest_function("executable?", rb_file_executable_p, 1);
05299 define_filetest_function("executable_real?", rb_file_executable_real_p, 1);
05300 define_filetest_function("file?", rb_file_file_p, 1);
05301 define_filetest_function("zero?", rb_file_zero_p, 1);
05302 define_filetest_function("size?", rb_file_size_p, 1);
05303 define_filetest_function("size", rb_file_s_size, 1);
05304 define_filetest_function("owned?", rb_file_owned_p, 1);
05305 define_filetest_function("grpowned?", rb_file_grpowned_p, 1);
05306
05307 define_filetest_function("pipe?", rb_file_pipe_p, 1);
05308 define_filetest_function("symlink?", rb_file_symlink_p, 1);
05309 define_filetest_function("socket?", rb_file_socket_p, 1);
05310
05311 define_filetest_function("blockdev?", rb_file_blockdev_p, 1);
05312 define_filetest_function("chardev?", rb_file_chardev_p, 1);
05313
05314 define_filetest_function("setuid?", rb_file_suid_p, 1);
05315 define_filetest_function("setgid?", rb_file_sgid_p, 1);
05316 define_filetest_function("sticky?", rb_file_sticky_p, 1);
05317
05318 define_filetest_function("identical?", rb_file_identical_p, 2);
05319
05320 rb_define_singleton_method(rb_cFile, "stat", rb_file_s_stat, 1);
05321 rb_define_singleton_method(rb_cFile, "lstat", rb_file_s_lstat, 1);
05322 rb_define_singleton_method(rb_cFile, "ftype", rb_file_s_ftype, 1);
05323
05324 rb_define_singleton_method(rb_cFile, "atime", rb_file_s_atime, 1);
05325 rb_define_singleton_method(rb_cFile, "mtime", rb_file_s_mtime, 1);
05326 rb_define_singleton_method(rb_cFile, "ctime", rb_file_s_ctime, 1);
05327
05328 rb_define_singleton_method(rb_cFile, "utime", rb_file_s_utime, -1);
05329 rb_define_singleton_method(rb_cFile, "chmod", rb_file_s_chmod, -1);
05330 rb_define_singleton_method(rb_cFile, "chown", rb_file_s_chown, -1);
05331 rb_define_singleton_method(rb_cFile, "lchmod", rb_file_s_lchmod, -1);
05332 rb_define_singleton_method(rb_cFile, "lchown", rb_file_s_lchown, -1);
05333
05334 rb_define_singleton_method(rb_cFile, "link", rb_file_s_link, 2);
05335 rb_define_singleton_method(rb_cFile, "symlink", rb_file_s_symlink, 2);
05336 rb_define_singleton_method(rb_cFile, "readlink", rb_file_s_readlink, 1);
05337
05338 rb_define_singleton_method(rb_cFile, "unlink", rb_file_s_unlink, -2);
05339 rb_define_singleton_method(rb_cFile, "delete", rb_file_s_unlink, -2);
05340 rb_define_singleton_method(rb_cFile, "rename", rb_file_s_rename, 2);
05341 rb_define_singleton_method(rb_cFile, "umask", rb_file_s_umask, -1);
05342 rb_define_singleton_method(rb_cFile, "truncate", rb_file_s_truncate, 2);
05343 rb_define_singleton_method(rb_cFile, "expand_path", rb_file_s_expand_path, -1);
05344 rb_define_singleton_method(rb_cFile, "absolute_path", rb_file_s_absolute_path, -1);
05345 rb_define_singleton_method(rb_cFile, "realpath", rb_file_s_realpath, -1);
05346 rb_define_singleton_method(rb_cFile, "realdirpath", rb_file_s_realdirpath, -1);
05347 rb_define_singleton_method(rb_cFile, "basename", rb_file_s_basename, -1);
05348 rb_define_singleton_method(rb_cFile, "dirname", rb_file_s_dirname, 1);
05349 rb_define_singleton_method(rb_cFile, "extname", rb_file_s_extname, 1);
05350 rb_define_singleton_method(rb_cFile, "path", rb_file_s_path, 1);
05351
05352 separator = rb_obj_freeze(rb_usascii_str_new2("/"));
05353 rb_define_const(rb_cFile, "Separator", separator);
05354 rb_define_const(rb_cFile, "SEPARATOR", separator);
05355 rb_define_singleton_method(rb_cFile, "split", rb_file_s_split, 1);
05356 rb_define_singleton_method(rb_cFile, "join", rb_file_s_join, -2);
05357
05358 #ifdef DOSISH
05359 rb_define_const(rb_cFile, "ALT_SEPARATOR", rb_obj_freeze(rb_usascii_str_new2(file_alt_separator)));
05360 #else
05361 rb_define_const(rb_cFile, "ALT_SEPARATOR", Qnil);
05362 #endif
05363 rb_define_const(rb_cFile, "PATH_SEPARATOR", rb_obj_freeze(rb_str_new2(PATH_SEP)));
05364
05365 rb_define_method(rb_cIO, "stat", rb_io_stat, 0);
05366 rb_define_method(rb_cFile, "lstat", rb_file_lstat, 0);
05367
05368 rb_define_method(rb_cFile, "atime", rb_file_atime, 0);
05369 rb_define_method(rb_cFile, "mtime", rb_file_mtime, 0);
05370 rb_define_method(rb_cFile, "ctime", rb_file_ctime, 0);
05371 rb_define_method(rb_cFile, "size", rb_file_size, 0);
05372
05373 rb_define_method(rb_cFile, "chmod", rb_file_chmod, 1);
05374 rb_define_method(rb_cFile, "chown", rb_file_chown, 2);
05375 rb_define_method(rb_cFile, "truncate", rb_file_truncate, 1);
05376
05377 rb_define_method(rb_cFile, "flock", rb_file_flock, 1);
05378
05379 rb_mFConst = rb_define_module_under(rb_cFile, "Constants");
05380 rb_include_module(rb_cIO, rb_mFConst);
05381 rb_file_const("LOCK_SH", INT2FIX(LOCK_SH));
05382 rb_file_const("LOCK_EX", INT2FIX(LOCK_EX));
05383 rb_file_const("LOCK_UN", INT2FIX(LOCK_UN));
05384 rb_file_const("LOCK_NB", INT2FIX(LOCK_NB));
05385
05386 rb_file_const("NULL", rb_obj_freeze(rb_usascii_str_new2(null_device)));
05387
05388 rb_define_method(rb_cFile, "path", rb_file_path, 0);
05389 rb_define_method(rb_cFile, "to_path", rb_file_path, 0);
05390 rb_define_global_function("test", rb_f_test, -1);
05391
05392 rb_cStat = rb_define_class_under(rb_cFile, "Stat", rb_cObject);
05393 rb_define_alloc_func(rb_cStat, rb_stat_s_alloc);
05394 rb_define_method(rb_cStat, "initialize", rb_stat_init, 1);
05395 rb_define_method(rb_cStat, "initialize_copy", rb_stat_init_copy, 1);
05396
05397 rb_include_module(rb_cStat, rb_mComparable);
05398
05399 rb_define_method(rb_cStat, "<=>", rb_stat_cmp, 1);
05400
05401 rb_define_method(rb_cStat, "dev", rb_stat_dev, 0);
05402 rb_define_method(rb_cStat, "dev_major", rb_stat_dev_major, 0);
05403 rb_define_method(rb_cStat, "dev_minor", rb_stat_dev_minor, 0);
05404 rb_define_method(rb_cStat, "ino", rb_stat_ino, 0);
05405 rb_define_method(rb_cStat, "mode", rb_stat_mode, 0);
05406 rb_define_method(rb_cStat, "nlink", rb_stat_nlink, 0);
05407 rb_define_method(rb_cStat, "uid", rb_stat_uid, 0);
05408 rb_define_method(rb_cStat, "gid", rb_stat_gid, 0);
05409 rb_define_method(rb_cStat, "rdev", rb_stat_rdev, 0);
05410 rb_define_method(rb_cStat, "rdev_major", rb_stat_rdev_major, 0);
05411 rb_define_method(rb_cStat, "rdev_minor", rb_stat_rdev_minor, 0);
05412 rb_define_method(rb_cStat, "size", rb_stat_size, 0);
05413 rb_define_method(rb_cStat, "blksize", rb_stat_blksize, 0);
05414 rb_define_method(rb_cStat, "blocks", rb_stat_blocks, 0);
05415 rb_define_method(rb_cStat, "atime", rb_stat_atime, 0);
05416 rb_define_method(rb_cStat, "mtime", rb_stat_mtime, 0);
05417 rb_define_method(rb_cStat, "ctime", rb_stat_ctime, 0);
05418
05419 rb_define_method(rb_cStat, "inspect", rb_stat_inspect, 0);
05420
05421 rb_define_method(rb_cStat, "ftype", rb_stat_ftype, 0);
05422
05423 rb_define_method(rb_cStat, "directory?", rb_stat_d, 0);
05424 rb_define_method(rb_cStat, "readable?", rb_stat_r, 0);
05425 rb_define_method(rb_cStat, "readable_real?", rb_stat_R, 0);
05426 rb_define_method(rb_cStat, "world_readable?", rb_stat_wr, 0);
05427 rb_define_method(rb_cStat, "writable?", rb_stat_w, 0);
05428 rb_define_method(rb_cStat, "writable_real?", rb_stat_W, 0);
05429 rb_define_method(rb_cStat, "world_writable?", rb_stat_ww, 0);
05430 rb_define_method(rb_cStat, "executable?", rb_stat_x, 0);
05431 rb_define_method(rb_cStat, "executable_real?", rb_stat_X, 0);
05432 rb_define_method(rb_cStat, "file?", rb_stat_f, 0);
05433 rb_define_method(rb_cStat, "zero?", rb_stat_z, 0);
05434 rb_define_method(rb_cStat, "size?", rb_stat_s, 0);
05435 rb_define_method(rb_cStat, "owned?", rb_stat_owned, 0);
05436 rb_define_method(rb_cStat, "grpowned?", rb_stat_grpowned, 0);
05437
05438 rb_define_method(rb_cStat, "pipe?", rb_stat_p, 0);
05439 rb_define_method(rb_cStat, "symlink?", rb_stat_l, 0);
05440 rb_define_method(rb_cStat, "socket?", rb_stat_S, 0);
05441
05442 rb_define_method(rb_cStat, "blockdev?", rb_stat_b, 0);
05443 rb_define_method(rb_cStat, "chardev?", rb_stat_c, 0);
05444
05445 rb_define_method(rb_cStat, "setuid?", rb_stat_suid, 0);
05446 rb_define_method(rb_cStat, "setgid?", rb_stat_sgid, 0);
05447 rb_define_method(rb_cStat, "sticky?", rb_stat_sticky, 0);
05448 }
05449