summaryrefslogtreecommitdiffhomepage
path: root/mrbgems/mruby-io/src/file.c
diff options
context:
space:
mode:
authorYukihiro "Matz" Matsumoto <[email protected]>2017-12-07 18:11:06 +0900
committerYukihiro "Matz" Matsumoto <[email protected]>2017-12-07 18:11:06 +0900
commitd75266dd1bade53255044460a9cd74596addaa84 (patch)
treeac97feb393da5597855dd8f79a7b8feba17c5c14 /mrbgems/mruby-io/src/file.c
parent10ed730e4bd921cf4d8fe6f6d2e3cb3f0840f3b7 (diff)
parent3c8e1f94c44252c836f79a48bb17726da28e2756 (diff)
downloadmruby-d75266dd1bade53255044460a9cd74596addaa84.tar.gz
mruby-d75266dd1bade53255044460a9cd74596addaa84.zip
Add 'mrbgems/mruby-io/' from commit '3c8e1f94c44252c836f79a48bb17726da28e2756'
git-subtree-dir: mrbgems/mruby-io git-subtree-mainline: 10ed730e4bd921cf4d8fe6f6d2e3cb3f0840f3b7 git-subtree-split: 3c8e1f94c44252c836f79a48bb17726da28e2756
Diffstat (limited to 'mrbgems/mruby-io/src/file.c')
-rw-r--r--mrbgems/mruby-io/src/file.c427
1 files changed, 427 insertions, 0 deletions
diff --git a/mrbgems/mruby-io/src/file.c b/mrbgems/mruby-io/src/file.c
new file mode 100644
index 000000000..0f7674d77
--- /dev/null
+++ b/mrbgems/mruby-io/src/file.c
@@ -0,0 +1,427 @@
+/*
+** file.c - File class
+*/
+
+#include "mruby.h"
+#include "mruby/class.h"
+#include "mruby/data.h"
+#include "mruby/string.h"
+#include "mruby/ext/io.h"
+
+#if MRUBY_RELEASE_NO < 10000
+#include "error.h"
+#else
+#include "mruby/error.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <fcntl.h>
+#include <limits.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#if defined(_WIN32) || defined(_WIN64)
+ #define NULL_FILE "NUL"
+ #define UNLINK _unlink
+ #define GETCWD _getcwd
+ #define CHMOD(a, b) 0
+ #define MAXPATHLEN 1024
+ #if !defined(PATH_MAX)
+ #define PATH_MAX _MAX_PATH
+ #endif
+ #define realpath(N,R) _fullpath((R),(N),_MAX_PATH)
+ #include <direct.h>
+#else
+ #define NULL_FILE "/dev/null"
+ #include <unistd.h>
+ #define UNLINK unlink
+ #define GETCWD getcwd
+ #define CHMOD(a, b) chmod(a,b)
+ #include <sys/file.h>
+ #include <libgen.h>
+ #include <sys/param.h>
+ #include <pwd.h>
+#endif
+
+#define FILE_SEPARATOR "/"
+
+#if defined(_WIN32) || defined(_WIN64)
+ #define PATH_SEPARATOR ";"
+ #define FILE_ALT_SEPARATOR "\\"
+#else
+ #define PATH_SEPARATOR ":"
+#endif
+
+#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
+
+#define STAT(p, s) stat(p, s)
+
+
+mrb_value
+mrb_file_s_umask(mrb_state *mrb, mrb_value klass)
+{
+#if defined(_WIN32) || defined(_WIN64)
+ /* nothing to do on windows */
+ return mrb_fixnum_value(0);
+
+#else
+ mrb_int mask, omask;
+ if (mrb_get_args(mrb, "|i", &mask) == 0) {
+ omask = umask(0);
+ umask(omask);
+ } else {
+ omask = umask(mask);
+ }
+ return mrb_fixnum_value(omask);
+#endif
+}
+
+static mrb_value
+mrb_file_s_unlink(mrb_state *mrb, mrb_value obj)
+{
+ mrb_value *argv;
+ mrb_value pathv;
+ mrb_int argc, i;
+ const char *path;
+
+ mrb_get_args(mrb, "*", &argv, &argc);
+ for (i = 0; i < argc; i++) {
+ pathv = mrb_convert_type(mrb, argv[i], MRB_TT_STRING, "String", "to_str");
+ path = mrb_string_value_cstr(mrb, &pathv);
+ if (UNLINK(path) < 0) {
+ mrb_sys_fail(mrb, path);
+ }
+ }
+ return mrb_fixnum_value(argc);
+}
+
+static mrb_value
+mrb_file_s_rename(mrb_state *mrb, mrb_value obj)
+{
+ mrb_value from, to;
+ const char *src, *dst;
+
+ mrb_get_args(mrb, "SS", &from, &to);
+ src = mrb_string_value_cstr(mrb, &from);
+ dst = mrb_string_value_cstr(mrb, &to);
+ if (rename(src, dst) < 0) {
+#if defined(_WIN32) || defined(_WIN64)
+ if (CHMOD(dst, 0666) == 0 && UNLINK(dst) == 0 && rename(src, dst) == 0) {
+ return mrb_fixnum_value(0);
+ }
+#endif
+ mrb_sys_fail(mrb, mrb_str_to_cstr(mrb, mrb_format(mrb, "(%S, %S)", from, to)));
+ }
+ return mrb_fixnum_value(0);
+}
+
+static mrb_value
+mrb_file_dirname(mrb_state *mrb, mrb_value klass)
+{
+#if defined(_WIN32) || defined(_WIN64)
+ char dname[_MAX_DIR], vname[_MAX_DRIVE];
+ char buffer[_MAX_DRIVE + _MAX_DIR];
+ char *path;
+ size_t ridx;
+ mrb_value s;
+ mrb_get_args(mrb, "S", &s);
+ path = mrb_str_to_cstr(mrb, s);
+ _splitpath((const char*)path, vname, dname, NULL, NULL);
+ snprintf(buffer, _MAX_DRIVE + _MAX_DIR, "%s%s", vname, dname);
+ ridx = strlen(buffer);
+ if (ridx == 0) {
+ strncpy(buffer, ".", 2); /* null terminated */
+ } else if (ridx > 1) {
+ ridx--;
+ while (ridx > 0 && (buffer[ridx] == '/' || buffer[ridx] == '\\')) {
+ buffer[ridx] = '\0'; /* remove last char */
+ ridx--;
+ }
+ }
+ return mrb_str_new_cstr(mrb, buffer);
+#else
+ char *dname, *path;
+ mrb_value s;
+ mrb_get_args(mrb, "S", &s);
+ path = mrb_str_to_cstr(mrb, s);
+
+ if ((dname = dirname(path)) == NULL) {
+ mrb_sys_fail(mrb, "dirname");
+ }
+#endif
+ return mrb_str_new_cstr(mrb, dname);
+}
+
+static mrb_value
+mrb_file_basename(mrb_state *mrb, mrb_value klass)
+{
+#if defined(_WIN32) || defined(_WIN64)
+ char bname[_MAX_DIR];
+ char extname[_MAX_EXT];
+ char *path;
+ size_t ridx;
+ char buffer[_MAX_DIR + _MAX_EXT];
+ mrb_value s;
+ mrb_get_args(mrb, "S", &s);
+ path = mrb_str_to_cstr(mrb, s);
+ ridx = strlen(path);
+ if (ridx > 0) {
+ ridx--;
+ while (ridx > 0 && (path[ridx] == '/' || path[ridx] == '\\')) {
+ path[ridx] = '\0';
+ ridx--;
+ }
+ if (strncmp(path, "/", 2) == 0) {
+ return mrb_str_new_cstr(mrb, path);
+ }
+ }
+ _splitpath((const char*)path, NULL, NULL, bname, extname);
+ snprintf(buffer, _MAX_DIR + _MAX_EXT, "%s%s", bname, extname);
+ return mrb_str_new_cstr(mrb, buffer);
+#else
+ char *bname, *path;
+ mrb_value s;
+ mrb_get_args(mrb, "S", &s);
+ path = mrb_str_to_cstr(mrb, s);
+ if ((bname = basename(path)) == NULL) {
+ mrb_sys_fail(mrb, "basename");
+ }
+ return mrb_str_new_cstr(mrb, bname);
+#endif
+}
+
+static mrb_value
+mrb_file_realpath(mrb_state *mrb, mrb_value klass)
+{
+ mrb_value pathname, dir_string, s, result;
+ int argc;
+ char *cpath;
+
+ argc = mrb_get_args(mrb, "S|S", &pathname, &dir_string);
+ if (argc == 2) {
+ s = mrb_str_dup(mrb, dir_string);
+ s = mrb_str_append(mrb, s, mrb_str_new_cstr(mrb, FILE_SEPARATOR));
+ s = mrb_str_append(mrb, s, pathname);
+ pathname = s;
+ }
+ cpath = mrb_str_to_cstr(mrb, pathname);
+ result = mrb_str_buf_new(mrb, PATH_MAX);
+ if (realpath(cpath, RSTRING_PTR(result)) == NULL)
+ mrb_sys_fail(mrb, cpath);
+ mrb_str_resize(mrb, result, strlen(RSTRING_PTR(result)));
+ return result;
+}
+
+mrb_value
+mrb_file__getwd(mrb_state *mrb, mrb_value klass)
+{
+ mrb_value path;
+
+ path = mrb_str_buf_new(mrb, MAXPATHLEN);
+ if (GETCWD(RSTRING_PTR(path), MAXPATHLEN) == NULL) {
+ mrb_sys_fail(mrb, "getcwd(2)");
+ }
+ mrb_str_resize(mrb, path, strlen(RSTRING_PTR(path)));
+ return path;
+}
+
+static int
+mrb_file_is_absolute_path(const char *path)
+{
+ return (path[0] == '/');
+}
+
+static mrb_value
+mrb_file__gethome(mrb_state *mrb, mrb_value klass)
+{
+#ifndef _WIN32
+ mrb_value username;
+ int argc;
+ char *home;
+
+ argc = mrb_get_args(mrb, "|S", &username);
+ if (argc == 0) {
+ home = getenv("HOME");
+ if (home == NULL) {
+ return mrb_nil_value();
+ }
+ if (!mrb_file_is_absolute_path(home)) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "non-absolute home");
+ }
+ } else {
+ const char *cuser = mrb_str_to_cstr(mrb, username);
+ struct passwd *pwd = getpwnam(cuser);
+ if (pwd == NULL) {
+ return mrb_nil_value();
+ }
+ home = pwd->pw_dir;
+ if (!mrb_file_is_absolute_path(home)) {
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "non-absolute home of ~%S", username);
+ }
+ }
+ return mrb_str_new_cstr(mrb, home);
+#else
+
+ return mrb_nil_value();
+#endif
+}
+
+mrb_value
+mrb_file_flock(mrb_state *mrb, mrb_value self)
+{
+#if defined(_WIN32) || defined(_WIN64) || defined(sun)
+ mrb_raise(mrb, E_NOTIMP_ERROR, "flock is not supported on Illumos/Solaris/Windows");
+#else
+ mrb_int operation;
+ int fd;
+
+ mrb_get_args(mrb, "i", &operation);
+ fd = mrb_fixnum(mrb_io_fileno(mrb, self));
+
+ while (flock(fd, operation) == -1) {
+ switch (errno) {
+ case EINTR:
+ /* retry */
+ break;
+ case EAGAIN: /* NetBSD */
+#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
+ case EWOULDBLOCK: /* FreeBSD OpenBSD Linux */
+#endif
+ if (operation & LOCK_NB) {
+ return mrb_false_value();
+ }
+ /* FALLTHRU - should not happen */
+ default:
+ mrb_sys_fail(mrb, "flock failed");
+ break;
+ }
+ }
+#endif
+ return mrb_fixnum_value(0);
+}
+
+static mrb_value
+mrb_file_s_symlink(mrb_state *mrb, mrb_value klass)
+{
+#if defined(_WIN32) || defined(_WIN64)
+ mrb_raise(mrb, E_NOTIMP_ERROR, "symlink is not supported on this platform");
+#else
+ mrb_value from, to;
+ const char *src, *dst;
+ int ai = mrb_gc_arena_save(mrb);
+
+ mrb_get_args(mrb, "SS", &from, &to);
+ src = mrb_str_to_cstr(mrb, from);
+ dst = mrb_str_to_cstr(mrb, to);
+
+ if (symlink(src, dst) == -1) {
+ mrb_sys_fail(mrb, mrb_str_to_cstr(mrb, mrb_format(mrb, "(%S, %S)", from, to)));
+ }
+ mrb_gc_arena_restore(mrb, ai);
+#endif
+ return mrb_fixnum_value(0);
+}
+
+static mrb_value
+mrb_file_s_chmod(mrb_state *mrb, mrb_value klass) {
+ mrb_int mode;
+ mrb_int argc, i;
+ mrb_value *filenames;
+ int ai = mrb_gc_arena_save(mrb);
+
+ mrb_get_args(mrb, "i*", &mode, &filenames, &argc);
+ for (i = 0; i < argc; i++) {
+ char *path = mrb_str_to_cstr(mrb, filenames[i]);
+ if (CHMOD(path, mode) == -1) {
+ mrb_sys_fail(mrb, path);
+ }
+ }
+
+ mrb_gc_arena_restore(mrb, ai);
+ return mrb_fixnum_value(argc);
+}
+
+static mrb_value
+mrb_file_s_readlink(mrb_state *mrb, mrb_value klass) {
+#if defined(_WIN32) || defined(_WIN64)
+ mrb_raise(mrb, E_NOTIMP_ERROR, "readlink is not supported on this platform");
+ return mrb_nil_value(); // unreachable
+#else
+ char *path, *buf;
+ size_t bufsize = 100;
+ ssize_t rc;
+ mrb_value ret;
+ int ai = mrb_gc_arena_save(mrb);
+
+ mrb_get_args(mrb, "z", &path);
+
+ buf = (char *)mrb_malloc(mrb, bufsize);
+ while ((rc = readlink(path, buf, bufsize)) == bufsize && rc != -1) {
+ bufsize *= 2;
+ buf = (char *)mrb_realloc(mrb, buf, bufsize);
+ }
+ if (rc == -1) {
+ mrb_free(mrb, buf);
+ mrb_sys_fail(mrb, path);
+ }
+ ret = mrb_str_new(mrb, buf, rc);
+ mrb_free(mrb, buf);
+
+ mrb_gc_arena_restore(mrb, ai);
+ return ret;
+#endif
+}
+
+void
+mrb_init_file(mrb_state *mrb)
+{
+ struct RClass *io, *file, *cnst;
+
+ io = mrb_class_get(mrb, "IO");
+ file = mrb_define_class(mrb, "File", io);
+ MRB_SET_INSTANCE_TT(file, MRB_TT_DATA);
+ mrb_define_class_method(mrb, file, "umask", mrb_file_s_umask, MRB_ARGS_REQ(1));
+ mrb_define_class_method(mrb, file, "delete", mrb_file_s_unlink, MRB_ARGS_ANY());
+ mrb_define_class_method(mrb, file, "unlink", mrb_file_s_unlink, MRB_ARGS_ANY());
+ mrb_define_class_method(mrb, file, "rename", mrb_file_s_rename, MRB_ARGS_REQ(2));
+ mrb_define_class_method(mrb, file, "symlink", mrb_file_s_symlink, MRB_ARGS_REQ(2));
+ mrb_define_class_method(mrb, file, "chmod", mrb_file_s_chmod, MRB_ARGS_REQ(1) | MRB_ARGS_REST());
+ mrb_define_class_method(mrb, file, "readlink", mrb_file_s_readlink, MRB_ARGS_REQ(1));
+
+ mrb_define_class_method(mrb, file, "dirname", mrb_file_dirname, MRB_ARGS_REQ(1));
+ mrb_define_class_method(mrb, file, "basename", mrb_file_basename, MRB_ARGS_REQ(1));
+ mrb_define_class_method(mrb, file, "realpath", mrb_file_realpath, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1));
+ mrb_define_class_method(mrb, file, "_getwd", mrb_file__getwd, MRB_ARGS_NONE());
+ mrb_define_class_method(mrb, file, "_gethome", mrb_file__gethome, MRB_ARGS_OPT(1));
+
+ mrb_define_method(mrb, file, "flock", mrb_file_flock, MRB_ARGS_REQ(1));
+
+ cnst = mrb_define_module_under(mrb, file, "Constants");
+ mrb_define_const(mrb, cnst, "LOCK_SH", mrb_fixnum_value(LOCK_SH));
+ mrb_define_const(mrb, cnst, "LOCK_EX", mrb_fixnum_value(LOCK_EX));
+ mrb_define_const(mrb, cnst, "LOCK_UN", mrb_fixnum_value(LOCK_UN));
+ mrb_define_const(mrb, cnst, "LOCK_NB", mrb_fixnum_value(LOCK_NB));
+ mrb_define_const(mrb, cnst, "SEPARATOR", mrb_str_new_cstr(mrb, FILE_SEPARATOR));
+ mrb_define_const(mrb, cnst, "PATH_SEPARATOR", mrb_str_new_cstr(mrb, PATH_SEPARATOR));
+#if defined(_WIN32) || defined(_WIN64)
+ mrb_define_const(mrb, cnst, "ALT_SEPARATOR", mrb_str_new_cstr(mrb, FILE_ALT_SEPARATOR));
+#else
+ mrb_define_const(mrb, cnst, "ALT_SEPARATOR", mrb_nil_value());
+#endif
+ mrb_define_const(mrb, cnst, "NULL", mrb_str_new_cstr(mrb, NULL_FILE));
+
+}