Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristopher Faylor <me@cgf.cx>2003-01-17 08:18:30 +0300
committerChristopher Faylor <me@cgf.cx>2003-01-17 08:18:30 +0300
commit14ea50290a1f9f3954cc562ab877c1950ab8a2bb (patch)
tree2d4965c5bb977b8e1b41f5125aa4b24ba7c7ba38 /winsup/cygwin
parentd4d80d8c65042953c8bd5514c44c8bb2d31dd227 (diff)
* grp.cc (read_etc_group): On NT, add a line for gid = -1. Change name
"unknown" to "mkgroup". (internal_getgrgid): Do not return default in nontsec case. (internal_getgroups): Add argument srchsid and look for it in groups if not NULL. * passwd.cc (read_etc_passwd): On NT, add a line for uid = -1. Use same default uid for Win95 and NT. Call cygheap_user::ontherange to initialize HOME. * cygheap.cc (init_cygheap::etc_changed): Move to uinfo.cc. * cygheap.h (init_cygheap::etc_changed_h): Remove. (init_cygheap::etc_changed): Ditto. * grp.cc (group_state): Remove. Use gr instead throughout. (gr): Define as class pwdgrp. (read_etc_group): Remove gr definition. Remove calls to set_last_modified and close. Pass add_grp to gr.load to load file. * passwd.cc (passwd_state): Remove. Use pr instead, throughout. (pr): Define as class pwdgrp. (read_etc_passwd): Remove pr definition. Remove calls to set_last_modified and close. Pass add_pwd_line to pr.load to load file. * pwdgrp.h (etc): New helper class for pwdgrp. (pwdgrp): Combine pwdgrp_check and pwdgrp_read into one class. Remove file_w32 and last_modified fields. (pwdgrp::set_last_modified): Remove. (pwdgrp::isinitializing): Remove FindFirstFile stuff. Move to etc::file_changed. (pwdgrp::load): Rename from 'open'. Call etc::init to initialize etc scanning. Close file handle after reading buffer into memory. Parse buffer by calling second argument. (pwdgrp::gets): Reorganize slightly to rely on eptr starting at beginning of buffer. Free buffer when memory exhausted. (pwdgrp::close): Remove. * uinfo.cc (etc::dir_changed): New function. (etc::init): Ditto. (etc::file_changed): Ditto. (etc::set_last_modified): Ditto.
Diffstat (limited to 'winsup/cygwin')
-rw-r--r--winsup/cygwin/ChangeLog43
-rw-r--r--winsup/cygwin/cygheap.cc33
-rw-r--r--winsup/cygwin/cygheap.h5
-rw-r--r--winsup/cygwin/grp.cc59
-rw-r--r--winsup/cygwin/passwd.cc53
-rw-r--r--winsup/cygwin/pwdgrp.h166
-rw-r--r--winsup/cygwin/uinfo.cc85
7 files changed, 256 insertions, 188 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index e9c3a2077..3868a2f4c 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,3 +1,46 @@
+2003-01-17 Pierre Humblet <pierre.humblet@ieee.org>
+
+ * grp.cc (read_etc_group): On NT, add a line for gid = -1. Change name
+ "unknown" to "mkgroup".
+ (internal_getgrgid): Do not return default in nontsec case.
+ (internal_getgroups): Add argument srchsid and look for it in groups if
+ not NULL.
+ * passwd.cc (read_etc_passwd): On NT, add a line for uid = -1. Use
+ same default uid for Win95 and NT. Call cygheap_user::ontherange to
+ initialize HOME.
+
+
+2003-01-16 Christopher Faylor <cgf@redhat.com>
+
+ * cygheap.cc (init_cygheap::etc_changed): Move to uinfo.cc.
+ * cygheap.h (init_cygheap::etc_changed_h): Remove.
+ (init_cygheap::etc_changed): Ditto.
+ * grp.cc (group_state): Remove. Use gr instead throughout.
+ (gr): Define as class pwdgrp.
+ (read_etc_group): Remove gr definition. Remove calls to
+ set_last_modified and close. Pass add_grp to gr.load to load file.
+ * passwd.cc (passwd_state): Remove. Use pr instead, throughout.
+ (pr): Define as class pwdgrp.
+ (read_etc_passwd): Remove pr definition. Remove calls to
+ set_last_modified and close. Pass add_pwd_line to pr.load to load
+ file.
+ * pwdgrp.h (etc): New helper class for pwdgrp.
+ (pwdgrp): Combine pwdgrp_check and pwdgrp_read into one class. Remove
+ file_w32 and last_modified fields.
+ (pwdgrp::set_last_modified): Remove.
+ (pwdgrp::isinitializing): Remove FindFirstFile stuff. Move to
+ etc::file_changed.
+ (pwdgrp::load): Rename from 'open'. Call etc::init to initialize etc
+ scanning. Close file handle after reading buffer into memory. Parse
+ buffer by calling second argument.
+ (pwdgrp::gets): Reorganize slightly to rely on eptr starting at
+ beginning of buffer. Free buffer when memory exhausted.
+ (pwdgrp::close): Remove.
+ * uinfo.cc (etc::dir_changed): New function.
+ (etc::init): Ditto.
+ (etc::file_changed): Ditto.
+ (etc::set_last_modified): Ditto.
+
2003-01-16 Jason Tishler <jason@tishler.net>
* mmap.cc (fixup_mmaps_after_fork): Add ERROR_NOACCESS to the list of
diff --git a/winsup/cygwin/cygheap.cc b/winsup/cygwin/cygheap.cc
index d0843e7ac..cdef3e490 100644
--- a/winsup/cygwin/cygheap.cc
+++ b/winsup/cygwin/cygheap.cc
@@ -380,39 +380,6 @@ cstrdup1 (const char *s)
return p;
}
-bool
-init_cygheap::etc_changed ()
-{
- bool res = 0;
-
- if (!etc_changed_h)
- {
- path_conv pwd ("/etc");
- etc_changed_h = FindFirstChangeNotification (pwd, FALSE,
- FILE_NOTIFY_CHANGE_LAST_WRITE);
- if (etc_changed_h == INVALID_HANDLE_VALUE)
- system_printf ("Can't open /etc for checking, %E", (char *) pwd,
- etc_changed_h);
- else if (!DuplicateHandle (hMainProc, etc_changed_h, hMainProc,
- &etc_changed_h, 0, TRUE,
- DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE))
- {
- system_printf ("Can't inherit /etc handle, %E", (char *) pwd,
- etc_changed_h);
- etc_changed_h = INVALID_HANDLE_VALUE;
- }
- }
-
- if (etc_changed_h != INVALID_HANDLE_VALUE
- && WaitForSingleObject (etc_changed_h, 0) == WAIT_OBJECT_0)
- {
- (void) FindNextChangeNotification (etc_changed_h);
- res = 1;
- }
-
- return res;
-}
-
void
cygheap_root::set (const char *posix, const char *native)
{
diff --git a/winsup/cygwin/cygheap.h b/winsup/cygwin/cygheap.h
index 703c1d1dc..bfa7a9308 100644
--- a/winsup/cygwin/cygheap.h
+++ b/winsup/cygwin/cygheap.h
@@ -1,6 +1,6 @@
/* cygheap.h: Cygwin heap manager.
- Copyright 2000, 2001, 2002 Red Hat, Inc.
+ Copyright 2000, 2001, 2002, 2003 Red Hat, Inc.
This file is part of Cygwin.
@@ -216,15 +216,12 @@ struct init_cygheap
mode_t umask;
HANDLE shared_h;
HANDLE console_h;
- HANDLE etc_changed_h;
char *cygwin_regname;
cwdstuff cwd;
dtable fdtab;
#ifdef DEBUGGING
cygheap_debug debug;
#endif
-
- bool etc_changed ();
};
#define CYGHEAPSIZE (sizeof (init_cygheap) + (16000 * sizeof (fhandler_union)) + (4 * 65536))
diff --git a/winsup/cygwin/grp.cc b/winsup/cygwin/grp.cc
index 51ccd066c..9ce2787d0 100644
--- a/winsup/cygwin/grp.cc
+++ b/winsup/cygwin/grp.cc
@@ -40,8 +40,8 @@ static int max_lines;
static int grp_pos = 0;
#endif
-static pwdgrp_check group_state;
-static char * NO_COPY null_ptr = NULL;
+static pwdgrp gr;
+static char * NO_COPY null_ptr;
static int
parse_grp (struct __group32 &grp, char *line)
@@ -129,35 +129,24 @@ pthread_mutex_t NO_COPY group_lock::mutex = (pthread_mutex_t) PTHREAD_MUTEX_INIT
static void
read_etc_group ()
{
- static pwdgrp_read gr;
-
group_lock here (cygwin_finished_initializing);
/* if we got blocked by the mutex, then etc_group may have been processed */
- if (group_state.isinitializing ())
+ if (gr.isinitializing ())
{
for (int i = 0; i < curr_lines; i++)
if ((group_buf + i)->gr_mem != &null_ptr)
free ((group_buf + i)->gr_mem);
curr_lines = 0;
- if (gr.open ("/etc/group"))
- {
- char *line;
- while ((line = gr.gets ()) != NULL)
- add_grp_line (line);
-
- group_state.set_last_modified (gr.get_fhandle (), gr.get_fname ());
- gr.close ();
- debug_printf ("Read /etc/group, %d lines", curr_lines);
- }
- group_state = loaded;
+ if (!gr.load ("/etc/group", add_grp_line))
+ debug_printf ("gr.load failed");
/* Complete /etc/group in memory if needed */
if (!internal_getgrgid (myself->gid))
{
static char linebuf [200];
- char group_name [UNLEN + 1] = "unknown";
+ char group_name [UNLEN + 1] = "mkgroup";
char strbuf[128] = "";
if (wincap.has_security ())
@@ -173,6 +162,9 @@ read_etc_group ()
debug_printf ("Completing /etc/group: %s", linebuf);
add_grp_line (linebuf);
}
+ static char pretty_ls[] = "????????::-1:";
+ if (wincap.has_security ())
+ add_grp_line (pretty_ls);
}
return;
}
@@ -182,7 +174,7 @@ internal_getgrsid (cygsid &sid)
{
char sid_string[128];
- if (group_state.isuninitialized ())
+ if (gr.isuninitialized ())
read_etc_group ();
if (sid.string (sid_string))
@@ -195,27 +187,19 @@ internal_getgrsid (cygsid &sid)
struct __group32 *
internal_getgrgid (__gid32_t gid, BOOL check)
{
- struct __group32 * default_grp = NULL;
-
- if (group_state.isuninitialized ()
- || (check && group_state.isinitializing ()))
+ if (gr.isuninitialized () || (check && gr.isinitializing ()))
read_etc_group ();
for (int i = 0; i < curr_lines; i++)
- {
- if (group_buf[i].gr_gid == myself->gid)
- default_grp = group_buf + i;
- if (group_buf[i].gr_gid == gid)
- return group_buf + i;
- }
- return allow_ntsec || gid != ILLEGAL_GID ? NULL : default_grp;
+ if (group_buf[i].gr_gid == gid)
+ return group_buf + i;
+ return NULL;
}
struct __group32 *
internal_getgrnam (const char *name, BOOL check)
{
- if (group_state.isuninitialized ()
- || (check && group_state.isinitializing ()))
+ if (gr.isuninitialized () || (check && gr.isinitializing ()))
read_etc_group ();
for (int i = 0; i < curr_lines; i++)
@@ -280,7 +264,7 @@ endgrent ()
extern "C" struct __group32 *
getgrent32 ()
{
- if (group_state.isinitializing ())
+ if (gr.isinitializing ())
read_etc_group ();
if (grp_pos < curr_lines)
@@ -307,7 +291,7 @@ setgrent ()
struct __group32 *
internal_getgrent (int pos)
{
- if (group_state.isuninitialized ())
+ if (gr.isuninitialized ())
read_etc_group ();
if (pos < curr_lines)
@@ -316,7 +300,7 @@ internal_getgrent (int pos)
}
int
-internal_getgroups (int gidsetsize, __gid32_t *grouplist)
+internal_getgroups (int gidsetsize, __gid32_t *grouplist, cygsid * srchsid)
{
HANDLE hToken = NULL;
DWORD size;
@@ -345,6 +329,13 @@ internal_getgroups (int gidsetsize, __gid32_t *grouplist)
{
cygsid sid;
+ if (srchsid)
+ {
+ for (DWORD pg = 0; pg < groups->GroupCount; ++pg)
+ if (*srchsid == groups->Groups[pg].Sid)
+ return 1;
+ return 0;
+ }
for (int gidx = 0; (gr = internal_getgrent (gidx)); ++gidx)
if (sid.getfromgr (gr))
for (DWORD pg = 0; pg < groups->GroupCount; ++pg)
diff --git a/winsup/cygwin/passwd.cc b/winsup/cygwin/passwd.cc
index 2aca84c5d..d87864f52 100644
--- a/winsup/cygwin/passwd.cc
+++ b/winsup/cygwin/passwd.cc
@@ -30,8 +30,7 @@ static struct passwd *passwd_buf; /* passwd contents in memory */
static int curr_lines;
static int max_lines;
-static pwdgrp_check passwd_state;
-
+static pwdgrp pr;
/* Position in the passwd cache */
#ifdef _MT_SAFE
@@ -40,7 +39,7 @@ static pwdgrp_check passwd_state;
static int pw_pos = 0;
#endif
-/* Remove a : teminated string from the buffer, and increment the pointer */
+/* Remove a : terminated string from the buffer, and increment the pointer */
static char *
grab_string (char **p)
{
@@ -122,48 +121,37 @@ class passwd_lock
pthread_mutex_t NO_COPY passwd_lock::mutex = (pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER;
/* Read in /etc/passwd and save contents in the password cache.
- This sets passwd_state to loaded or emulated so functions in this file can
+ This sets pr to loaded or emulated so functions in this file can
tell that /etc/passwd has been read in or will be emulated. */
static void
read_etc_passwd ()
{
- static pwdgrp_read pr;
-
/* A mutex is ok for speed here - pthreads will use critical sections not
* mutexes for non-shared mutexes in the future. Also, this function will
- * at most be called once from each thread, after that the passwd_state
+ * at most be called once from each thread, after that the pr
* test will succeed */
passwd_lock here (cygwin_finished_initializing);
/* if we got blocked by the mutex, then etc_passwd may have been processed */
- if (passwd_state.isinitializing ())
+ if (pr.isinitializing ())
{
curr_lines = 0;
- if (pr.open ("/etc/passwd"))
- {
- char *line;
- while ((line = pr.gets ()) != NULL)
- add_pwd_line (line);
-
- passwd_state.set_last_modified (pr.get_fhandle (), pr.get_fname ());
- pr.close ();
- debug_printf ("Read /etc/passwd, %d lines", curr_lines);
- }
- passwd_state = loaded;
+ if (!pr.load ("/etc/passwd", add_pwd_line))
+ debug_printf ("pr.load failed");
static char linebuf[1024];
char strbuf[128] = "";
BOOL searchentry = TRUE;
- __uid32_t default_uid = DEFAULT_UID;
struct passwd *pw;
if (wincap.has_security ())
{
+ static char pretty_ls[] = "????????:*:-1:-1:";
+ add_pwd_line (pretty_ls);
cygsid tu = cygheap->user.sid ();
tu.string (strbuf);
- if (myself->uid == ILLEGAL_UID
- && (searchentry = !internal_getpwsid (tu)))
- default_uid = DEFAULT_UID_NT;
+ if (myself->uid == ILLEGAL_UID)
+ searchentry = !internal_getpwsid (tu);
}
else if (myself->uid == ILLEGAL_UID)
searchentry = !internal_getpwuid (DEFAULT_UID);
@@ -173,11 +161,12 @@ read_etc_passwd ()
myself->uid != (__uid32_t) pw->pw_uid &&
!internal_getpwuid (myself->uid))))
{
+ (void) cygheap->user.ontherange (CH_HOME, NULL);
snprintf (linebuf, sizeof (linebuf), "%s:*:%lu:%lu:,%s:%s:/bin/sh",
cygheap->user.name (),
- myself->uid == ILLEGAL_UID ? default_uid : myself->uid,
+ myself->uid == ILLEGAL_UID ? DEFAULT_UID_NT : myself->uid,
myself->gid,
- strbuf, getenv ("HOME") ?: "/");
+ strbuf, getenv ("HOME") ?: "");
debug_printf ("Completing /etc/passwd: %s", linebuf);
add_pwd_line (linebuf);
}
@@ -192,7 +181,7 @@ internal_getpwsid (cygsid &sid)
char *ptr1, *ptr2, *endptr;
char sid_string[128] = {0,','};
- if (passwd_state.isuninitialized ())
+ if (pr.isuninitialized ())
read_etc_passwd ();
if (sid.string (sid_string + 2))
@@ -211,8 +200,8 @@ internal_getpwsid (cygsid &sid)
struct passwd *
internal_getpwuid (__uid32_t uid, BOOL check)
{
- if (passwd_state.isuninitialized ()
- || (check && passwd_state.isinitializing ()))
+ if (pr.isuninitialized ()
+ || (check && pr.isinitializing ()))
read_etc_passwd ();
for (int i = 0; i < curr_lines; i++)
@@ -224,8 +213,8 @@ internal_getpwuid (__uid32_t uid, BOOL check)
struct passwd *
internal_getpwnam (const char *name, BOOL check)
{
- if (passwd_state.isuninitialized ()
- || (check && passwd_state.isinitializing ()))
+ if (pr.isuninitialized ()
+ || (check && pr.isinitializing ()))
read_etc_passwd ();
for (int i = 0; i < curr_lines; i++)
@@ -347,7 +336,7 @@ getpwnam_r (const char *nam, struct passwd *pwd, char *buffer, size_t bufsize, s
extern "C" struct passwd *
getpwent (void)
{
- if (passwd_state.isinitializing ())
+ if (pr.isinitializing ())
read_etc_passwd ();
if (pw_pos < curr_lines)
@@ -390,7 +379,7 @@ getpass (const char * prompt)
#endif
struct termios ti, newti;
- if (passwd_state.isinitializing ())
+ if (pr.isinitializing ())
read_etc_passwd ();
cygheap_fdget fhstdin (0);
diff --git a/winsup/cygwin/pwdgrp.h b/winsup/cygwin/pwdgrp.h
index 6be1b32f7..c0466b446 100644
--- a/winsup/cygwin/pwdgrp.h
+++ b/winsup/cygwin/pwdgrp.h
@@ -19,7 +19,7 @@ extern struct __group32 *internal_getgrsid (cygsid &);
extern struct __group32 *internal_getgrgid (__gid32_t gid, BOOL = FALSE);
extern struct __group32 *internal_getgrnam (const char *, BOOL = FALSE);
extern struct __group32 *internal_getgrent (int);
-int internal_getgroups (int, __gid32_t *);
+int internal_getgroups (int, __gid32_t *, cygsid * = NULL);
enum pwdgrp_state {
uninitialized = 0,
@@ -27,111 +27,107 @@ enum pwdgrp_state {
loaded
};
-class pwdgrp_check {
- pwdgrp_state state;
- FILETIME last_modified;
- char file_w32[MAX_PATH];
+#define MAX_ETC_FILES 2
+class etc
+{
+ static int curr_ix;
+ static bool sawchange[MAX_ETC_FILES];
+ static const char *fn[MAX_ETC_FILES];
+ static FILETIME last_modified[MAX_ETC_FILES];
+ static bool dir_changed (int);
+ static int init (int, const char *);
+ static bool file_changed (int);
+ static void set_last_modified (int, FILETIME&);
+ friend class pwdgrp;
+};
+
+class pwdgrp
+{
+ pwdgrp_state state;
+ int pwd_ix;
+ path_conv pc;
+ char *buf;
+ char *lptr, *eptr;
+
+ char *gets ()
+ {
+ if (!buf)
+ lptr = NULL;
+ else if (!eptr)
+ lptr = NULL;
+ else
+ {
+ lptr = eptr;
+ eptr = strchr (lptr, '\n');
+ if (eptr)
+ {
+ if (eptr > lptr && *(eptr - 1) == '\r')
+ *(eptr - 1) = 0;
+ *eptr++ = '\0';
+ }
+ }
+ return lptr;
+ }
public:
- pwdgrp_check () : state (uninitialized) {}
+ pwdgrp () : state (uninitialized) {}
BOOL isinitializing ()
{
if (state <= initializing)
state = initializing;
- else if (cygheap->etc_changed ())
- {
- if (!file_w32[0])
- state = initializing;
- else
- {
- HANDLE h;
- WIN32_FIND_DATA data;
-
- if ((h = FindFirstFile (file_w32, &data)) != INVALID_HANDLE_VALUE)
- {
- if (CompareFileTime (&data.ftLastWriteTime, &last_modified) > 0)
- state = initializing;
- FindClose (h);
- }
- }
- }
+ else if (etc::file_changed (pwd_ix - 1))
+ state = initializing;
return state == initializing;
}
- void operator = (pwdgrp_state nstate)
- {
- state = nstate;
- }
+ void operator = (pwdgrp_state nstate) { state = nstate; }
BOOL isuninitialized () const { return state == uninitialized; }
- void set_last_modified (HANDLE fh, const char *name)
- {
- if (!file_w32[0])
- strcpy (file_w32, name);
- GetFileTime (fh, NULL, NULL, &last_modified);
- }
-};
-
-class pwdgrp_read {
- path_conv pc;
- HANDLE fh;
- char *buf;
- char *lptr, *eptr;
-public:
- bool open (const char *posix_fname)
+ bool load (const char *posix_fname, void (* add_line) (char *))
{
if (buf)
free (buf);
buf = lptr = eptr = NULL;
pc.check (posix_fname);
- if (pc.error || !pc.exists () || !pc.isdisk () || pc.isdir ())
- return false;
+ pwd_ix = etc::init (pwd_ix - 1, pc) + 1;
+
+ paranoid_printf ("%s", posix_fname);
- fh = CreateFile (pc, GENERIC_READ, wincap.shared (), NULL, OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL, 0);
- if (fh != INVALID_HANDLE_VALUE)
+ bool res;
+ if (pc.error || !pc.exists () || !pc.isdisk () || pc.isdir ())
+ res = false;
+ else
{
- DWORD size = GetFileSize (fh, NULL), read_bytes;
- buf = (char *) malloc (size + 1);
- if (!ReadFile (fh, buf, size, &read_bytes, NULL))
+ HANDLE fh = CreateFile (pc, GENERIC_READ, wincap.shared (), NULL,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
+ if (fh == INVALID_HANDLE_VALUE)
+ res = false;
+ else
{
- if (buf)
- free (buf);
- buf = NULL;
+ DWORD size = GetFileSize (fh, NULL), read_bytes;
+ buf = (char *) malloc (size + 1);
+ if (!ReadFile (fh, buf, size, &read_bytes, NULL))
+ {
+ if (buf)
+ free (buf);
+ buf = NULL;
+ fh = NULL;
+ return false;
+ }
+ buf[read_bytes] = '\0';
+ eptr = buf;
CloseHandle (fh);
- fh = NULL;
- return false;
+ FILETIME ft;
+ if (GetFileTime (fh, NULL, NULL, &ft))
+ etc::set_last_modified (pwd_ix - 1, ft);
+ char *line;
+ while ((line = gets()) != NULL)
+ add_line (line);
+ res = true;
}
- buf[read_bytes] = '\0';
- return true;
- }
- return false;
- }
- char *gets ()
- {
- if (!buf)
- return NULL;
- if (!lptr)
- lptr = buf;
- else if (!eptr)
- return lptr = NULL;
- else
- lptr = eptr;
- eptr = strchr (lptr, '\n');
- if (eptr)
- {
- if (eptr > lptr && *(eptr - 1) == '\r')
- *(eptr - 1) = 0;
- *eptr++ = '\0';
}
- return lptr;
- }
- inline HANDLE get_fhandle () { return fh; }
- inline const char *get_fname () { return pc; }
- void close ()
- {
- if (fh)
- CloseHandle (fh);
- fh = NULL;
+
+ state = loaded;
+ return res;
}
};
diff --git a/winsup/cygwin/uinfo.cc b/winsup/cygwin/uinfo.cc
index a2a46a03f..5eb76b100 100644
--- a/winsup/cygwin/uinfo.cc
+++ b/winsup/cygwin/uinfo.cc
@@ -389,3 +389,88 @@ cygheap_user::env_name (const char *name, size_t namelen)
(void) domain ();
return pwinname;
}
+
+int NO_COPY etc::curr_ix = -1;
+bool NO_COPY etc::sawchange[MAX_ETC_FILES];
+const NO_COPY char *etc::fn[MAX_ETC_FILES];
+FILETIME NO_COPY etc::last_modified[MAX_ETC_FILES];
+
+int
+etc::init (int n, const char *etc_fn)
+{
+ if (n >= 0)
+ /* ok */;
+ else if (++curr_ix < MAX_ETC_FILES)
+ n = curr_ix;
+ else
+ api_fatal ("internal error");
+
+ fn[n] = etc_fn;
+ sawchange[n] = false;
+ paranoid_printf ("curr_ix %d, n %d", curr_ix, n);
+ return curr_ix;
+}
+
+bool
+etc::dir_changed (int n)
+{
+ bool res = sawchange[n];
+
+ if (!res)
+ {
+ static HANDLE NO_COPY changed_h;
+ if (!changed_h)
+ {
+ path_conv pwd ("/etc");
+ changed_h = FindFirstChangeNotification (pwd, FALSE,
+ FILE_NOTIFY_CHANGE_LAST_WRITE);
+ if (changed_h == INVALID_HANDLE_VALUE)
+ system_printf ("Can't open /etc for checking, %E", (char *) pwd,
+ changed_h);
+ }
+
+ if (changed_h == INVALID_HANDLE_VALUE)
+ res = true;
+ else if (WaitForSingleObject (changed_h, 0) == WAIT_OBJECT_0)
+ {
+ (void) FindNextChangeNotification (changed_h);
+ memset (sawchange, true, sizeof sawchange);
+ res = true;
+ }
+ }
+
+ paranoid_printf ("%s res %d", fn[n], res);
+ return res;
+}
+
+bool
+etc::file_changed (int n)
+{
+ bool res = false;
+ if (!fn[n])
+ res = true;
+ else if (dir_changed (n))
+ {
+ HANDLE h;
+ WIN32_FIND_DATA data;
+
+ if ((h = FindFirstFile (fn[n], &data)) == INVALID_HANDLE_VALUE)
+ res = true;
+ else
+ {
+ FindClose (h);
+ if (CompareFileTime (&data.ftLastWriteTime, last_modified + n) > 0)
+ res = true;
+ }
+ }
+ sawchange[n] = false;
+ paranoid_printf ("%s res %d", fn[n], res);
+ return res;
+}
+
+void
+etc::set_last_modified (int n, FILETIME& ft)
+{
+ last_modified[n] = ft;
+ sawchange[n] = false;
+}