diff options
author | ridiculousfish <corydoras@ridiculousfish.com> | 2014-04-28 15:14:33 -0700 |
---|---|---|
committer | ridiculousfish <corydoras@ridiculousfish.com> | 2014-04-28 15:14:33 -0700 |
commit | 91aadab3dda85cf51b7c6d89b7e70f32bd437e5b (patch) | |
tree | 83795d0565e567f04b61ef4493c079c25efa4686 /wutil.cpp | |
parent | c3425bc55f9b4c627519e49d8c29a7d4abde2019 (diff) |
Enhance file_id_t to have richer information, to guard against inode
recycling on Linux filesystems
Diffstat (limited to 'wutil.cpp')
-rw-r--r-- | wutil.cpp | 79 |
1 files changed, 74 insertions, 5 deletions
@@ -35,7 +35,7 @@ typedef std::string cstring; -const file_id_t kInvalidFileID = file_id_t((dev_t)(-1), (ino_t)(-1)); +const file_id_t kInvalidFileID = {-1, -1, -1, -1, -1, -1}; /** Minimum length of the internal covnersion buffers @@ -528,14 +528,42 @@ int fish_wcstoi(const wchar_t *str, wchar_t ** endptr, int base) return (int)ret; } +file_id_t file_id_t::file_id_from_stat(const struct stat *buf) +{ + assert(buf != NULL); + + file_id_t result = {}; + result.device = buf->st_dev; + result.inode = buf->st_ino; + result.size = buf->st_size; + result.change_seconds = buf->st_ctime; + +#if STAT_HAVE_NSEC + result.change_nanoseconds = buf->st_ctime_nsec; +#elif defined(__APPLE__) + result.change_nanoseconds = buf->st_ctimespec.tv_nsec; +#elif defined(_BSD_SOURCE) || defined(_SVID_SOURCE) || defined(_XOPEN_SOURCE) + result.change_nanoseconds = buf->st_ctim.tv_nsec; +#else + result.change_nanoseconds = 0; +#endif + +#if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + result.generation = buf->st_gen; +#else + result.generation = 0; +#endif + return result; +} + + file_id_t file_id_for_fd(int fd) { file_id_t result = kInvalidFileID; struct stat buf = {}; if (0 == fstat(fd, &buf)) { - result.first = buf.st_dev; - result.second = buf.st_ino; + result = file_id_t::file_id_from_stat(&buf); } return result; } @@ -546,9 +574,50 @@ file_id_t file_id_for_path(const wcstring &path) struct stat buf = {}; if (0 == wstat(path, &buf)) { - result.first = buf.st_dev; - result.second = buf.st_ino; + result = file_id_t::file_id_from_stat(&buf); } return result; } + +bool file_id_t::operator==(const file_id_t &rhs) const +{ + return device == rhs.device && + inode == rhs.inode && + size == rhs.size && + change_seconds == rhs.change_seconds && + change_nanoseconds == rhs.change_nanoseconds && + generation == rhs.generation; +} + +bool file_id_t::operator!=(const file_id_t &rhs) const +{ + return ! (*this == rhs); +} + +template<typename T> +int compare(T a, T b) +{ + if (a < b) + { + return -1; + } + else if (a > b) + { + return 1; + } + return 0; +} + +bool file_id_t::operator<(const file_id_t &rhs) const +{ + /* Compare each field, stopping when we get to a non-equal field */ + int ret = 0; + if (! ret) ret = compare(device, rhs.device); + if (! ret) ret = compare(inode, rhs.inode); + if (! ret) ret = compare(size, rhs.size); + if (! ret) ret = compare(generation, rhs.generation); + if (! ret) ret = compare(change_seconds, rhs.change_seconds); + if (! ret) ret = compare(change_nanoseconds, rhs.change_nanoseconds); + return ret < 0; +} |