aboutsummaryrefslogtreecommitdiffhomepage
path: root/wutil.cpp
diff options
context:
space:
mode:
authorGravatar ridiculousfish <corydoras@ridiculousfish.com>2014-04-28 15:14:33 -0700
committerGravatar ridiculousfish <corydoras@ridiculousfish.com>2014-04-28 15:14:33 -0700
commit91aadab3dda85cf51b7c6d89b7e70f32bd437e5b (patch)
tree83795d0565e567f04b61ef4493c079c25efa4686 /wutil.cpp
parentc3425bc55f9b4c627519e49d8c29a7d4abde2019 (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.cpp79
1 files changed, 74 insertions, 5 deletions
diff --git a/wutil.cpp b/wutil.cpp
index af6de26a..3b1bba79 100644
--- a/wutil.cpp
+++ b/wutil.cpp
@@ -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;
+}