From d1c48192cbff3cdc9168854c115d2d421068fb01 Mon Sep 17 00:00:00 2001 From: Kohei Suzuki Date: Sat, 17 Dec 2016 15:00:04 +0900 Subject: Add File.readlink --- README.md | 2 +- src/file.c | 31 +++++++++++++++++++++++++++++++ test/file.rb | 16 ++++++++++++++++ 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 604361f25..e007393a9 100644 --- a/README.md +++ b/README.md @@ -134,7 +134,7 @@ Add the line below to your `build_config.rb`: | File.pipe? | o | FileTest | | File.readable? | | FileTest | | File.readable_real? | | FileTest | -| File.readlink | | | +| File.readlink | o | | | File.realdirpath | | | | File.realpath | o | | | File.rename | o | | diff --git a/src/file.c b/src/file.c index 2131db654..a1c965638 100644 --- a/src/file.c +++ b/src/file.c @@ -353,6 +353,36 @@ mrb_file_s_chmod(mrb_state *mrb, mrb_value klass) { 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 = mrb_malloc(mrb, bufsize); + while ((rc = readlink(path, buf, bufsize)) == bufsize && rc != -1) { + bufsize *= 2; + buf = mrb_realloc(mrb, buf, bufsize); + } + if (rc == -1) { + 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) { @@ -367,6 +397,7 @@ mrb_init_file(mrb_state *mrb) 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)); diff --git a/test/file.rb b/test/file.rb index f5607bbaa..58c16bbfe 100644 --- a/test/file.rb +++ b/test/file.rb @@ -91,6 +91,22 @@ assert('File.realpath') do end end +assert("File.readlink") do + begin + assert_equal 'hoge', File.readlink($mrbtest_io_symlinkname) + rescue NotImplementedError => e + skip e.message + end +end + +assert("File.readlink fails with non-symlink") do + begin + assert_raise(RuntimeError) { File.readlink($mrbtest_io_rfname) } + rescue NotImplementedError => e + skip e.message + end +end + assert('File TEST CLEANUP') do assert_nil MRubyIOTestUtil.io_test_cleanup end -- cgit v1.2.3