Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions mrbgem.rake
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ MRuby::Gem::Specification.new('mruby-file-stat') do |spec|
spec.license = 'MIT'
spec.author = 'ksss <[email protected]>'
spec.add_dependency('mruby-time')
spec.add_test_dependency('mruby-io')

env = {
'CC' => "#{build.cc.command} #{build.cc.flags.join(' ')}",
Expand Down
67 changes: 38 additions & 29 deletions src/file-stat.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,11 +101,20 @@
# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
#endif

#define STAT(p,s) stat(p,s)
#ifdef HAVE_LSTAT
# define LSTAT(p,s) lstat(p,s)
#if defined(_WIN32) || defined(_WIN64)
# define STAT(p,s) _stat64(p,s)
# define FSTAT(fd,s) _fstat64(fd,s)
# define LSTAT(p,s) _stat64(p,s)
# define STAT_STRUCT struct _stat64
#else
# define LSTAT(p,s) stat(p,s)
# define STAT(p,s) stat(p,s)
# define FSTAT(fd,s) fstat(fd,s)
# ifdef HAVE_LSTAT
# define LSTAT(p,s) lstat(p,s)
# else
# define LSTAT(p,s) stat(p,s)
# endif
# define STAT_STRUCT struct stat
#endif
#define MRB_MAX_GROUPS (65536)

Expand Down Expand Up @@ -145,18 +154,18 @@ getegid(void)

struct mrb_data_type mrb_stat_type = { "File::Stat", mrb_free };

static struct stat *
static STAT_STRUCT *
mrb_stat_alloc(mrb_state *mrb)
{
return (struct stat *)mrb_malloc(mrb, sizeof(struct stat));
return (STAT_STRUCT *)mrb_malloc(mrb, sizeof(STAT_STRUCT));
}

static mrb_value
file_s_lstat(mrb_state *mrb, mrb_value klass)
{
struct RClass *file_class;
struct RClass *stat_class;
struct stat st, *ptr;
STAT_STRUCT st, *ptr;
mrb_value fname, tmp;
char *path;

Expand Down Expand Up @@ -190,7 +199,7 @@ file_s_lstat(mrb_state *mrb, mrb_value klass)
static mrb_value
stat_initialize(mrb_state *mrb, mrb_value self)
{
struct stat st, *ptr;
STAT_STRUCT st, *ptr;
mrb_value fname, tmp;
char *path;

Expand All @@ -213,7 +222,7 @@ stat_initialize(mrb_state *mrb, mrb_value self)
}
}

ptr = (struct stat *)DATA_PTR(self);
ptr = (STAT_STRUCT *)DATA_PTR(self);
if (ptr) {
mrb_free(mrb, ptr);
}
Expand Down Expand Up @@ -246,19 +255,19 @@ stat_initialize_copy(mrb_state *mrb, mrb_value copy)
}

if (DATA_PTR(orig)) {
DATA_PTR(copy) = mrb_malloc(mrb, sizeof(struct stat));
DATA_PTR(copy) = mrb_malloc(mrb, sizeof(STAT_STRUCT));
DATA_TYPE(copy) = &mrb_stat_type;
*(struct stat *)DATA_PTR(copy) = *(struct stat *)DATA_PTR(orig);
*(STAT_STRUCT *)DATA_PTR(copy) = *(STAT_STRUCT *)DATA_PTR(orig);
}
return copy;
}

