diff options
Diffstat (limited to 'winsup/cygwin/path.cc')
-rw-r--r-- | winsup/cygwin/path.cc | 136 |
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 |