aboutsummaryrefslogtreecommitdiffstats
path: root/file.c
diff options
context:
space:
mode:
authormatz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>1998-01-16 12:13:05 +0000
committermatz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>1998-01-16 12:13:05 +0000
commit3db12e8b236ac8f88db8eb4690d10e4a3b8dbcd4 (patch)
treeb3c086e437cab449f90ba637710daed0ddfec4c4 /file.c
parent392296c12de9d7f9be03a8205250ba0844cb9d38 (diff)
downloadruby-3db12e8b236ac8f88db8eb4690d10e4a3b8dbcd4.tar.gz
Initial revisionv1_0_r2
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@2 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'file.c')
-rw-r--r--file.c1756
1 files changed, 1756 insertions, 0 deletions
diff --git a/file.c b/file.c
new file mode 100644
index 0000000000..0caa98adb1
--- /dev/null
+++ b/file.c
@@ -0,0 +1,1756 @@
+/************************************************
+
+ file.c -
+
+ $Author$
+ $Date$
+ created at: Mon Nov 15 12:24:34 JST 1993
+
+ Copyright (C) 1993-1996 Yukihiro Matsumoto
+
+************************************************/
+
+#include "ruby.h"
+#include "io.h"
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#else
+# define MAXPATHLEN 1024
+#endif
+
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#else
+#ifndef NT
+struct timeval {
+ long tv_sec; /* seconds */
+ long tv_usec; /* and microseconds */
+};
+#endif /* NT */
+#endif
+
+#ifdef HAVE_UTIME_H
+#include <utime.h>
+#endif
+
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+
+#ifdef HAVE_STRING_H
+# include <string.h>
+#else
+char *strrchr();
+#endif
+
+#ifdef NT
+#include <sys/stat.h>
+#endif
+
+#ifndef NT
+char *strdup();
+char *getenv();
+#endif
+
+extern VALUE cIO;
+VALUE cFile;
+VALUE mFileTest;
+static VALUE sStat;
+
+VALUE time_new();
+
+VALUE
+file_open(fname, mode)
+ char *fname, *mode;
+{
+ OpenFile *fptr;
+ NEWOBJ(port, struct RFile);
+ OBJSETUP(port, cFile, T_FILE);
+ MakeOpenFile(port, fptr);
+
+ fptr->mode = io_mode_flags(mode);
+ fptr->f = rb_fopen(fname, mode);
+ fptr->path = strdup(fname);
+
+ return (VALUE)port;
+}
+
+static VALUE
+file_s_open(argc, argv, class)
+ int argc;
+ VALUE *argv;
+ VALUE class;
+{
+ VALUE fname, vmode, file;
+ char *mode;
+
+ rb_scan_args(argc, argv, "11", &fname, &vmode);
+ Check_SafeStr(fname);
+ if (!NIL_P(vmode)) {
+ Check_Type(vmode, T_STRING);
+ mode = RSTRING(vmode)->ptr;
+ }
+ else {
+ mode = "r";
+ }
+ file = file_open(RSTRING(fname)->ptr, mode);
+
+ RBASIC(file)->class = class;
+ return file;
+}
+
+static VALUE
+file_reopen(argc, argv, file)
+ int argc;
+ VALUE *argv;
+ VALUE file;
+{
+ VALUE fname, nmode;
+ char *mode;
+ OpenFile *fptr;
+
+ if (rb_scan_args(argc, argv, "11", &fname, &nmode) == 1) {
+ if (TYPE(fname) == T_FILE) { /* fname must be IO */
+ return io_reopen(file, fname);
+ }
+ }
+
+ Check_SafeStr(fname);
+ if (!NIL_P(nmode)) {
+ Check_Type(nmode, T_STRING);
+ mode = RSTRING(nmode)->ptr;
+ }
+ else {
+ mode = "r";
+ }
+
+ GetOpenFile(file, fptr);
+ if (fptr->path) free(fptr->path);
+ fptr->path = strdup(RSTRING(fname)->ptr);
+ fptr->mode = io_mode_flags(mode);
+ if (!fptr->f) {
+ fptr->f = rb_fopen(RSTRING(fname)->ptr, mode);
+ if (fptr->f2) {
+ fclose(fptr->f2);
+ fptr->f2 = NULL;
+ }
+ return file;
+ }
+
+ if (freopen(RSTRING(fname)->ptr, mode, fptr->f) == NULL) {
+ rb_sys_fail(fptr->path);
+ }
+ if (fptr->f2) {
+ if (freopen(RSTRING(fname)->ptr, "w", fptr->f2) == NULL) {
+ rb_sys_fail(fptr->path);
+ }
+ }
+
+ return file;
+}
+
+static int
+apply2files(func, args, arg)
+ int (*func)();
+ struct RArray *args;
+ void *arg;
+{
+ int i;
+ VALUE path;
+
+ for (i=0; i<args->len; i++) {
+ Check_SafeStr(args->ptr[i]);
+ }
+
+ for (i=0; i<args->len; i++) {
+ path = args->ptr[i];
+ if ((*func)(RSTRING(path)->ptr, arg) < 0)
+ rb_sys_fail(RSTRING(path)->ptr);
+ }
+
+ return args->len;
+}
+
+static VALUE
+file_tell(obj)
+ VALUE obj;
+{
+ OpenFile *fptr;
+ long pos;
+
+ GetOpenFile(obj, fptr);
+
+ pos = ftell(fptr->f);
+ if (ferror(fptr->f) != 0) rb_sys_fail(0);
+
+ return int2inum(pos);
+}
+
+static VALUE
+file_seek(obj, offset, ptrname)
+ VALUE obj, offset, ptrname;
+{
+ OpenFile *fptr;
+ long pos;
+
+ GetOpenFile(obj, fptr);
+
+ pos = fseek(fptr->f, NUM2INT(offset), NUM2INT(ptrname));
+ if (pos != 0) rb_sys_fail(0);
+ clearerr(fptr->f);
+
+ return obj;
+}
+
+static VALUE
+file_set_pos(obj, offset)
+ VALUE obj, offset;
+{
+ OpenFile *fptr;
+ long pos;
+
+ GetOpenFile(obj, fptr);
+ pos = fseek(fptr->f, NUM2INT(offset), 0);
+ if (pos != 0) rb_sys_fail(0);
+ clearerr(fptr->f);
+
+ return obj;
+}
+
+static VALUE
+file_rewind(obj)
+ VALUE obj;
+{
+ OpenFile *fptr;
+
+ GetOpenFile(obj, fptr);
+ if (fseek(fptr->f, 0L, 0) != 0) rb_sys_fail(0);
+ clearerr(fptr->f);
+
+ return obj;
+}
+
+static VALUE
+file_eof(obj)
+ VALUE obj;
+{
+ OpenFile *fptr;
+
+ GetOpenFile(obj, fptr);
+ if (feof(fptr->f) == 0) return FALSE;
+ return TRUE;
+}
+
+static VALUE
+file_path(obj)
+ VALUE obj;
+{
+ OpenFile *fptr;
+
+ GetOpenFile(obj, fptr);
+ return str_new2(fptr->path);
+}
+
+static VALUE
+file_isatty(obj)
+ VALUE obj;
+{
+ return FALSE;
+}
+
+#include <sys/types.h>
+#ifndef NT
+#include <sys/file.h>
+#else
+#include "missing/file.h"
+#endif
+#include <sys/stat.h>
+
+static VALUE
+stat_new(st)
+ struct stat *st;
+{
+ if (!st) Bug("stat_new() called with bad value");
+ return struct_new(sStat,
+ INT2FIX((int)st->st_dev),
+ INT2FIX((int)st->st_ino),
+ INT2FIX((int)st->st_mode),
+ INT2FIX((int)st->st_nlink),
+ INT2FIX((int)st->st_uid),
+ INT2FIX((int)st->st_gid),
+#ifdef HAVE_ST_RDEV
+ INT2FIX((int)st->st_rdev),
+#else
+ INT2FIX(0),
+#endif
+ INT2FIX((int)st->st_size),
+#ifdef HAVE_ST_BLKSIZE
+ INT2FIX((int)st->st_blksize),
+#else
+ INT2FIX(0),
+#endif
+#ifdef HAVE_ST_BLOCKS
+ INT2FIX((int)st->st_blocks),
+#else
+ INT2FIX(0),
+#endif
+ time_new(st->st_atime, 0),
+ time_new(st->st_mtime, 0),
+ time_new(st->st_ctime, 0));
+}
+
+static VALUE
+file_s_stat(obj, fname)
+ VALUE obj;
+ struct RString *fname;
+{
+ struct stat st;
+
+ Check_SafeStr(fname);
+ if (stat(fname->ptr, &st) == -1) {
+ rb_sys_fail(fname->ptr);
+ }
+ return stat_new(&st);
+}
+
+static VALUE
+file_stat(obj)
+ VALUE obj;
+{
+ OpenFile *fptr;
+ struct stat st;
+
+ GetOpenFile(obj, fptr);
+ if (fstat(fileno(fptr->f), &st) == -1) {
+ rb_sys_fail(fptr->path);
+ }
+ return stat_new(&st);
+}
+
+static VALUE
+file_s_lstat(obj, fname)
+ VALUE obj;
+ struct RString *fname;
+{
+#if !defined(MSDOS) && !defined(NT)
+ struct stat st;
+
+ Check_SafeStr(fname);
+ if (lstat(fname->ptr, &st) == -1) {
+ rb_sys_fail(fname->ptr);
+ }
+ return stat_new(&st);
+#else
+ rb_notimplement();
+#endif
+}
+
+static VALUE
+file_lstat(obj)
+ VALUE obj;
+{
+#if !defined(MSDOS) && !defined(NT)
+ OpenFile *fptr;
+ struct stat st;
+
+ GetOpenFile(obj, fptr);
+ if (lstat(fptr->path, &st) == -1) {
+ rb_sys_fail(fptr->path);
+ }
+ return stat_new(&st);
+#else
+ rb_notimplement();
+#endif
+}
+
+static int
+group_member(gid)
+ GETGROUPS_T gid;
+{
+#ifndef NT
+ if (getgid() == gid || getegid() == gid)
+ return TRUE;
+
+# ifdef HAVE_GETGROUPS
+# ifndef NGROUPS
+# define NGROUPS 32
+# endif
+ {
+ GETGROUPS_T gary[NGROUPS];
+ int anum;
+
+ anum = getgroups(NGROUPS, gary);
+ while (--anum >= 0)
+ if (gary[anum] == gid)
+ return TRUE;
+ }
+# endif
+#endif
+ return FALSE;
+}
+
+#ifndef S_IXUGO
+# define S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH)
+#endif
+
+int
+eaccess(path, mode)
+ char *path;
+ int mode;
+{
+#ifndef NT
+ struct stat st;
+ static int euid = -1;
+
+ if (stat(path, &st) < 0) return (-1);
+
+ if (euid == -1)
+ euid = geteuid ();
+
+ if (euid == 0)
+ {
+ /* Root can read or write any file. */
+ if (mode != X_OK)
+ return 0;
+
+ /* Root can execute any file that has any one of the execute
+ bits set. */
+ if (st.st_mode & S_IXUGO)
+ return 0;
+ }
+
+#if defined(DJGPP)
+ {
+ int stat_mode = 0;
+ if (mode & X_OK)
+ stat_mode |= S_IXOTH;
+ if (mode & W_OK)
+ stat_mode |= S_IWOTH;
+ if (mode & R_OK)
+ stat_mode |= S_IROTH;
+ mode = stat_mode;
+ }
+#endif
+
+ if (st.st_uid == euid) /* owner */
+ mode <<= 6;
+ else if (group_member (st.st_gid))
+ mode <<= 3;
+
+ if (st.st_mode & mode) return 0;
+
+ return -1;
+#else /* !NT*/
+ return 0;
+#endif
+}
+
+static VALUE
+test_d(obj, fname)
+ VALUE obj;
+ struct RString *fname;
+{
+#ifndef S_ISDIR
+# define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR)
+#endif
+
+ struct stat st;
+
+ Check_SafeStr(fname);
+ if (stat(fname->ptr, &st) < 0) return FALSE;
+ if (S_ISDIR(st.st_mode)) return TRUE;
+ return FALSE;
+}
+
+static VALUE
+test_p(obj, fname)
+ VALUE obj;
+ struct RString *fname;
+{
+#ifdef S_IFIFO
+# ifndef S_ISFIFO
+# define S_ISFIFO(m) ((m & S_IFMT) == S_IFIFO)
+# endif
+
+ struct stat st;
+
+ Check_SafeStr(fname);
+ if (stat(fname->ptr, &st) < 0) return FALSE;
+ if (S_ISFIFO(st.st_mode)) return TRUE;
+
+#endif
+ return FALSE;
+}
+
+static VALUE
+test_l(obj, fname)
+ VALUE obj;
+ struct RString *fname;
+{
+#ifndef S_ISLNK
+# ifdef _S_ISLNK
+# define S_ISLNK(m) _S_ISLNK(m)
+# else
+# ifdef _S_IFLNK
+# define S_ISLNK(m) ((m & S_IFMT) == _S_IFLNK)
+# else
+# ifdef S_IFLNK
+# define S_ISLNK(m) ((m & S_IFMT) == S_IFLNK)
+# endif
+# endif
+# endif
+#endif
+
+#ifdef S_ISLNK
+ struct stat st;
+
+ Check_SafeStr(fname);
+ if (lstat(fname->ptr, &st) < 0) return FALSE;
+ if (S_ISLNK(st.st_mode)) return TRUE;
+
+#endif
+ return FALSE;
+}
+
+static VALUE
+test_S(obj, fname)
+ VALUE obj;
+ struct RString *fname;
+{
+#ifndef S_ISSOCK
+# ifdef _S_ISSOCK
+# define S_ISSOCK(m) _S_ISSOCK(m)
+# else
+# ifdef _S_IFSOCK
+# define S_ISSOCK(m) ((m & S_IFMT) == _S_IFSOCK)
+# else
+# ifdef S_IFSOCK
+# define S_ISSOCK(m) ((m & S_IFMT) == S_IFSOCK)
+# endif
+# endif
+# endif
+#endif
+
+#ifdef S_ISSOCK
+ struct stat st;
+
+ Check_SafeStr(fname);
+ if (stat(fname->ptr, &st) < 0) return FALSE;
+ if (S_ISSOCK(st.st_mode)) return TRUE;
+
+#endif
+ return FALSE;
+}
+
+static VALUE
+test_b(obj, fname)
+ VALUE obj;
+ struct RString *fname;
+{
+#ifndef S_ISBLK
+# ifdef S_IFBLK
+# define S_ISBLK(m) ((m & S_IFMT) == S_IFBLK)
+# else
+# define S_ISBLK(m) (0) /* anytime false */
+# endif
+#endif
+
+#ifdef S_ISBLK
+ struct stat st;
+
+ Check_SafeStr(fname);
+ if (stat(fname->ptr, &st) < 0) return FALSE;
+ if (S_ISBLK(st.st_mode)) return TRUE;
+
+#endif
+ return FALSE;
+}
+
+static VALUE
+test_c(obj, fname)
+ VALUE obj;
+ struct RString *fname;
+{
+#ifndef S_ISCHR
+# define S_ISCHR(m) ((m & S_IFMT) == S_IFCHR)
+#endif
+
+ struct stat st;
+
+ Check_SafeStr(fname);
+ if (stat(fname->ptr, &st) < 0) return FALSE;
+ if (S_ISBLK(st.st_mode)) return TRUE;
+
+ return FALSE;
+}
+
+static VALUE
+test_e(obj, fname)
+ VALUE obj;
+ struct RString *fname;
+{
+ struct stat st;
+
+ Check_SafeStr(fname);
+ if (stat(fname->ptr, &st) < 0) return FALSE;
+ return TRUE;
+}
+
+static VALUE
+test_r(obj, fname)
+ VALUE obj;
+ struct RString *fname;
+{
+ Check_SafeStr(fname);
+ if (eaccess(fname->ptr, R_OK) < 0) return FALSE;
+ return TRUE;
+}
+
+static VALUE
+test_R(obj, fname)
+ VALUE obj;
+ struct RString *fname;
+{
+ Check_SafeStr(fname);
+ if (access(fname->ptr, R_OK) < 0) return FALSE;
+ return TRUE;
+}
+
+static VALUE
+test_w(obj, fname)
+ VALUE obj;
+ struct RString *fname;
+{
+ Check_SafeStr(fname);
+ if (eaccess(fname->ptr, W_OK) < 0) return FALSE;
+ return TRUE;
+}
+
+static VALUE
+test_W(obj, fname)
+ VALUE obj;
+ struct RString *fname;
+{
+ Check_SafeStr(fname);
+ if (access(fname->ptr, W_OK) < 0) return FALSE;
+ return TRUE;
+}
+
+static VALUE
+test_x(obj, fname)
+ VALUE obj;
+ struct RString *fname;
+{
+ Check_SafeStr(fname);
+ if (eaccess(fname->ptr, X_OK) < 0) return FALSE;
+ return TRUE;
+}
+
+static VALUE
+test_X(obj, fname)
+ VALUE obj;
+ struct RString *fname;
+{
+ Check_SafeStr(fname);
+ if (access(fname->ptr, X_OK) < 0) return FALSE;
+ return TRUE;
+}
+
+#ifndef S_ISREG
+# define S_ISREG(m) ((m & S_IFMT) == S_IFREG)
+#endif
+
+static VALUE
+test_f(obj, fname)
+ VALUE obj;
+ struct RString *fname;
+{
+ struct stat st;
+
+ Check_SafeStr(fname);
+ if (stat(fname->ptr, &st) < 0) return FALSE;
+ if (S_ISREG(st.st_mode)) return TRUE;
+ return FALSE;
+}
+
+static VALUE
+test_z(obj, fname)
+ VALUE obj;
+ struct RString *fname;
+{
+ struct stat st;
+
+ Check_SafeStr(fname);
+ if (stat(fname->ptr, &st) < 0) return FALSE;
+ if (st.st_size == 0) return TRUE;
+ return FALSE;
+}
+
+static VALUE
+test_s(obj, fname)
+ VALUE obj;
+ struct RString *fname;
+{
+ struct stat st;
+
+ Check_SafeStr(fname);
+ if (stat(fname->ptr, &st) < 0) return FALSE;
+ if (st.st_size == 0) return FALSE;
+ return int2inum(st.st_size);
+}
+
+static VALUE
+test_owned(obj, fname)
+ VALUE obj;
+ struct RString *fname;
+{
+ struct stat st;
+
+ Check_SafeStr(fname);
+ if (stat(fname->ptr, &st) < 0) return FALSE;
+ if (st.st_uid == geteuid()) return TRUE;
+ return FALSE;
+}
+
+static VALUE
+test_rowned(obj, fname)
+ VALUE obj;
+ struct RString *fname;
+{
+ struct stat st;
+
+ Check_SafeStr(fname);
+ if (stat(fname->ptr, &st) < 0) return FALSE;
+ if (st.st_uid == getuid()) return TRUE;
+ return FALSE;
+}
+
+static VALUE
+test_grpowned(obj, fname)
+ VALUE obj;
+ struct RString *fname;
+{
+#ifndef NT
+ struct stat st;
+
+ Check_SafeStr(fname);
+ if (stat(fname->ptr, &st) < 0) return FALSE;
+ if (st.st_gid == getegid()) return TRUE;
+#endif
+ return FALSE;
+}
+
+#if defined(S_ISUID) || defined(S_ISGID) || defined(S_ISVTX)
+static VALUE
+check3rdbyte(file, mode)
+ char *file;
+ int mode;
+{
+ struct stat st;
+
+ if (stat(file, &st) < 0) return FALSE;
+ if (st.st_mode & mode) return TRUE;
+ return FALSE;
+}
+#endif
+
+static VALUE
+test_suid(obj, fname)
+ VALUE obj;
+ struct RString *fname;
+{
+#ifdef S_ISUID
+ Check_SafeStr(fname);
+ return check3rdbyte(fname->ptr, S_ISUID);
+#else
+ return FALSE;
+#endif
+}
+
+static VALUE
+test_sgid(obj, fname)
+ VALUE obj;
+ struct RString *fname;
+{
+#ifndef NT
+ Check_SafeStr(fname);
+ return check3rdbyte(fname->ptr, S_ISGID);
+#else
+ return FALSE;
+#endif
+}
+
+static VALUE
+test_sticky(obj, fname)
+ VALUE obj;
+ struct RString *fname;
+{
+ Check_Type(fname, T_STRING);
+#ifdef S_ISVTX
+ return check3rdbyte(fname->ptr, S_ISVTX);
+#else
+ return FALSE;
+#endif
+}
+
+static VALUE
+file_s_size(obj, fname)
+ VALUE obj;
+ struct RString *fname;
+{
+ struct stat st;
+
+ Check_SafeStr(fname);
+ if (stat(fname->ptr, &st) < 0) rb_sys_fail(fname->ptr);
+ return int2inum(st.st_size);
+}
+
+static VALUE
+file_s_ftype(obj, fname)
+ VALUE obj;
+ struct RString *fname;
+{
+ struct stat st;
+ char *t;
+
+ Check_SafeStr(fname);
+ if (stat(fname->ptr, &st) < 0) rb_sys_fail(fname->ptr);
+
+ if (S_ISREG(st.st_mode)) {
+ t = "file";
+ } else if (S_ISDIR(st.st_mode)) {
+ t = "directory";
+ } else if (S_ISCHR(st.st_mode)) {
+ t = "characterSpecial";
+ }
+#ifdef S_ISBLK
+ else if (S_ISBLK(st.st_mode)) {
+ t = "blockSpecial";
+ }
+#endif
+#ifdef S_ISFIFO
+ else if (S_ISFIFO(st.st_mode)) {
+ t = "fifo";
+ }
+#endif
+#ifdef S_ISLNK
+ else if (S_ISLNK(st.st_mode)) {
+ t = "link";
+ }
+#endif
+#ifdef S_ISSOCK
+ else if (S_ISSOCK(st.st_mode)) {
+ t = "socket";
+ }
+#endif
+ else {
+ t = "unknown";
+ }
+
+ return str_new2(t);
+}
+
+static VALUE
+file_s_atime(obj, fname)
+ VALUE obj;
+ struct RString *fname;
+{
+ struct stat st;
+
+ Check_SafeStr(fname);
+ if (stat(fname->ptr, &st) < 0) rb_sys_fail(fname->ptr);
+ return time_new(st.st_atime, 0);
+}
+
+static VALUE
+file_atime(obj)
+ VALUE obj;
+{
+ OpenFile *fptr;
+ struct stat st;
+
+ GetOpenFile(obj, fptr);
+ if (fstat(fileno(fptr->f), &st) == -1) {
+ rb_sys_fail(fptr->path);
+ }
+ return time_new(st.st_atime, 0);
+}
+
+static VALUE
+file_s_mtime(obj, fname)
+ VALUE obj;
+ struct RString *fname;
+{
+ struct stat st;
+
+ Check_SafeStr(fname);
+ if (stat(fname->ptr, &st) < 0) rb_sys_fail(fname->ptr);
+ return time_new(st.st_mtime, 0);
+}
+
+static VALUE
+file_mtime(obj)
+ VALUE obj;
+{
+ OpenFile *fptr;
+ struct stat st;
+
+ GetOpenFile(obj, fptr);
+ if (fstat(fileno(fptr->f), &st) == -1) {
+ rb_sys_fail(fptr->path);
+ }
+ return time_new(st.st_mtime, 0);
+}
+
+static VALUE
+file_s_ctime(obj, fname)
+ VALUE obj;
+ struct RString *fname;
+{
+ struct stat st;
+
+ Check_SafeStr(fname);
+ if (stat(fname->ptr, &st) < 0) rb_sys_fail(fname->ptr);
+ return time_new(st.st_ctime, 0);
+}
+
+static VALUE
+file_ctime(obj)
+ VALUE obj;
+{
+ OpenFile *fptr;
+ struct stat st;
+
+ GetOpenFile(obj, fptr);
+ if (fstat(fileno(fptr->f), &st) == -1) {
+ rb_sys_fail(fptr->path);
+ }
+ return time_new(st.st_ctime, 0);
+}
+
+static void
+chmod_internal(path, mode)
+ char *path;
+ int mode;
+{
+ if (chmod(path, mode) == -1)
+ rb_sys_fail(path);
+}
+
+static VALUE
+file_s_chmod(argc, argv)
+ int argc;
+ VALUE *argv;
+{
+ VALUE vmode;
+ VALUE rest;
+ int mode, n;
+
+ rb_scan_args(argc, argv, "1*", &vmode, &rest);
+ mode = NUM2INT(vmode);
+
+ n = apply2files(chmod_internal, rest, mode);
+ return INT2FIX(n);
+}
+
+static VALUE
+file_chmod(obj, vmode)
+ VALUE obj, vmode;
+{
+ OpenFile *fptr;
+ int mode;
+
+ rb_secure(2);
+ mode = NUM2INT(vmode);
+
+ GetOpenFile(obj, fptr);
+#if defined(DJGPP) || defined(__CYGWIN32__) || defined(NT)
+ if (chmod(fptr->path, mode) == -1)
+ rb_sys_fail(fptr->path);
+#else
+ if (fchmod(fileno(fptr->f), mode) == -1)
+ rb_sys_fail(fptr->path);
+#endif
+
+ return INT2FIX(0);
+}
+
+struct chown_args {
+ int owner, group;
+};
+
+static void
+chown_internal(path, args)
+ char *path;
+ struct chown_args *args;
+{
+ if (chown(path, args->owner, args->group) < 0)
+ rb_sys_fail(path);
+}
+
+static VALUE
+file_s_chown(argc, argv)
+ int argc;
+ VALUE *argv;
+{
+ VALUE o, g, rest;
+ struct chown_args arg;
+ int n;
+
+ rb_scan_args(argc, argv, "2*", &o, &g, &rest);
+ if (NIL_P(o)) {
+ arg.owner = -1;
+ }
+ else {
+ arg.owner = NUM2INT(o);
+ }
+ if (NIL_P(g)) {
+ arg.group = -1;
+ }
+ else {
+ arg.group = NUM2INT(g);
+ }
+
+ n = apply2files(chown_internal, rest, &arg);
+ return INT2FIX(n);
+}
+
+static VALUE
+file_chown(obj, owner, group)
+ VALUE obj, owner, group;
+{
+ OpenFile *fptr;
+
+ rb_secure(2);
+ GetOpenFile(obj, fptr);
+#if defined(DJGPP) || defined(__CYGWIN32__) || defined(NT)
+ if (chown(fptr->path, NUM2INT(owner), NUM2INT(group)) == -1)
+ rb_sys_fail(fptr->path);
+#else
+ if (fchown(fileno(fptr->f), NUM2INT(owner), NUM2INT(group)) == -1)
+ rb_sys_fail(fptr->path);
+#endif
+
+ return INT2FIX(0);
+}
+
+struct timeval time_timeval();
+
+#ifdef HAVE_UTIMES
+
+static void
+utime_internal(path, tvp)
+ char *path;
+ struct timeval tvp[];
+{
+ if (utimes(path, tvp) < 0)
+ rb_sys_fail(path);
+}
+
+static VALUE
+file_s_utime(argc, argv)
+ int argc;
+ VALUE *argv;
+{
+ VALUE atime, mtime, rest;
+ struct timeval tvp[2];
+ int n;
+
+ rb_scan_args(argc, argv, "2*", &atime, &mtime, &rest);
+
+ tvp[0] = time_timeval(atime);
+ tvp[1] = time_timeval(mtime);
+
+ n = apply2files(utime_internal, rest, tvp);
+ return INT2FIX(n);
+}
+
+#else
+
+#ifndef HAVE_UTIME_H
+# ifdef NT
+# include <sys/utime.h>
+# define utimbuf _utimbuf
+# else
+struct utimbuf {
+ long actime;
+ long modtime;
+};
+# endif
+#endif
+
+static void
+utime_internal(path, utp)
+ char *path;
+ struct utimbuf *utp;
+{
+ if (utime(path, utp) < 0)
+ rb_sys_fail(path);
+}
+
+static VALUE
+file_s_utime(argc, argv)
+ int argc;
+ VALUE *argv;
+{
+ VALUE atime, mtime, rest;
+ int n;
+ struct timeval tv;
+ struct utimbuf utbuf;
+
+ rb_scan_args(argc, argv, "2*", &atime, &mtime, &rest);
+
+ tv = time_timeval(atime);
+ utbuf.actime = tv.tv_sec;
+ tv = time_timeval(mtime);
+ utbuf.modtime = tv.tv_sec;
+
+ n = apply2files(utime_internal, rest, &utbuf);
+ return INT2FIX(n);
+}
+
+#endif
+
+static VALUE
+file_s_link(obj, from, to)
+ VALUE obj;
+ struct RString *from, *to;
+{
+#ifndef __human68k__
+ Check_SafeStr(from);
+ Check_SafeStr(to);
+
+ if (link(from->ptr, to->ptr) < 0)
+ rb_sys_fail(from->ptr);
+ return INT2FIX(0);
+#else
+ rb_notimplement();
+#endif
+}
+
+static VALUE
+file_s_symlink(obj, from, to)
+ VALUE obj;
+ struct RString *from, *to;
+{
+#if !defined(MSDOS) && !defined(NT)
+ Check_SafeStr(from);
+ Check_SafeStr(to);
+
+ if (symlink(from->ptr, to->ptr) < 0)
+ rb_sys_fail(from->ptr);
+ return TRUE;
+#else
+ rb_notimplement();
+#endif
+}
+
+static VALUE
+file_s_readlink(obj, path)
+ VALUE obj;
+ struct RString *path;
+{
+#if !defined(MSDOS) && !defined(NT)
+ char buf[MAXPATHLEN];
+ int cc;
+
+ Check_SafeStr(path);
+
+ if ((cc = readlink(path->ptr, buf, MAXPATHLEN)) < 0)
+ rb_sys_fail(path->ptr);
+
+ return str_new(buf, cc);
+#else
+ rb_notimplement();
+#endif
+}
+
+static void
+unlink_internal(path)
+ char *path;
+{
+ if (unlink(path) < 0)
+ rb_sys_fail(path);
+}
+
+static VALUE
+file_s_unlink(obj, args)
+ VALUE obj;
+ struct RArray *args;
+{
+ int n;
+
+ n = apply2files(unlink_internal, args, 0);
+ return INT2FIX(n);
+}
+
+static VALUE
+file_s_rename(obj, from, to)
+ VALUE obj;
+ struct RString *from, *to;
+{
+ Check_SafeStr(from);
+ Check_SafeStr(to);
+
+ if (rename(from->ptr, to->ptr) == -1)
+ rb_sys_fail(from->ptr);
+
+ return INT2FIX(0);
+}
+
+static VALUE
+file_s_umask(argc, argv)
+ int argc;
+ VALUE *argv;
+{
+ int omask = 0;
+
+ if (argc == 0) {
+ int omask = umask(0);
+ umask(omask);
+ }
+ else if (argc == 1) {
+ omask = umask(NUM2INT(argv[0]));
+ }
+ else {
+ ArgError("wrong # of argument");
+ }
+ return INT2FIX(omask);
+}
+
+VALUE
+file_s_expand_path(obj, fname)
+ VALUE obj;
+ struct RString *fname;
+{
+ char *s, *p;
+ char buf[MAXPATHLEN];
+
+ Check_Type(fname, T_STRING);
+ s = fname->ptr;
+
+ p = buf;
+ if (s[0] == '~') {
+ if (s[1] == '/' || s[1] == '\0') {
+ char *dir = getenv("HOME");
+
+ if (!dir) {
+ Fail("couldn't find HOME environment -- expanding `%s'", s);
+ }
+ strcpy(buf, dir);
+ p = &buf[strlen(buf)];
+ s++;
+ }
+ else {
+#ifdef HAVE_PWD_H
+ struct passwd *pwPtr;
+ s++;
+#endif
+
+ while (*s && *s != '/') {
+ *p++ = *s++;
+ }
+ *p = '\0';
+#ifdef HAVE_PWD_H
+ pwPtr = getpwnam(buf);
+ if (!pwPtr) {
+ endpwent();
+ Fail("user %s doesn't exist", buf);
+ }
+ strcpy(buf, pwPtr->pw_dir);
+ p = &buf[strlen(buf)];
+ endpwent();
+#endif
+ }
+ }
+ else if (s[0] != '/') {
+#ifdef HAVE_GETCWD
+ getcwd(buf, MAXPATHLEN);
+#else
+ getwd(buf);
+#endif
+ p = &buf[strlen(buf)];
+ }
+ *p = '/';
+
+ for ( ; *s; s++) {
+ switch (*s) {
+ case '.':
+ if (*(s+1)) {
+ switch (*++s) {
+ case '.':
+ if (*(s+1) == '\0' || *(s+1) == '/') {
+ /* We must go back to the parent */
+ if (*p == '/' && p > buf) p--;
+ while (p > buf && *p != '/') p--;
+ }
+ else {
+ *++p = '.';
+ *++p = '.';
+ }
+ break;
+ case '/':
+ if (*p != '/') *++p = '/';
+ break;
+ default:
+ *++p = '.'; *++p = *s; break;
+ }
+ }
+ break;
+ case '/':
+ if (*p != '/') *++p = '/'; break;
+ default:
+ *++p = *s;
+ }
+ }
+
+ /* Place a \0 at end. If path ends with a "/", delete it */
+ if (p == buf || *p != '/') p++;
+ *p = '\0';
+
+ return str_taint(str_new2(buf));
+}
+
+static int
+rmext(p, e)
+ char *p, *e;
+{
+ int l1, l2;
+
+ l1 = strlen(p);
+ if (!e) return 0;
+
+ l2 = strlen(e);
+ if (l1 < l2) return l1;
+
+ if (strcmp(p+l1-l2, e) == 0) {
+ return l1-l2;
+ }
+ return 0;
+}
+
+static VALUE
+file_s_basename(argc, argv)
+ int argc;
+ VALUE *argv;
+{
+ struct RString *fname;
+ struct RString *ext;
+ char *p;
+ int f;
+
+ rb_scan_args(argc, argv, "11", &fname, &ext);
+ Check_Type(fname, T_STRING);
+ if (!NIL_P(ext)) Check_Type(ext, T_STRING);
+ p = strrchr(fname->ptr, '/');
+ if (!p) {
+ if (!NIL_P(ext)) {
+ f = rmext(fname->ptr, ext->ptr);
+ if (f) return str_new(fname->ptr, f);
+ }
+ return (VALUE)fname;
+ }
+ p++; /* skip last `/' */
+ if (!NIL_P(ext)) {
+ f = rmext(p, ext->ptr);
+ if (f) return str_new(p, f);
+ }
+ return str_taint(str_new2(p));
+}
+
+static VALUE
+file_s_dirname(obj, fname)
+ VALUE obj;
+ struct RString *fname;
+{
+ UCHAR *p;
+
+ Check_Type(fname, T_STRING);
+ p = strrchr(fname->ptr, '/');
+ if (!p) {
+ return str_new2(".");
+ }
+ if (p == fname->ptr)
+ p++;
+ return str_taint(str_new(fname->ptr, p - fname->ptr));
+}
+
+static VALUE
+file_s_split(obj, path)
+ VALUE obj, path;
+{
+ return assoc_new(file_s_dirname(Qnil, path), file_s_basename(1,&path));
+}
+
+static VALUE separator;
+
+static VALUE
+file_s_join(obj, args)
+ VALUE obj, args;
+{
+ return ary_join(args, separator);
+}
+
+static VALUE
+file_s_truncate(obj, path, len)
+ VALUE obj, len;
+ struct RString *path;
+{
+ Check_SafeStr(path);
+
+#ifdef HAVE_TRUNCATE
+ if (truncate(path->ptr, NUM2INT(len)) < 0)
+ rb_sys_fail(path->ptr);
+#else
+# ifdef HAVE_CHSIZE
+ {
+ int tmpfd;
+
+# if defined(NT)
+ if ((tmpfd = open(path->ptr, O_RDWR)) < 0) {
+ rb_sys_fail(path->ptr);
+ }
+# else
+ if ((tmpfd = open(path->ptr, 0)) < 0) {
+ rb_sys_fail(path->ptr);
+ }
+# endif
+ if (chsize(tmpfd, NUM2INT(len)) < 0) {
+ close(tmpfd);
+ rb_sys_fail(path->ptr);
+ }
+ close(tmpfd);
+ }
+# else
+ rb_notimplement();
+# endif
+#endif
+ return TRUE;
+}
+
+static VALUE
+file_truncate(obj, len)
+ VALUE obj, len;
+{
+ OpenFile *fptr;
+
+ GetOpenFile(obj, fptr);
+
+ rb_secure(2);
+ if (!(fptr->mode & FMODE_WRITABLE)) {
+ Fail("not opened for writing");
+ }
+#ifdef HAVE_TRUNCATE
+ if (ftruncate(fileno(fptr->f), NUM2INT(len)) < 0)
+ rb_sys_fail(fptr->path);
+#else
+# ifdef HAVE_CHSIZE
+ if (chsize(fileno(fptr->f), NUM2INT(len)) < 0)
+ rb_sys_fail(fptr->path);
+# else
+ rb_notimplement();
+# endif
+#endif
+ return TRUE;
+}
+
+static VALUE
+file_flock(obj, operation)
+ VALUE obj;
+ VALUE operation;
+{
+ OpenFile *fptr;
+
+ GetOpenFile(obj, fptr);
+
+ rb_secure(2);
+ if (flock(fileno(fptr->f), NUM2INT(operation)) < 0) {
+#ifdef EWOULDBLOCK
+ if (errno == EWOULDBLOCK) {
+ return FALSE;
+ }
+#endif
+ rb_sys_fail(fptr->path);
+ }
+ return obj;
+}
+
+static void
+test_check(n, argc, argv)
+ int n, argc;
+ VALUE *argv;
+{
+ int i;
+
+ n+=1;
+ if (n < argc) ArgError("Wrong # of arguments(%d for %d)", argc, n);
+ for (i=1; i<n; i++) {
+ Check_SafeStr(argv[i]);
+ }
+}
+
+#define CHECK(n) test_check((n), argc, argv)
+
+static VALUE
+f_test(argc, argv)
+ int argc;
+ VALUE *argv;
+{
+ int cmd;
+
+ if (argc == 0) ArgError("Wrong # of arguments");
+ if (TYPE(argv[0]) == T_STRING && RSTRING(argv[0])->len == 1) {
+ cmd = RSTRING(argv[0])->ptr[0];
+ }
+ else {
+ cmd = NUM2INT(argv[0]);
+ }
+ if (cmd == 0) return FALSE;
+ if (strchr("bcdefgGkloOprRsSuwWxXz", cmd)) {
+ CHECK(1);
+ switch (cmd) {
+ case 'b':
+ return test_b(0, argv[1]);
+
+ case 'c':
+ return test_c(0, argv[1]);
+
+ case 'd':
+ return test_d(0, argv[1]);
+
+ case 'a':
+ case 'e':
+ return test_e(0, argv[1]);
+
+ case 'f':
+ return test_f(0, argv[1]);
+
+ case 'g':
+ return test_sgid(0, argv[1]);
+
+ case 'G':
+ return test_grpowned(0, argv[1]);
+
+ case 'k':
+ return test_sticky(0, argv[1]);
+
+ case 'l':
+ return test_l(0, argv[1]);
+
+ case 'o':
+ return test_owned(0, argv[1]);
+
+ case 'O':
+ return test_rowned(0, argv[1]);
+
+ case 'p':
+ return test_p(0, argv[1]);
+
+ case 'r':
+ return test_r(0, argv[1]);
+
+ case 'R':
+ return test_R(0, argv[1]);
+
+ case 's':
+ return test_s(0, argv[1]);
+
+ case 'S':
+ return test_S(0, argv[1]);
+
+ case 'u':
+ return test_suid(0, argv[1]);
+
+ case 'w':
+ return test_w(0, argv[1]);
+
+ case 'W':
+ return test_W(0, argv[1]);
+
+ case 'x':
+ return test_x(0, argv[1]);
+
+ case 'X':
+ return test_X(0, argv[1]);
+
+ case 'z':
+ return test_z(0, argv[1]);
+ }
+ }
+
+ if (strchr("MAC", cmd)) {
+ struct stat st;
+
+ CHECK(1);
+ if (stat(RSTRING(argv[1])->ptr, &st) == -1) {
+ rb_sys_fail(RSTRING(argv[1])->ptr);
+ }
+
+ switch (cmd) {
+ case 'A':
+ return time_new(st.st_atime, 0);
+ case 'M':
+ return time_new(st.st_mtime, 0);
+ case 'C':
+ return time_new(st.st_ctime, 0);
+ }
+ }
+
+ if (strchr("-=<>", cmd)) {
+ struct stat st1, st2;
+
+ CHECK(2);
+ if (stat(RSTRING(argv[1])->ptr, &st1) < 0) return FALSE;
+ if (stat(RSTRING(argv[2])->ptr, &st2) < 0) return FALSE;
+
+ switch (cmd) {
+ case '-':
+ if (st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino)
+ return TRUE;
+ break;
+
+ case '=':
+ if (st1.st_mtime == st2.st_mtime) return TRUE;
+ break;
+
+ case '>':
+ if (st1.st_mtime > st2.st_mtime) return TRUE;
+ break;
+
+ case '<':
+ if (st1.st_mtime < st2.st_mtime) return TRUE;
+ break;
+ }
+ }
+ return FALSE;
+}
+
+extern VALUE mKernel;
+
+void
+Init_File()
+{
+ mFileTest = rb_define_module("FileTest");
+
+ rb_define_module_function(mFileTest, "directory?", test_d, 1);
+ rb_define_module_function(mFileTest, "exist?", test_e, 1);
+ rb_define_module_function(mFileTest, "exists?", test_e, 1); /* temporary */
+ rb_define_module_function(mFileTest, "readable?", test_r, 1);
+ rb_define_module_function(mFileTest, "readable_real?", test_R, 1);
+ rb_define_module_function(mFileTest, "writable?", test_w, 1);
+ rb_define_module_function(mFileTest, "writable_real?", test_W, 1);
+ rb_define_module_function(mFileTest, "executable?", test_x, 1);
+ rb_define_module_function(mFileTest, "executable_real?", test_X, 1);
+ rb_define_module_function(mFileTest, "file?", test_f, 1);
+ rb_define_module_function(mFileTest, "zero?", test_z, 1);
+ rb_define_module_function(mFileTest, "size?", test_s, 1);
+ rb_define_module_function(mFileTest, "owned?", test_owned, 1);
+ rb_define_module_function(mFileTest, "grpowned?", test_grpowned, 1);
+
+ rb_define_module_function(mFileTest, "pipe?", test_p, 1);
+ rb_define_module_function(mFileTest, "symlink?", test_l, 1);
+ rb_define_module_function(mFileTest, "socket?", test_S, 1);
+
+ rb_define_module_function(mFileTest, "blockdev?", test_b, 1);
+ rb_define_module_function(mFileTest, "chardev?", test_c, 1);
+
+ rb_define_module_function(mFileTest, "setuid?", test_suid, 1);
+ rb_define_module_function(mFileTest, "setgid?", test_sgid, 1);
+ rb_define_module_function(mFileTest, "sticky?", test_sticky, 1);
+
+ cFile = rb_define_class("File", cIO);
+ rb_extend_object(cFile, CLASS_OF(mFileTest));
+
+ rb_define_singleton_method(cFile, "new", file_s_open, -1);
+ rb_define_singleton_method(cFile, "open", file_s_open, -1);
+
+ rb_define_singleton_method(cFile, "stat", file_s_stat, 1);
+ rb_define_singleton_method(cFile, "lstat", file_s_lstat, 1);
+ rb_define_singleton_method(cFile, "ftype", file_s_ftype, 1);
+
+ rb_define_singleton_method(cFile, "atime", file_s_atime, 1);
+ rb_define_singleton_method(cFile, "mtime", file_s_mtime, 1);
+ rb_define_singleton_method(cFile, "ctime", file_s_ctime, 1);
+ rb_define_singleton_method(cFile, "size", file_s_size, 1);
+
+ rb_define_singleton_method(cFile, "utime", file_s_utime, -1);
+ rb_define_singleton_method(cFile, "chmod", file_s_chmod, -1);
+ rb_define_singleton_method(cFile, "chown", file_s_chown, -1);
+
+ rb_define_singleton_method(cFile, "link", file_s_link, 2);
+ rb_define_singleton_method(cFile, "symlink", file_s_symlink, 2);
+ rb_define_singleton_method(cFile, "readlink", file_s_readlink, 1);
+
+ rb_define_singleton_method(cFile, "unlink", file_s_unlink, -2);
+ rb_define_singleton_method(cFile, "delete", file_s_unlink, -2);
+ rb_define_singleton_method(cFile, "rename", file_s_rename, 2);
+ rb_define_singleton_method(cFile, "umask", file_s_umask, -1);
+ rb_define_singleton_method(cFile, "truncate", file_s_truncate, 2);
+ rb_define_singleton_method(cFile, "expand_path", file_s_expand_path, 1);
+ rb_define_singleton_method(cFile, "basename", file_s_basename, -1);
+ rb_define_singleton_method(cFile, "dirname", file_s_dirname, 1);
+
+ separator = str_new2("/");
+ rb_define_const(cFile, "Separator", separator);
+ rb_define_singleton_method(cFile, "split", file_s_split, 1);
+ rb_define_singleton_method(cFile, "join", file_s_join, -2);
+
+ rb_define_method(cFile, "reopen", file_reopen, -1);
+
+ rb_define_method(cFile, "stat", file_stat, 0);
+ rb_define_method(cFile, "lstat", file_lstat, 0);
+
+ rb_define_method(cFile, "atime", file_atime, 0);
+ rb_define_method(cFile, "mtime", file_mtime, 0);
+ rb_define_method(cFile, "ctime", file_ctime, 0);
+
+ rb_define_method(cFile, "chmod", file_chmod, 1);
+ rb_define_method(cFile, "chown", file_chown, 2);
+ rb_define_method(cFile, "truncate", file_truncate, 1);
+
+ rb_define_method(cFile, "tell", file_tell, 0);
+ rb_define_method(cFile, "seek", file_seek, 2);
+
+ rb_define_method(cFile, "pos", file_tell, 0);
+ rb_define_method(cFile, "pos=", file_set_pos, 1);
+
+ rb_define_method(cFile, "rewind", file_rewind, 0);
+ rb_define_method(cFile, "isatty", file_isatty, 0);
+ rb_define_method(cFile, "tty?", file_isatty, 0);
+ rb_define_method(cFile, "eof", file_eof, 0);
+ rb_define_method(cFile, "eof?", file_eof, 0);
+
+ rb_define_method(cFile, "flock", file_flock, 1);
+
+# ifndef LOCK_SH
+# define LOCK_SH 1
+# endif
+# ifndef LOCK_EX
+# define LOCK_EX 2
+# endif
+# ifndef LOCK_NB
+# define LOCK_NB 4
+# endif
+# ifndef LOCK_UN
+# define LOCK_UN 8
+# endif
+
+ rb_define_const(cFile, "LOCK_SH", INT2FIX(LOCK_SH));
+ rb_define_const(cFile, "LOCK_EX", INT2FIX(LOCK_EX));
+ rb_define_const(cFile, "LOCK_UN", INT2FIX(LOCK_UN));
+ rb_define_const(cFile, "LOCK_NB", INT2FIX(LOCK_NB));
+
+ rb_define_method(cFile, "path", file_path, 0);
+
+ rb_define_global_function("test", f_test, -1);
+
+ sStat = struct_define("Stat", "dev", "ino", "mode",
+ "nlink", "uid", "gid", "rdev",
+ "size", "blksize", "blocks",
+ "atime", "mtime", "ctime", 0);
+}