ruby-changes:6404
From: nobu <ko1@a...>
Date: Mon, 7 Jul 2008 02:11:52 +0900 (JST)
Subject: [ruby-changes:6404] Ruby:r17920 (mvm): * dir.c (rb_dir_open, rb_dir_fchmod, rb_dir_lchmod, rb_dir_fchown),
nobu 2008-07-07 02:11:37 +0900 (Mon, 07 Jul 2008) New Revision: 17920 Modified files: branches/mvm/ChangeLog branches/mvm/dir.c branches/mvm/file.c branches/mvm/io.c Log: * dir.c (rb_dir_open, rb_dir_fchmod, rb_dir_lchmod, rb_dir_fchown), (rb_dir_lchown, rb_dir_fstat, rb_dir_lstat, rb_dir_utime), (rb_dir_mkdir, rb_dir_rmdir, rb_dir_unlink, rb_dir_chdir): added. * file.c (rb_file_stat_new, rb_stat, ruby_futimesat): made public. * io.c (rb_openat): added. http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=17920 Index: mvm/ChangeLog =================================================================== --- mvm/ChangeLog (revision 17919) +++ mvm/ChangeLog (revision 17920) @@ -1,3 +1,13 @@ +Mon Jul 7 02:11:34 2008 Nobuyoshi Nakada <nobu@r...> + + * dir.c (rb_dir_open, rb_dir_fchmod, rb_dir_lchmod, rb_dir_fchown), + (rb_dir_lchown, rb_dir_fstat, rb_dir_lstat, rb_dir_utime), + (rb_dir_mkdir, rb_dir_rmdir, rb_dir_unlink, rb_dir_chdir): added. + + * file.c (rb_file_stat_new, rb_stat, ruby_futimesat): made public. + + * io.c (rb_openat): added. + Mon Jul 7 02:04:57 2008 Nobuyoshi Nakada <nobu@r...> * dir.c (dir_s_chdir): restore cwd by fchdir if possible. Index: mvm/io.c =================================================================== --- mvm/io.c (revision 17919) +++ mvm/io.c (revision 17920) @@ -3549,6 +3549,67 @@ return rb_file_sysopen_internal(io_alloc(rb_cFile), fname, flags, mode); } +VALUE +rb_openat(int argc, VALUE *argv, int base, const char *path) +{ + VALUE fname, vmode, perm, newio; + volatile VALUE full; + int flags = O_RDONLY, fmode = 0666, fd; + const char *fullpath; +#ifdef AT_FDCWD + const char *name; +#endif + rb_io_t *fptr; + + rb_secure(2); + rb_scan_args(argc, argv, "12", &fname, &vmode, &perm); + FilePathValue(fname); + + if (!NIL_P(vmode)) { + if (FIXNUM_P(vmode)) { + flags = FIX2INT(vmode); + } + else { + SafeStringValue(vmode); + flags = rb_io_mode_modenum(RSTRING_PTR(vmode)); + } + } + if (!NIL_P(perm)) { + fmode = NUM2INT(perm); + } + newio = io_alloc(rb_cFile); + MakeOpenFile(newio, fptr); + fptr->mode = rb_io_modenum_flags(flags); +#ifdef AT_FDCWD + name = RSTRING_PTR(fname); +#define RB_DO_OPENAT() ((base == -1) ? \ + open(fullpath, flags, fmode) : \ + openat(base, name, flags, fmode)) +#else +#define RB_DO_OPENAT() open(fullpath, flags, fmode) +#endif + full = fname = rb_file_expand_path(fname, rb_str_new2(path)); + RBASIC(fname)->klass = 0; + OBJ_FREEZE(fname); + fullpath = RSTRING_PTR(fname); + if ((fd = RB_DO_OPENAT()) < 0) { + if (errno == EMFILE || errno == ENFILE) { + rb_gc(); + fd = RB_DO_OPENAT(); + } + if (fd < 0) { + rb_sys_fail(fullpath); + } + } +#undef RB_DO_OPENAT + fptr->fd = fd; + fptr->path = strdup(fullpath); + if (rb_block_given_p()) { + return rb_ensure(rb_yield, newio, io_close, newio); + } + return newio; +} + #if defined(__CYGWIN__) || !defined(HAVE_FORK) static struct pipe_list { rb_io_t *fptr; Index: mvm/dir.c =================================================================== --- mvm/dir.c (revision 17919) +++ mvm/dir.c (revision 17920) @@ -63,6 +63,9 @@ #include "ruby/util.h" +#define preserving_errno(stmts) \ + do {int saved_errno = errno; stmts; errno = saved_errno;} while (0) + #if !defined HAVE_LSTAT && !defined lstat #define lstat stat #endif @@ -1944,7 +1947,435 @@ return Qfalse; } +/* directory relative feature */ +static const char * +to_fullpath(volatile VALUE *fname, VALUE base) +{ + VALUE fullpath = rb_file_expand_path(*fname, base); + RBASIC(fullpath)->klass = 0; + OBJ_FREEZE(fullpath); + *fname = fullpath; + return RSTRING_PTR(fullpath); +} + +VALUE rb_openat(int argc, VALUE *argv, int base, const char *path); +#if defined HAVE_DIRFD && defined HAVE_OPENAT && defined AT_FDCWD +#define USE_OPENAT 1 +#else +#define USE_OPENAT 0 +#endif + /* + * call-seq: + * dir.open(relative-path, mode [, perm]) => File + * + * openes relative path. + */ +static VALUE +rb_dir_open(int argc, VALUE *argv, VALUE dir) +{ + struct dir_data *dp; + int base = -1; + + GetDIR(dir, dp); +#if USE_OPENAT + base = dirfd(dp->dir); +#endif + return rb_openat(argc, argv, base, dp->path); +} + +static long +apply2filesat(struct dir_data *dp, int (*func)(int, const char *, void *), + int argc, VALUE *argv, void *arg) +{ + long i; + volatile VALUE path; + const char *fullpath; + int base, ret; +#if !USE_OPENAT + VALUE basepath; +#endif + + rb_secure(4); +#if USE_OPENAT + base = dirfd(dp->dir); +#else + basepath = rb_str_new2(dp->path); +#ifdef AT_FDCWD + base = AT_FDCWD; +#else + base = -1; +#endif +#endif + for (i = 0; i < argc; i++) { + path = rb_get_path(argv[i]); + +#if USE_OPENAT + ret = (*func)(base, RSTRING_PTR(path), arg); +#else + fullpath = to_fullpath(&path, basepath); + ret = (*func)(base, fullpath, arg); +#endif + if (ret < 0) { +#if USE_OPENAT + preserving_errno(fullpath = to_fullpath(&path, rb_str_new2(dp->path))); +#endif + rb_sys_fail(fullpath); + } + } + + return i; +} + +static int +fchmodat_internal(int base, const char *path, void *arg) +{ + int *p = arg; +#if USE_OPENAT + return fchmodat(base, path, p[0], AT_SYMLINK_NOFOLLOW); +#else + return chmod(path, p[0]); +#endif +} + +static VALUE +rb_dir_fchmod(int argc, VALUE *argv, VALUE dir) +{ + struct dir_data *dp; + int mode; + long n; + + rb_secure(2); + if (argc < 1) { + rb_raise(rb_eArgError, "wrong number of argument (%d for 1)", argc); + } + --argc; + mode = NUM2INT(*argv); ++argv; + GetDIR(dir, dp); + n = apply2filesat(dp, fchmodat_internal, argc, argv, &mode); + return LONG2NUM(n); +} + +static int +lchmodat_internal(int base, const char *path, void *arg) +{ +#if USE_OPENAT + return fchmodat(base, path, *(int *)arg, 0); +#elif defined(HAVE_LCHMOD) + int *p = arg; + return lchmod(path, *(int *)arg); +#else + rb_notimplement(); + return Qnil; /* not reached */ +#endif +} + +static VALUE +rb_dir_lchmod(int argc, VALUE *argv, VALUE dir) +{ + struct dir_data *dp; + int mode; + long n; + + rb_secure(2); + if (argc < 1) { + rb_raise(rb_eArgError, "wrong number of argument (%d for 1)", argc); + } + --argc; + mode = NUM2INT(*argv); ++argv; + GetDIR(dir, dp); + n = apply2filesat(dp, lchmodat_internal, argc, argv, &mode); + return LONG2NUM(n); +} + +struct chown_args { + rb_uid_t owner; + rb_gid_t group; +}; + +static int +fchown_internal(int base, const char *path, void *arg) +{ + struct chown_args *p = arg; +#if USE_OPENAT + return fchownat(base, path, p->owner, p->group, 0); +#else + return chown(path, p->owner, p->group); +#endif +} + +static VALUE +rb_dir_fchown(int argc, VALUE *argv, VALUE dir) +{ + struct dir_data *dp; + struct chown_args arg; + long n; + + rb_secure(2); + if (argc < 2) { + rb_raise(rb_eArgError, "wrong number of argument (%d for 1)", argc); + } + argc -= 2; + arg.owner = NIL_P(*argv) ? -1 : NUM2UIDT(*argv); ++argv; + arg.group = NIL_P(*argv) ? -1 : NUM2GIDT(*argv); ++argv; + GetDIR(dir, dp); + n = apply2filesat(dp, fchown_internal, argc, argv, &arg); + return LONG2NUM(n); +} + +#if defined(AT_FDCWD) || defined(HAVE_LCHOWN) +static int +lchown_internal(int base, const char *path, void *arg) +{ + struct chown_args *p = arg; +#if USE_OPENAT + return fchownat(base, path, p->owner, p->group, AT_SYMLINK_NOFOLLOW); +#else + return lchown(path, p->owner, p->group); +#endif +} + +static VALUE +rb_dir_lchown(int argc, VALUE *argv, VALUE dir) +{ + struct dir_data *dp; + struct chown_args arg; + long n; + + rb_secure(2); + if (argc < 2) { + rb_raise(rb_eArgError, "wrong number of argument (%d for 1)", argc); + } + argc -= 2; + arg.owner = NIL_P(*argv) ? -1 : NUM2UIDT(*argv); ++argv; + arg.group = NIL_P(*argv) ? -1 : NUM2GIDT(*argv); ++argv; + GetDIR(dir, dp); + n = apply2filesat(dp, lchown_internal, argc, argv, &arg); + return LONG2NUM(n); +} +#else +static VALUE +rb_dir_lchown(int argc, VALUE *argv, VALUE dir) +{ + rb_notimplement(); +} +#endif + +VALUE rb_file_stat_new(struct stat *); + +static int +fstatat_internal(int base, const char *path, void *arg) +{ + struct stat *p = arg; +#if USE_OPENAT + return fstatat(base, path, p, 0); +#else + return stat(path, p); +#endif +} + +static VALUE +rb_dir_fstat(VALUE dir, VALUE path) +{ + struct dir_data *dp; + struct stat st; + + rb_secure(2); + GetDIR(dir, dp); + apply2filesat(dp, fstatat_internal, 1, &path, &st); + return rb_file_stat_new(&st); +} + +#ifdef HAVE_LSTAT +static int +lstatat_internal(int base, const char *path, void *arg) +{ + struct stat *p = arg; +#if USE_OPENAT + return fstatat(base, path, p, AT_SYMLINK_NOFOLLOW); +#else + return lstat(path, p); +#endif +} + +static VALUE +rb_dir_lstat(VALUE dir, VALUE path) +{ + struct dir_data *dp; + struct stat st; + + rb_secure(2); + GetDIR(dir, dp); + apply2filesat(dp, lstatat_internal, 1, &path, &st); + return rb_file_stat_new(&st); +} +#else +#define rb_io_lstatat rb_io_fstatat +#endif + +int ruby_futimesat(int base, const char *path, struct timespec *tsp); + +static int +futimesat_internal(int base, const char *path, void *arg) +{ + return ruby_futimesat(base, path, arg); +} + +struct timespec rb_time_timespec(VALUE time); + +static VALUE +rb_dir_utime(int argc, VALUE *argv, VALUE dir) +{ + struct dir_data *dp; + VALUE atime, mtime; + struct timespec tss[2], *tsp = NULL; + long n; + + rb_secure(2); + rb_scan_args(argc, argv, "2*", &atime, &mtime, 0); + argc -= 2; + argv += 2; + + if (!NIL_P(atime) || !NIL_P(mtime)) { + tsp = tss; + tsp[0] = rb_time_timespec(atime); + tsp[1] = rb_time_timespec(mtime); + } + + GetDIR(dir, dp); + n = apply2filesat(dp, futimesat_internal, argc, argv, tsp); + return LONG2FIX(n); +} + +#if 0 +static VALUE +rb_dir_link(int argc, VALUE *argv, VALUE dir) +{ + struct dir_data *dp; + + rb_secure(2); +#if USE_OPENAT + FilePathValue(from); + FilePathValue(to); + + GetDIR(dir, dp); + if (linkat(dirfd(dp->dir), RSTRING_PTR(from), dirfd(dp2->dir), RSTRING_PTR(to)) < 0) { + } +#else +#endif +} +#endif + +static VALUE +rb_dir_mkdir(int argc, VALUE *argv, VALUE dir) +{ + struct dir_data *dp; + VALUE path, vmode; + const char *fullpath; + int mode; + + rb_secure(2); + if (rb_scan_args(argc, argv, "11", &path, &vmode) == 2) { + mode = NUM2INT(vmode); + } + else { + mode = 0777; + } + + check_dirname(&path); + GetDIR(dir, dp); +#if USE_OPENAT + if (mkdirat(dirfd(dp), RSTRING_PTR(path), mode) == -1) { + preserving_errno(fullpath = to_fullpath(&path, rb_str_new2(dp->path))); + rb_sys_fail(fullpath); + } +#else + fullpath = to_fullpath(&path, rb_str_new2(dp->path)); + if (mkdir(fullpath, mode) == -1) { + rb_sys_fail(fullpath); + } +#endif + + return INT2FIX(0); +} + +static VALUE +rb_dir_unlink(VALUE dir, VALUE path) +{ + struct dir_data *dp; + const char *fullpath; + + rb_secure(2); + check_dirname(&path); + GetDIR(dir, dp); +#if USE_OPENAT + if (unlinkat(dirfd(dp), RSTRING_PTR(path), 0) == -1) { + preserving_errno(fullpath = to_fullpath(&path, rb_str_new2(dp->path))); + rb_sys_fail(fullpath); + } +#else + fullpath = to_fullpath(&path, rb_str_new2(dp->path)); + if (unlink(fullpath) == -1) { + rb_sys_fail(fullpath); + } +#endif + + return INT2FIX(0); +} + +static VALUE +rb_dir_chdir(int argc, VALUE *argv, VALUE dir) +{ + struct dir_data *dp; + VALUE path; + + if (rb_scan_args(argc, argv, "01", &path)) { + check_dirname(&path); + } + GetDIR(dir, dp); + +#if USE_OPENAT + if (fchdir(dirfd(dp->dir))) rb_sys_fail(0); +#else + path = rb_file_expand_path(path, rb_str_new2(dp->path)); +#endif + if (chdir(RSTRING_PTR(path))) rb_sys_fail(0); + + return INT2FIX(0); +} + +static VALUE +rb_dir_rmdir(VALUE dir, VALUE path) +{ + struct dir_data *dp; + const char *fullpath; + + rb_secure(2); + check_dirname(&path); + GetDIR(dir, dp); +#if USE_OPENAT + if (unlinkat(dirfd(dp), RSTRING_PTR(path), AT_REMOVEDIR) == -1) { + preserving_errno(fullpath = to_fullpath(&path, rb_str_new2(dp->path))); + rb_sys_fail(fullpath); + } +#else + fullpath = to_fullpath(&path, rb_str_new2(dp->path)); + if (rmdir(fullpath) == -1) { + rb_sys_fail(fullpath); + } +#endif + + return INT2FIX(0); +} + +/* + mknodat + readlinkat + renameat + symlinkat +*/ + +/* * Objects of class <code>Dir</code> are directory streams representing * directories in the underlying file system. They provide a variety of * ways to list directories and their contents. See also @@ -1979,6 +2410,19 @@ rb_define_method(rb_cDir,"pos=", dir_set_pos, 1); rb_define_method(rb_cDir,"close", dir_close, 0); + rb_define_method(rb_cDir, "open", rb_dir_open, -1); + rb_define_method(rb_cDir, "chmod", rb_dir_fchmod, -1); + rb_define_method(rb_cDir, "lchmod", rb_dir_lchmod, -1); + rb_define_method(rb_cDir, "chown", rb_dir_fchown, -1); + rb_define_method(rb_cDir, "lchown", rb_dir_lchown, -1); + rb_define_method(rb_cDir, "stat", rb_dir_fstat, 1); + rb_define_method(rb_cDir, "lstat", rb_dir_lstat, 1); + rb_define_method(rb_cDir, "utime", rb_dir_utime, -1); + rb_define_method(rb_cDir, "mkdir", rb_dir_mkdir, -1); + rb_define_method(rb_cDir, "rmdir", rb_dir_rmdir, 1); + rb_define_method(rb_cDir, "unlink", rb_dir_unlink, 1); + rb_define_method(rb_cDir, "chdir", rb_dir_chdir, -1); + rb_define_singleton_method(rb_cDir,"chdir", dir_s_chdir, -1); rb_define_singleton_method(rb_cDir,"getwd", dir_s_getwd, 0); rb_define_singleton_method(rb_cDir,"pwd", dir_s_getwd, 0); Index: mvm/file.c =================================================================== --- mvm/file.c (revision 17919) +++ mvm/file.c (revision 17920) @@ -183,12 +183,14 @@ return Data_Wrap_Struct(klass, NULL, -1, nst); } -static VALUE -stat_new(struct stat *st) +VALUE +rb_file_stat_new(struct stat *st) { return stat_new_0(rb_cStat, st); } +#define stat_new rb_file_stat_new + static struct stat* get_stat(VALUE self) { @@ -705,7 +707,7 @@ return str; } -static int +int rb_stat(VALUE file, struct stat *st) { VALUE tmp; @@ -2058,27 +2060,22 @@ #if defined(HAVE_UTIMES) -static void -utime_internal(const char *path, void *arg) +int +ruby_futimesat(int base, const char *path, struct timespec *tsp) { - struct timespec *tsp = arg; - struct timeval tvbuf[2], *tvp = arg; + struct timeval tvbuf[2], *tvp; #ifdef HAVE_UTIMENSAT static int try_utimensat = 1; - if (try_utimensat) { - struct timespec *tsp = arg; - if (utimensat(AT_FDCWD, path, tsp, 0) < 0) { - if (errno == ENOSYS) { - try_utimensat = 0; - goto no_utimensat; - } - rb_sys_fail(path); - } - return; + int ret = utimensat(base, path, tsp, 0); + if (ret < 0 && errno == ENOSYS) { + try_utimensat = 0; + goto no_utimensat; + } + return ret; } -no_utimensat: + no_utimensat: #endif if (tsp) { @@ -2088,8 +2085,27 @@ tvbuf[1].tv_usec = tsp[1].tv_nsec / 1000; tvp = tvbuf; } - if (utimes(path, tvp) < 0) + else { + tvp = 0; + } +#ifdef AT_FDCWD + return futimesat(base, path, tvp); +#else + return utimes(path, tvp); +#endif +} + +static void +utime_internal(const char *path, void *arg) +{ +#ifdef AT_FDCWD + const int fdcwd = AT_FDCWD; +#else + const int fdcwd = 0; +#endif + if (ruby_futimesat(fdcwd, path, arg) < 0) { rb_sys_fail(path); + } } #else -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/