static struct stat *
static STAT_STRUCT *
get_stat(mrb_state *mrb, mrb_value self)
{
struct stat *st;
STAT_STRUCT *st;

st = (struct stat *)mrb_data_get_ptr(mrb, self, &mrb_stat_type);
st = (STAT_STRUCT *)mrb_data_get_ptr(mrb, self, &mrb_stat_type);
if (!st) mrb_raise(mrb, E_TYPE_ERROR, "uninitialized File::Stat");
return st;
}
Expand All @@ -283,7 +292,7 @@ io_stat(mrb_state *mrb, mrb_value self)
{
struct RClass *file_class;
struct RClass *stat_class;
struct stat st, *ptr;
STAT_STRUCT st, *ptr;
mrb_value fileno;

if (mrb_respond_to(mrb, self, mrb_intern_lit(mrb, "fileno"))) {
Expand All @@ -293,7 +302,7 @@ io_stat(mrb_state *mrb, mrb_value self)
mrb_raise(mrb, E_NOTIMP_ERROR, "`fileno' is not implemented");
}

if (fstat(mrb_fixnum(fileno), &st) == -1) {
if (FSTAT(mrb_fixnum(fileno), &st) == -1) {
mrb_sys_fail(mrb, "fstat");
}

Expand Down Expand Up @@ -394,7 +403,7 @@ time_at_with_sec_nsec(mrb_state *mrb, time_t sec, long nsec)
}

static struct timespec
stat_atimespec(const struct stat *st)
stat_atimespec(const STAT_STRUCT *st)
{
struct timespec ts;
ts.tv_sec = st->st_atime;
Expand All @@ -418,7 +427,7 @@ stat_atime(mrb_state *mrb, mrb_value self)
}

static struct timespec
stat_mtimespec(const struct stat *st)
stat_mtimespec(const STAT_STRUCT *st)
{
struct timespec ts;
ts.tv_sec = st->st_mtime;
Expand All @@ -442,7 +451,7 @@ stat_mtime(mrb_state *mrb, mrb_value self)
}

static struct timespec
stat_ctimespec(const struct stat *st)
stat_ctimespec(const STAT_STRUCT *st)
{
struct timespec ts;
ts.tv_sec = st->st_ctime;
Expand All @@ -469,7 +478,7 @@ stat_ctime(mrb_state *mrb, mrb_value self)
static mrb_value
stat_birthtime(mrb_state *mrb, mrb_value self)
{
struct stat *st = get_stat(mrb, self);
STAT_STRUCT *st = get_stat(mrb, self);
const struct timespec *ts = &st->st_birthtimespec;
return time_at_with_sec_nsec(mrb, ts->tv_sec, ts->tv_nsec);
}
Expand Down Expand Up @@ -564,7 +573,7 @@ stat_grpowned_p(mrb_state *mrb, mrb_value self)
static mrb_value
stat_readable_p(mrb_state *mrb, mrb_value self)
{
struct stat *st;
STAT_STRUCT *st;
#ifdef USE_GETEUID
if (geteuid() == 0)
return mrb_true_value();
Expand All @@ -588,7 +597,7 @@ stat_readable_p(mrb_state *mrb, mrb_value self)
static mrb_value
stat_readable_real_p(mrb_state *mrb, mrb_value self)
{
struct stat *st;
STAT_STRUCT *st;

#ifdef USE_GETEUID
if (getuid() == 0)
Expand All @@ -613,7 +622,7 @@ static mrb_value
stat_world_readable_p(mrb_state *mrb, mrb_value self)
{
#ifdef S_IROTH
struct stat *st = get_stat(mrb, self);
STAT_STRUCT *st = get_stat(mrb, self);
if ((st->st_mode & (S_IROTH)) == S_IROTH) {
return mrb_fixnum_value(st->st_mode & (S_IRUGO|S_IWUGO|S_IXUGO));
}
Expand All @@ -629,7 +638,7 @@ stat_world_readable_p(mrb_state *mrb, mrb_value self)
static mrb_value
stat_writable_p(mrb_state *mrb, mrb_value self)
{
struct stat *st;
STAT_STRUCT *st;

#ifdef USE_GETEUID
if (geteuid() == 0)
Expand All @@ -654,7 +663,7 @@ stat_writable_p(mrb_state *mrb, mrb_value self)
static mrb_value
stat_writable_real_p(mrb_state *mrb, mrb_value self)
{
struct stat *st;
STAT_STRUCT *st;

#ifdef USE_GETEUID
if (getuid() == 0)
Expand All @@ -679,7 +688,7 @@ static mrb_value
stat_world_writable_p(mrb_state *mrb, mrb_value self)
{
#ifdef S_IWOTH
struct stat *st = get_stat(mrb, self);
STAT_STRUCT *st = get_stat(mrb, self);
if ((st->st_mode & (S_IWOTH)) == S_IWOTH) {
return mrb_fixnum_value(st->st_mode & (S_IRUGO|S_IWUGO|S_IXUGO));
}
Expand All @@ -694,7 +703,7 @@ stat_world_writable_p(mrb_state *mrb, mrb_value self)
static mrb_value
stat_executable_p(mrb_state *mrb, mrb_value self)
{
struct stat *st = get_stat(mrb, self);
STAT_STRUCT *st = get_stat(mrb, self);

#ifdef USE_GETEUID
if (geteuid() == 0) {
Expand All @@ -719,7 +728,7 @@ stat_executable_p(mrb_state *mrb, mrb_value self)
static mrb_value
stat_executable_real_p(mrb_state *mrb, mrb_value self)
{
struct stat *st = get_stat(mrb, self);
STAT_STRUCT *st = get_stat(mrb, self);

#ifdef USE_GETEUID
if (getuid() == 0)
Expand Down Expand Up @@ -836,7 +845,7 @@ stat_sticky_p(mrb_state *mrb, mrb_value self)
static mrb_value
stat_ftype(mrb_state *mrb, mrb_value self)
{
struct stat *st = get_stat(mrb, self);
STAT_STRUCT *st = get_stat(mrb, self);
const char *t;

if (S_ISREG(st->st_mode)) {
Expand Down
14 changes: 14 additions & 0 deletions test/file-stat.rb
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,20 @@ def chmod(mode, path)
assert_true 0 < stat.size?
end

assert 'File::Stat#size with large file (2GB)' do
large_file = "test_large_file.tmp"
target_size = 2**31 # 2GB
begin
File.open(large_file, 'wb') do |f|
(2**19).times { f << "\0" * 4096 }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use target_size here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fix: e15ed5b Sure, I tried to use it with seek.

end
stat = File::Stat.new(large_file)
assert_equal target_size, stat.size
ensure
File.delete(large_file) if File.exist?(large_file)
end
end

assert 'File::Stat#owned?' do
stat = File::Stat.new('README.md')
assert_true stat.owned?
Expand Down
Loading