aboutsummaryrefslogtreecommitdiff
path: root/winsup/cygwin/path.cc
diff options
context:
space:
mode:
Diffstat (limited to 'winsup/cygwin/path.cc')
-rw-r--r--winsup/cygwin/path.cc136
1 files changed, 136 insertions, 0 deletions
diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc
index 631b169a0..065456251 100644
--- a/winsup/cygwin/path.cc
+++ b/winsup/cygwin/path.cc
@@ -4633,6 +4633,142 @@ out:
return buf;
}
+int etc::curr_ix = 0;
+/* Note that the first elements of the below arrays are unused */
+bool etc::change_possible[MAX_ETC_FILES + 1];
+OBJECT_ATTRIBUTES etc::fn[MAX_ETC_FILES + 1];
+LARGE_INTEGER etc::last_modified[MAX_ETC_FILES + 1];
+
+int
+etc::init (int n, POBJECT_ATTRIBUTES attr)
+{
+ if (n > 0)
+ /* ok */;
+ else if (++curr_ix <= MAX_ETC_FILES)
+ n = curr_ix;
+ else
+ api_fatal ("internal error");
+
+ fn[n] = *attr;
+ change_possible[n] = false;
+ test_file_change (n);
+ paranoid_printf ("fn[%d] %S, curr_ix %d", n, fn[n].ObjectName, curr_ix);
+ return n;
+}
+
+bool
+etc::test_file_change (int n)
+{
+ NTSTATUS status;
+ FILE_NETWORK_OPEN_INFORMATION fnoi;
+ bool res;
+
+ status = NtQueryFullAttributesFile (&fn[n], &fnoi);
+ if (!NT_SUCCESS (status))
+ {
+ res = status != STATUS_OBJECT_NAME_NOT_FOUND;
+ memset (last_modified + n, 0, sizeof (last_modified[n]));
+ debug_printf ("NtQueryFullAttributesFile (%S) failed, %y",
+ fn[n].ObjectName, status);
+ }
+ else
+ {
+ res = CompareFileTime ((FILETIME *) &fnoi.LastWriteTime,
+ (FILETIME *) last_modified + n) > 0;
+ last_modified[n].QuadPart = fnoi.LastWriteTime.QuadPart;
+ }
+
+ paranoid_printf ("fn[%d] %S res %d", n, fn[n].ObjectName, res);
+ return res;
+}
+
+bool
+etc::dir_changed (int n)
+{
+ /* io MUST be static because NtNotifyChangeDirectoryFile works asynchronously.
+ It may write into io after the function has left, which may result in all
+ sorts of stack corruption. */
+ static IO_STATUS_BLOCK io NO_COPY;
+ static HANDLE changed_h NO_COPY;
+
+ if (!change_possible[n])
+ {
+ NTSTATUS status;
+
+ if (!changed_h)
+ {
+ OBJECT_ATTRIBUTES attr;
+
+ path_conv dir ("/etc");
+ status = NtOpenFile (&changed_h, SYNCHRONIZE | FILE_LIST_DIRECTORY,
+ dir.get_object_attr (attr, sec_none_nih), &io,
+ FILE_SHARE_VALID_FLAGS, FILE_DIRECTORY_FILE);
+ if (!NT_SUCCESS (status))
+ {
+#ifdef DEBUGGING
+ system_printf ("NtOpenFile (%S) failed, %y",
+ dir.get_nt_native_path (), status);
+#endif
+ changed_h = INVALID_HANDLE_VALUE;
+ }
+ else
+ {
+ status = NtNotifyChangeDirectoryFile (changed_h, NULL, NULL,
+ NULL, &io, NULL, 0,
+ FILE_NOTIFY_CHANGE_LAST_WRITE
+ | FILE_NOTIFY_CHANGE_FILE_NAME,
+ FALSE);
+ if (!NT_SUCCESS (status))
+ {
+#ifdef DEBUGGING
+ system_printf ("NtNotifyChangeDirectoryFile (1) failed, %y",
+ status);
+#endif
+ NtClose (changed_h);
+ changed_h = INVALID_HANDLE_VALUE;
+ }
+ }
+ memset (change_possible, true, sizeof (change_possible));
+ }
+
+ if (changed_h == INVALID_HANDLE_VALUE)
+ change_possible[n] = true;
+ else if (WaitForSingleObject (changed_h, 0) == WAIT_OBJECT_0)
+ {
+ status = NtNotifyChangeDirectoryFile (changed_h, NULL, NULL,
+ NULL, &io, NULL, 0,
+ FILE_NOTIFY_CHANGE_LAST_WRITE
+ | FILE_NOTIFY_CHANGE_FILE_NAME,
+ FALSE);
+ if (!NT_SUCCESS (status))
+ {
+#ifdef DEBUGGING
+ system_printf ("NtNotifyChangeDirectoryFile (2) failed, %y",
+ status);
+#endif
+ NtClose (changed_h);
+ changed_h = INVALID_HANDLE_VALUE;
+ }
+ memset (change_possible, true, sizeof change_possible);
+ }
+ }
+
+ paranoid_printf ("fn[%d] %S change_possible %d",
+ n, fn[n].ObjectName, change_possible[n]);
+ return change_possible[n];
+}
+
+bool
+etc::file_changed (int n)
+{
+ bool res = false;
+ if (dir_changed (n) && test_file_change (n))
+ res = true;
+ change_possible[n] = false; /* Change is no longer possible */
+ paranoid_printf ("fn[%d] %S res %d", n, fn[n].ObjectName, res);
+ return res;
+}
+
/* No need to be reentrant or thread-safe according to SUSv3.
/ and \\ are treated equally. Leading drive specifiers are
kept intact as far as it makes sense. Everything else is