|
52 | 52 | #include <malloc/malloc.h>
|
53 | 53 | #endif
|
54 | 54 |
|
| 55 | +#if TARGET_OS_LINUX |
| 56 | +// required for statx() system call |
| 57 | +#include <sys/syscall.h> |
| 58 | +#include <sys/types.h> |
| 59 | +#include <sys/stat.h> |
| 60 | +#include <linux/stat.h> |
| 61 | +#define AT_STATX_SYNC_AS_STAT 0x0000 /* - Do whatever stat() does */ |
| 62 | +#endif |
| 63 | + |
| 64 | + |
55 | 65 | _CF_EXPORT_SCOPE_BEGIN
|
56 | 66 |
|
57 | 67 | CF_CROSS_PLATFORM_EXPORT Boolean _CFCalendarGetNextWeekend(CFCalendarRef calendar, _CFCalendarWeekendRange *range);
|
@@ -482,6 +492,69 @@ static inline unsigned int _dev_major(dev_t rdev) {
|
482 | 492 | static inline unsigned int _dev_minor(dev_t rdev) {
|
483 | 493 | return minor(rdev);
|
484 | 494 | }
|
| 495 | + |
| 496 | +static inline dev_t _dev_makedev(unsigned int major, unsigned int minor) { |
| 497 | + return makedev(major, minor); |
| 498 | +} |
| 499 | +#endif |
| 500 | + |
| 501 | + |
| 502 | +#if TARGET_OS_LINUX |
| 503 | +#ifdef __NR_statx |
| 504 | + |
| 505 | +// There is no glibc statx() function, it must be called using syscall(). |
| 506 | + |
| 507 | +static inline ssize_t |
| 508 | +_statx(int dfd, const char *filename, unsigned int flags, unsigned int mask, struct statx *buffer) { |
| 509 | + return syscall(__NR_statx, dfd, filename, flags, mask, buffer); |
| 510 | +} |
| 511 | + |
| 512 | +// At the moment the only extra information statx() is used for is to get the btime (file creation time). |
| 513 | +// This function is here instead of in FileManager.swift because there is no way of setting a conditional |
| 514 | +// define that could be used with a #if in the Swift code. |
| 515 | +static inline ssize_t |
| 516 | +_stat_with_btime(const char *filename, struct stat *buffer, struct timespec *btime) { |
| 517 | + struct statx statx_buffer = {0}; |
| 518 | + *btime = (struct timespec) {0}; |
| 519 | + |
| 520 | + ssize_t ret = _statx(AT_FDCWD, filename, AT_SYMLINK_NOFOLLOW | AT_STATX_SYNC_AS_STAT, STATX_ALL, &statx_buffer); |
| 521 | + if (ret == 0) { |
| 522 | + *buffer = (struct stat) { |
| 523 | + .st_dev = makedev(statx_buffer.stx_dev_major, statx_buffer.stx_dev_minor), |
| 524 | + .st_ino = statx_buffer.stx_ino, |
| 525 | + .st_mode = statx_buffer.stx_mode, |
| 526 | + .st_nlink = statx_buffer.stx_nlink, |
| 527 | + .st_uid = statx_buffer.stx_uid, |
| 528 | + .st_gid = statx_buffer.stx_gid, |
| 529 | + .st_rdev = makedev(statx_buffer.stx_rdev_major, statx_buffer.stx_rdev_minor), |
| 530 | + .st_size = statx_buffer.stx_size, |
| 531 | + .st_blksize = statx_buffer.stx_blksize, |
| 532 | + .st_blocks = statx_buffer.stx_blocks, |
| 533 | + .st_atim = { .tv_sec = statx_buffer.stx_atime.tv_sec, .tv_nsec = statx_buffer.stx_atime.tv_nsec }, |
| 534 | + .st_mtim = { .tv_sec = statx_buffer.stx_mtime.tv_sec, .tv_nsec = statx_buffer.stx_mtime.tv_nsec }, |
| 535 | + .st_ctim = { .tv_sec = statx_buffer.stx_ctime.tv_sec, .tv_nsec = statx_buffer.stx_ctime.tv_nsec }, |
| 536 | + }; |
| 537 | + *btime = (struct timespec) { |
| 538 | + .tv_sec = statx_buffer.stx_btime.tv_sec, |
| 539 | + .tv_nsec = statx_buffer.stx_btime.tv_nsec |
| 540 | + }; |
| 541 | + } |
| 542 | + return ret; |
| 543 | +} |
| 544 | +#else |
| 545 | + |
| 546 | +// Dummy version when compiled where struct statx is not defined in the headers. |
| 547 | +// Just calles lstat() instead. |
| 548 | +static inline ssize_t |
| 549 | +_stat_with_btime(const char *filename, struct stat *buffer, struct timespec *btime) { |
| 550 | + *btime = (struct timespec) {0}; |
| 551 | + return lstat(filename, buffer); |
| 552 | +} |
| 553 | +#endif // __NR_statx |
| 554 | +#endif // TARGET_OS_LINUX |
| 555 | + |
| 556 | +#if __HAS_STATX |
| 557 | +#warning "Enabling statx" |
485 | 558 | #endif
|
486 | 559 |
|
487 | 560 | _CF_EXPORT_SCOPE_END
|
|
0 commit comments