OSDN Git Service

* grp.cc (read_etc_group): On NT, add a line for gid = -1. Change name
authorcgf <cgf>
Fri, 17 Jan 2003 05:18:29 +0000 (05:18 +0000)
committercgf <cgf>
Fri, 17 Jan 2003 05:18:29 +0000 (05:18 +0000)
"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.

winsup/cygwin/ChangeLog
winsup/cygwin/cygheap.cc
winsup/cygwin/cygheap.h
winsup/cygwin/grp.cc
winsup/cygwin/passwd.cc
winsup/cygwin/pwdgrp.h
winsup/cygwin/uinfo.cc

index e9c3a20..3868a2f 100644 (file)
@@ -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
index d0843e7..cdef3e4 100644 (file)
@@ -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)
 {
index 703c1d1..bfa7a93 100644 (file)
@@ -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))
index 51ccd06..9ce2787 100644 (file)
@@ -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)
index 2aca84c..d87864f 100644 (file)
@@ -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);
index 6be1b32..c0466b4 100644 (file)
@@ -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;
   }
 };
index a2a46a0..5eb76b1 100644 (file)
@@ -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;
+}