[前][次][番号順一覧][スレッド一覧]

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/

[前][次][番号順一覧][スレッド一覧]