diff options
| author | Yukihiro "Matz" Matsumoto <[email protected]> | 2017-12-07 18:11:06 +0900 |
|---|---|---|
| committer | Yukihiro "Matz" Matsumoto <[email protected]> | 2017-12-07 18:11:06 +0900 |
| commit | d75266dd1bade53255044460a9cd74596addaa84 (patch) | |
| tree | ac97feb393da5597855dd8f79a7b8feba17c5c14 /mrbgems/mruby-io/src/file.c | |
| parent | 10ed730e4bd921cf4d8fe6f6d2e3cb3f0840f3b7 (diff) | |
| parent | 3c8e1f94c44252c836f79a48bb17726da28e2756 (diff) | |
| download | mruby-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.c | 427 |
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)); + +} |
