|
70 | 70 | #define LOCK_UN 8 |
71 | 71 | #endif |
72 | 72 |
|
73 | | -#define STAT(p, s) stat(p, s) |
| 73 | +#ifndef _WIN32 |
| 74 | +typedef struct stat mrb_stat; |
| 75 | +# define mrb_stat(path, sb) stat(path, sb) |
| 76 | +# define mrb_fstat(fd, sb) fstat(fd, sb) |
| 77 | +#else |
| 78 | +typedef struct __stat64 mrb_stat; |
| 79 | +# define mrb_stat(path, sb) _stat64(path, sb) |
| 80 | +# define mrb_fstat(fd, sb) _fstat64(fd, sb) |
| 81 | +#endif |
74 | 82 |
|
75 | 83 | #ifdef _WIN32 |
76 | 84 | static int |
@@ -384,6 +392,95 @@ mrb_file_flock(mrb_state *mrb, mrb_value self) |
384 | 392 | return mrb_fixnum_value(0); |
385 | 393 | } |
386 | 394 |
|
| 395 | +static mrb_value |
| 396 | +mrb_file_size(mrb_state *mrb, mrb_value self) |
| 397 | +{ |
| 398 | + mrb_stat st; |
| 399 | + int fd; |
| 400 | + |
| 401 | + fd = (int)mrb_fixnum(mrb_io_fileno(mrb, self)); |
| 402 | + if (mrb_fstat(fd, &st) == -1) { |
| 403 | + mrb_raise(mrb, E_RUNTIME_ERROR, "fstat failed"); |
| 404 | + } |
| 405 | + |
| 406 | + if (st.st_size > MRB_INT_MAX) { |
| 407 | +#ifdef MRB_WITHOUT_FLOAT |
| 408 | + mrb_raise(mrb, E_RUNTIME_ERROR, "File#size too large for MRB_WITHOUT_FLOAT"); |
| 409 | +#else |
| 410 | + return mrb_float_value(mrb, st.st_size); |
| 411 | +#endif |
| 412 | + } |
| 413 | + |
| 414 | + return mrb_fixnum_value(st.st_size); |
| 415 | +} |
| 416 | + |
| 417 | +static int |
| 418 | +mrb_ftruncate(int fd, int64_t length) |
| 419 | +{ |
| 420 | +#ifndef _WIN32 |
| 421 | + return ftruncate(fd, (off_t)length); |
| 422 | +#else |
| 423 | + HANDLE file; |
| 424 | + __int64 cur; |
| 425 | + |
| 426 | + file = (HANDLE)_get_osfhandle(fd); |
| 427 | + if (file == INVALID_HANDLE_VALUE) { |
| 428 | + return -1; |
| 429 | + } |
| 430 | + |
| 431 | + cur = _lseeki64(fd, 0, SEEK_CUR); |
| 432 | + if (cur == -1) return -1; |
| 433 | + |
| 434 | + if (_lseeki64(fd, (__int64)length, SEEK_SET) == -1) return -1; |
| 435 | + |
| 436 | + if (!SetEndOfFile(file)) { |
| 437 | + errno = EINVAL; /* TODO: GetLastError to errno */ |
| 438 | + return -1; |
| 439 | + } |
| 440 | + |
| 441 | + if (_lseeki64(fd, cur, SEEK_SET) == -1) return -1; |
| 442 | + |
| 443 | + return 0; |
| 444 | +#endif /* _WIN32 */ |
| 445 | +} |
| 446 | + |
| 447 | +static mrb_value |
| 448 | +mrb_file_truncate(mrb_state *mrb, mrb_value self) |
| 449 | +{ |
| 450 | + int fd; |
| 451 | + int64_t length; |
| 452 | + mrb_value lenv; |
| 453 | + |
| 454 | + fd = (int)mrb_fixnum(mrb_io_fileno(mrb, self)); |
| 455 | + mrb_get_args(mrb, "o", &lenv); |
| 456 | + switch (mrb_type(lenv)) { |
| 457 | +#ifndef MRB_WITHOUT_FLOAT |
| 458 | + case MRB_TT_FLOAT: |
| 459 | + { |
| 460 | + mrb_float lenf = mrb_float(lenv); |
| 461 | + if (lenf > INT64_MAX) { |
| 462 | + mrb_raise(mrb, E_ARGUMENT_ERROR, "length too large"); |
| 463 | + } |
| 464 | + length = (int64_t)lenf; |
| 465 | + } |
| 466 | + break; |
| 467 | +#endif |
| 468 | + case MRB_TT_FIXNUM: |
| 469 | + default: |
| 470 | + { |
| 471 | + mrb_int leni = mrb_int(mrb, lenv); |
| 472 | + length = (int64_t)leni; |
| 473 | + } |
| 474 | + break; |
| 475 | + } |
| 476 | + |
| 477 | + if (mrb_ftruncate(fd, length) != 0) { |
| 478 | + mrb_raise(mrb, E_IO_ERROR, "ftruncate failed"); |
| 479 | + } |
| 480 | + |
| 481 | + return mrb_fixnum_value(0); |
| 482 | +} |
| 483 | + |
387 | 484 | static mrb_value |
388 | 485 | mrb_file_s_symlink(mrb_state *mrb, mrb_value klass) |
389 | 486 | { |
@@ -490,6 +587,8 @@ mrb_init_file(mrb_state *mrb) |
490 | 587 |
|
491 | 588 | mrb_define_method(mrb, file, "flock", mrb_file_flock, MRB_ARGS_REQ(1)); |
492 | 589 | mrb_define_method(mrb, file, "mtime", mrb_file_mtime, MRB_ARGS_NONE()); |
| 590 | + mrb_define_method(mrb, file, "size", mrb_file_size, MRB_ARGS_NONE()); |
| 591 | + mrb_define_method(mrb, file, "truncate", mrb_file_truncate, MRB_ARGS_REQ(1)); |
493 | 592 |
|
494 | 593 | cnst = mrb_define_module_under(mrb, file, "Constants"); |
495 | 594 | mrb_define_const(mrb, cnst, "LOCK_SH", mrb_fixnum_value(LOCK_SH)); |
|
0 commit comments