OSDN Git Service

* pwdgrp.h (etc): Move to path.h.
authorcgf <cgf>
Mon, 20 Jan 2003 02:57:53 +0000 (02:57 +0000)
committercgf <cgf>
Mon, 20 Jan 2003 02:57:53 +0000 (02:57 +0000)
(pwdgrp::max_lines): New field.
(pwdgrp::curr_lines): New field.
(pwdgrp::pwdgrp_buf): Ditto.
(pwdgrp_buf_elem_size): Ditto.
(pwdgrp_parse): Ditto.
(pwdgrp::gets): Just declare here.
(pwdgrp::load): Ditto.  Just take one argument.
(pwdgrp::load): Define overloaded function accepting passwd buf.
(pwdgrp::load): Define overloaded function accepting group buf.
* grp.cc: Use pwdgrp elements rather than standalone static variables
throughout.
(curr_lines): Eliminate.
(max_lines): Ditto.
(add_grp_line): Ditto.
(parse_grp): Define as returning boolean.  Accept void * arg and line count.
Coerce first argument into __group32 buf reference.  Increment curr_line as
appropriate.
(read_etc_group): Pass pwdgrp buffer to gr.load.
* passwd.cc: Use pwdgrp elements rather than standalone static variables
throughout.
(curr_lines): Eliminate.
(max_lines): Ditto.
(add_grp_line): Ditto.
(parse_passwd): Define as returning boolean.  Accept void * arg and line count.
Coerce first argument into passwd buf reference.  Increment curr_line as
appropriate.
(read_etc_group): Pass pwdgrp buffer to pr.load.
* path.cc (etc::fn): Extend buffer size to allow index by 1 rather than zero.
(etc::last_modified): Ditto.
(etc::change_possible): Ditto.  Renamed from sawchange.  Change to signed char
since elements are now tri-state.
(etc::init): Assume "handle" is 1 based rather than 0.
(etc::test_file_change): New function.  Sets change_possible based on file date
comparison.
(etc::dir_changed): Check file states immediately after changed_h is
initialized to avoid a race.
(etc::file_changed): Use test_file_change to detect if file needs to be
updated.
* path.h (etc): Move class here from pwdgrp.h.
* uinfo.cc: Move etc:: functions to path.cc.  Move pwdgrp functions here.
(pwdgrp::gets): Eliminate buf checks.  Just check eptr and set lptr.
(pwdgrp::add_line): New function.
(pwdgrp::load): Call generic add_line function which will call correct parser.

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

index 00936c3..8d17d97 100644 (file)
@@ -1,3 +1,54 @@
+2003-01-19  Christopher Faylor  <cgf@redhat.com>
+
+       * pwdgrp.h (etc): Move to path.h.
+       (pwdgrp::max_lines): New field.
+       (pwdgrp::curr_lines): New field.
+       (pwdgrp::pwdgrp_buf): Ditto.
+       (pwdgrp_buf_elem_size): Ditto.
+       (pwdgrp_parse): Ditto.
+       (pwdgrp::gets): Just declare here.
+       (pwdgrp::load): Ditto.  Just take one argument.
+       (pwdgrp::load): Define overloaded function accepting passwd buf.
+       (pwdgrp::load): Define overloaded function accepting group buf.
+       * grp.cc: Use pwdgrp elements rather than standalone static variables
+       throughout.
+       (curr_lines): Eliminate.
+       (max_lines): Ditto.
+       (add_grp_line): Ditto.
+       (parse_grp): Define as returning boolean.  Accept void * arg and line
+       count.  Coerce first argument into __group32 buf reference.  Increment
+       curr_line as appropriate.
+       (read_etc_group): Pass pwdgrp buffer to gr.load.
+       * passwd.cc: Use pwdgrp elements rather than standalone static variables
+       throughout.
+       (curr_lines): Eliminate.
+       (max_lines): Ditto.
+       (add_grp_line): Ditto.
+       (parse_passwd): Define as returning boolean.  Accept void * arg and line
+       count.  Coerce first argument into passwd buf reference.  Increment
+       curr_line as appropriate.
+       (read_etc_group): Pass pwdgrp buffer to pr.load.
+       * path.cc (etc::fn): Extend buffer size to allow index by 1 rather than
+       zero.
+       (etc::last_modified): Ditto.
+       (etc::change_possible): Ditto.  Renamed from sawchange.  Change to
+       signed char since elements are now tri-state.
+       (etc::init): Assume "handle" is 1 based rather than 0.
+       (etc::test_file_change): New function.  Sets change_possible based on
+       file date comparison.
+       (etc::dir_changed): Check file states immediately after changed_h is
+       initialized to avoid a race.
+       (etc::file_changed): Use test_file_change to detect if file needs to be
+       updated.
+       * path.h (etc): Move class here from pwdgrp.h.
+
+       * uinfo.cc: Move etc:: functions to path.cc.  Move pwdgrp functions
+       here.
+       (pwdgrp::gets): Eliminate buf checks.  Just check eptr and set lptr.
+       (pwdgrp::add_line): New function.
+       (pwdgrp::load): Call generic add_line function which will call correct
+       parser.
+
 2003-01-17  Christopher Faylor  <cgf@redhat.com>
 
        * cygheap.cc: Change most 'int's to 'unsigned's.
index 85ec51d..dc13304 100644 (file)
@@ -26,27 +26,22 @@ details. */
 #include "cygheap.h"
 #include "pwdgrp.h"
 
-/* Read /etc/group only once for better performance.  This is done
-   on the first call that needs information from it. */
-
-static struct __group32 NO_COPY *group_buf;            /* group contents in memory */
-static int NO_COPY curr_lines;
-static int NO_COPY max_lines;
-
 /* Position in the group cache */
 #define grp_pos _reent_winsup ()->_grp_pos
 
-static pwdgrp NO_COPY gr;
+static pwdgrp gr;
+static __group32 *group_buf;
 static char * NO_COPY null_ptr;
 
-static int
-parse_grp (struct __group32 &grp, char *line)
+bool
+pwdgrp::parse_grp (char *line)
 {
   char *dp = strchr (line, ':');
 
   if (!dp)
-    return 0;
+    return false;
 
+# define grp (* group_buf)[curr_lines]
   *dp++ = '\0';
   grp.gr_name = line;
 
@@ -80,23 +75,12 @@ parse_grp (struct __group32 &grp, char *line)
                  grp.gr_mem = namearray;
                }
            }
-         return 1;
+         curr_lines++;
+         return true;
        }
     }
-  return 0;
-}
-
-/* Read one line from /etc/group into the group cache */
-static void
-add_grp_line (char *line)
-{
-    if (curr_lines == max_lines)
-      {
-       max_lines += 10;
-       group_buf = (struct __group32 *) realloc (group_buf, max_lines * sizeof (struct __group32));
-      }
-    if (parse_grp (group_buf[curr_lines], line))
-      curr_lines++;
+  return false;
+# undef grp
 }
 
 class group_lock
@@ -130,12 +114,11 @@ read_etc_group ()
   /* if we got blocked by the mutex, then etc_group may have been processed */
   if (gr.isinitializing ())
     {
-      for (int i = 0; i < curr_lines; i++)
+      for (int i = 0; i < gr.curr_lines; i++)
        if ((group_buf + i)->gr_mem != &null_ptr)
          free ((group_buf + i)->gr_mem);
 
-      curr_lines = 0;
-      if (!gr.load ("/etc/group", add_grp_line))
+      if (!gr.load ("/etc/group", group_buf))
        debug_printf ("gr.load failed");
 
       /* Complete /etc/group in memory if needed */
@@ -156,11 +139,11 @@ read_etc_group ()
          snprintf (linebuf, sizeof (linebuf), "%s:%s:%lu:%s",
                    group_name, strbuf, myself->gid, cygheap->user.name ());
          debug_printf ("Completing /etc/group: %s", linebuf);
-         add_grp_line (linebuf);
+         gr.add_line (linebuf);
        }
       static char NO_COPY pretty_ls[] = "????????::-1:";
       if (wincap.has_security ())
-       add_grp_line (pretty_ls);
+       gr.add_line (pretty_ls);
     }
   return;
 }
@@ -174,7 +157,7 @@ internal_getgrsid (cygsid &sid)
     read_etc_group ();
 
   if (sid.string (sid_string))
-    for (int i = 0; i < curr_lines; i++)
+    for (int i = 0; i < gr.curr_lines; i++)
       if (!strcmp (sid_string, group_buf[i].gr_passwd))
         return group_buf + i;
   return NULL;
@@ -186,7 +169,7 @@ internal_getgrgid (__gid32_t gid, bool check)
   if (gr.isuninitialized () || (check && gr.isinitializing ()))
     read_etc_group ();
 
-  for (int i = 0; i < curr_lines; i++)
+  for (int i = 0; i < gr.curr_lines; i++)
     if (group_buf[i].gr_gid == gid)
       return group_buf + i;
   return NULL;
@@ -198,7 +181,7 @@ internal_getgrnam (const char *name, bool check)
   if (gr.isuninitialized () || (check && gr.isinitializing ()))
     read_etc_group ();
 
-  for (int i = 0; i < curr_lines; i++)
+  for (int i = 0; i < gr.curr_lines; i++)
     if (strcasematch (group_buf[i].gr_name, name))
       return group_buf + i;
 
@@ -206,8 +189,7 @@ internal_getgrnam (const char *name, bool check)
   return NULL;
 }
 
-static
-struct __group16 *
+static struct __group16 *
 grp32togrp16 (struct __group16 *gp16, struct __group32 *gp32)
 {
   if (!gp16 || !gp32)
@@ -263,7 +245,7 @@ getgrent32 ()
   if (gr.isinitializing ())
     read_etc_group ();
 
-  if (grp_pos < curr_lines)
+  if (grp_pos < gr.curr_lines)
     return group_buf + grp_pos++;
 
   return NULL;
@@ -290,7 +272,7 @@ internal_getgrent (int pos)
   if (gr.isuninitialized ())
     read_etc_group ();
 
-  if (pos < curr_lines)
+  if (pos < gr.curr_lines)
     return group_buf + pos;
   return NULL;
 }
index 113255a..91cbfa6 100644 (file)
@@ -26,11 +26,8 @@ details. */
 /* Read /etc/passwd only once for better performance.  This is done
    on the first call that needs information from it. */
 
-static struct passwd NO_COPY *passwd_buf;      /* passwd contents in memory */
-static int NO_COPY curr_lines;
-static int NO_COPY max_lines;
-
-static NO_COPY pwdgrp pr;
+static pwdgrp pr;
+passwd *passwd_buf;
 
 /* Position in the passwd cache */
 #define pw_pos  _reent_winsup ()->_pw_pos
@@ -65,9 +62,10 @@ grab_int (char **p)
 }
 
 /* Parse /etc/passwd line into passwd structure. */
-static int
-parse_pwd (struct passwd &res, char *buf)
+bool
+pwdgrp::parse_pwd (char *buf)
 {
+# define res (*passwd_buf)[curr_lines]
   /* Allocate enough room for the passwd struct and all the strings
      in it in one go */
   res.pw_name = grab_string (&buf);
@@ -75,25 +73,14 @@ parse_pwd (struct passwd &res, char *buf)
   res.pw_uid = grab_int (&buf);
   res.pw_gid = grab_int (&buf);
   if (!*buf)
-    return 0;
+    return false;
   res.pw_comment = 0;
   res.pw_gecos = grab_string (&buf);
   res.pw_dir =  grab_string (&buf);
   res.pw_shell = grab_string (&buf);
-  return 1;
-}
-
-/* Add one line from /etc/passwd into the password cache */
-static void
-add_pwd_line (char *line)
-{
-    if (curr_lines >= max_lines)
-      {
-       max_lines += 10;
-       passwd_buf = (struct passwd *) realloc (passwd_buf, max_lines * sizeof (struct passwd));
-      }
-    if (parse_pwd (passwd_buf[curr_lines], line))
-      curr_lines++;
+  curr_lines++;
+  return true;
+# undef res
 }
 
 class passwd_lock
@@ -131,8 +118,7 @@ read_etc_passwd ()
   /* if we got blocked by the mutex, then etc_passwd may have been processed */
   if (pr.isinitializing ())
     {
-      curr_lines = 0;
-      if (!pr.load ("/etc/passwd", add_pwd_line))
+      if (!pr.load ("/etc/passwd", passwd_buf))
        debug_printf ("pr.load failed");
 
       char strbuf[128] = "";
@@ -141,8 +127,8 @@ read_etc_passwd ()
 
       if (wincap.has_security ())
        {
-         static char pretty_ls[] = "????????:*:-1:-1:";
-         add_pwd_line (pretty_ls);
+         static char NO_COPY pretty_ls[] = "????????:*:-1:-1:";
+         pr.add_line (pretty_ls);
          cygsid tu = cygheap->user.sid ();
          tu.string (strbuf);
          if (myself->uid == ILLEGAL_UID)
@@ -164,7 +150,7 @@ read_etc_passwd ()
                    myself->gid,
                    strbuf, getenv ("HOME") ?: "");
          debug_printf ("Completing /etc/passwd: %s", linebuf);
-         add_pwd_line (linebuf);
+         pr.add_line (linebuf);
        }
     }
   return;
@@ -183,7 +169,7 @@ internal_getpwsid (cygsid &sid)
   if (sid.string (sid_string + 2))
     {
       endptr = strchr (sid_string + 2, 0) - 1;
-      for (int i = 0; i < curr_lines; i++)
+      for (int i = 0; i < pr.curr_lines; i++)
        if ((pw = passwd_buf + i)->pw_dir > pw->pw_gecos + 8)
          for (ptr1 = endptr, ptr2 = pw->pw_dir - 2;
               *ptr1 == *ptr2; ptr2--)
@@ -199,7 +185,7 @@ internal_getpwuid (__uid32_t uid, bool check)
   if (pr.isuninitialized () || (check && pr.isinitializing ()))
     read_etc_passwd ();
 
-  for (int i = 0; i < curr_lines; i++)
+  for (int i = 0; i < pr.curr_lines; i++)
     if (uid == (__uid32_t) passwd_buf[i].pw_uid)
       return passwd_buf + i;
   return NULL;
@@ -211,7 +197,7 @@ internal_getpwnam (const char *name, bool check)
   if (pr.isuninitialized () || (check && pr.isinitializing ()))
     read_etc_passwd ();
 
-  for (int i = 0; i < curr_lines; i++)
+  for (int i = 0; i < pr.curr_lines; i++)
     /* on Windows NT user names are case-insensitive */
     if (strcasematch (name, passwd_buf[i].pw_name))
       return passwd_buf + i;
@@ -333,7 +319,7 @@ getpwent (void)
   if (pr.isinitializing ())
     read_etc_passwd ();
 
-  if (pw_pos < curr_lines)
+  if (pw_pos < pr.curr_lines)
     return passwd_buf + pw_pos++;
 
   return NULL;
index aeeea9d..835fa98 100644 (file)
@@ -3753,3 +3753,104 @@ out:
   MALLOC_CHECK;
   return buf;
 }
+
+int etc::curr_ix = 0;
+/* Note that the first elements of the below arrays are unused */
+signed char etc::change_possible[MAX_ETC_FILES + 1];
+const char *etc::fn[MAX_ETC_FILES + 1];
+FILETIME etc::last_modified[MAX_ETC_FILES + 1];
+
+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;
+  change_possible[n] = false;
+  (void) test_file_change (n);
+  paranoid_printf ("fn[%d] %s, curr_ix %d", n, fn[n], curr_ix);
+  return n;
+}
+
+bool
+etc::test_file_change (int n)
+{
+  HANDLE h;
+  WIN32_FIND_DATA data;
+  bool res;
+
+  if (change_possible[n] < 0)
+    {
+      res = true;
+      paranoid_printf ("fn[%d] %s, already marked changed", n, fn[n]);
+    }
+  else if ((h = FindFirstFile (fn[n], &data)) == INVALID_HANDLE_VALUE)
+    {
+      res = true;
+      memset (last_modified + n, 0, sizeof (last_modified[n]));
+      debug_printf ("FindFirstFile failed, %E");
+    }
+  else
+    {
+      FindClose (h);
+      res = CompareFileTime (&data.ftLastWriteTime, last_modified + n) > 0;
+      last_modified[n] = data.ftLastWriteTime;
+      change_possible[n] = -res;
+      debug_printf ("FindFirstFile succeeded");
+    }
+
+  paranoid_printf ("fn[%d] %s res %d", n, fn[n], res);
+  return res;
+}
+
+bool
+etc::dir_changed (int n)
+{
+  if (!change_possible[n])
+    {
+      static HANDLE changed_h NO_COPY;
+
+      if (!changed_h)
+       {
+         path_conv pwd ("/etc");
+         changed_h = FindFirstChangeNotification (pwd, FALSE,
+                                                 FILE_NOTIFY_CHANGE_LAST_WRITE);
+#ifdef DEBUGGING
+         if (changed_h == INVALID_HANDLE_VALUE)
+           system_printf ("Can't open /etc for checking, %E", (char *) pwd,
+                          changed_h);
+#endif
+         for (int i = 1; i <= curr_ix; i++)
+           (void) test_file_change (i);
+       }
+
+      if (changed_h == INVALID_HANDLE_VALUE)
+       (void) test_file_change (n);    /* semi-brute-force way */
+      else if (WaitForSingleObject (changed_h, 0) == WAIT_OBJECT_0)
+       {
+         (void) FindNextChangeNotification (changed_h);
+         memset (change_possible, 1, sizeof change_possible);
+       }
+    }
+
+  paranoid_printf ("fn[%d] %s change_possible %d", n, fn[n], change_possible[n]);
+  return change_possible[n];
+}
+
+bool
+etc::file_changed (int n)
+{
+  bool res = false;
+  if (!fn[n])
+    res = true;
+  else if (dir_changed (n) && test_file_change (n))
+    res = true;
+  change_possible[n] = 0;
+  paranoid_printf ("fn[%d] %s res %d", n, fn[n], res);
+  return res;
+}
index 9d8291a..7fab204 100644 (file)
@@ -206,3 +206,20 @@ int pathmatch (const char *path1, const char *path2) __attribute__ ((regparm (2)
 int pathnmatch (const char *path1, const char *path2, int len) __attribute__ ((regparm (2)));
 
 int path_prefix_p (const char *path1, const char *path2, int len1) __attribute__ ((regparm (3)));
+
+/* FIXME: Move to own include file eventually */
+
+#define MAX_ETC_FILES 2
+class etc
+{
+  static int curr_ix;
+  static signed char change_possible[MAX_ETC_FILES + 1];
+  static const char *fn[MAX_ETC_FILES + 1];
+  static FILETIME last_modified[MAX_ETC_FILES + 1];
+  static bool dir_changed (int);
+  static int init (int, const char *);
+  static bool file_changed (int);
+  static void set_last_modified (int, FILETIME&);
+  static bool test_file_change (int);
+  friend class pwdgrp;
+};
index 7f7434b..07a618c 100644 (file)
@@ -27,106 +27,54 @@ enum pwdgrp_state {
   loaded
 };
 
-#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 ()
+  int max_lines;
+  union
   {
-    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;
-  }
+    passwd **passwd_buf;
+    __group32 **group_buf;
+    void **pwdgrp_buf;
+  };
+  unsigned pwdgrp_buf_elem_size;
+  bool (pwdgrp::*parse) (char *);
+
+  char *gets (char*&);
+  bool parse_pwd (char *);
+  bool parse_grp (char *);
 
 public:
+  int curr_lines;
+
+  void add_line (char *);
   bool isinitializing ()
-    {
-      if (state <= initializing)
-       state = initializing;
-      else if (etc::file_changed (pwd_ix - 1))
-       state = initializing;
-      return state == initializing;
-    }
+  {
+    if (state <= initializing)
+      state = initializing;
+    else if (etc::file_changed (pwd_ix))
+      state = initializing;
+    return state == initializing;
+  }
   void operator = (pwdgrp_state nstate) { state = nstate; }
   bool isuninitialized () const { return state == uninitialized; }
 
-  bool load (const char *posix_fname, void (* add_line) (char *))
+  bool load (const char *);
+  bool load (const char *posix_fname, passwd *&buf)
   {
-    if (buf)
-      free (buf);
-    buf = lptr = eptr = NULL;
-
-    pc.check (posix_fname);
-    pwd_ix = etc::init (pwd_ix - 1, pc) + 1;
-
-    paranoid_printf ("%s", posix_fname);
-
-    bool res;
-    if (pc.error || !pc.exists () || !pc.isdisk () || pc.isdir ())
-      res = false;
-    else
-      {
-       HANDLE fh = CreateFile (pc, GENERIC_READ, wincap.shared (), NULL,
-                               OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
-       if (fh == INVALID_HANDLE_VALUE)
-         res = false;
-       else
-         {
-           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);
-           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;
-         }
-      }
-
-    state = loaded;
-    return res;
+    passwd_buf = &buf;
+    pwdgrp_buf_elem_size = sizeof (*buf);
+    parse = &pwdgrp::parse_pwd;
+    return load (posix_fname);
+  }
+  bool load (const char *posix_fname, __group32 *&buf)
+  {
+    group_buf = &buf;
+    pwdgrp_buf_elem_size = sizeof (*buf);
+    parse = &pwdgrp::parse_grp;
+    return load (posix_fname);
   }
 };
index 438ff4a..868fc7d 100644 (file)
@@ -390,89 +390,87 @@ cygheap_user::env_name (const char *name, size_t namelen)
   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)
+char *
+pwdgrp::gets (char*& eptr)
 {
-  if (n >= 0)
-    /* ok */;
-  else if (++curr_ix < MAX_ETC_FILES)
-    n = curr_ix;
+  char *lptr;
+  if (!eptr)
+    lptr = NULL;
   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);
-#ifdef DEBUGGING
-         if (changed_h == INVALID_HANDLE_VALUE)
-           system_printf ("Can't open /etc for checking, %E", (char *) pwd,
-                          changed_h);
-#endif
-       }
-
-      if (changed_h == INVALID_HANDLE_VALUE)
-       res = true;
-      else if (WaitForSingleObject (changed_h, 0) == WAIT_OBJECT_0)
+      lptr = eptr;
+      eptr = strchr (lptr, '\n');
+      if (eptr)
        {
-         (void) FindNextChangeNotification (changed_h);
-         memset (sawchange, true, sizeof sawchange);
-         res = true;
+         if (eptr > lptr && *(eptr - 1) == '\r')
+           *(eptr - 1) = 0;
+         *eptr++ = '\0';
        }
     }
+  return lptr;
+}
 
-  paranoid_printf ("%s res %d", fn[n], res);
-  return res;
+void
+pwdgrp::add_line (char *line)
+{
+  if (curr_lines >= max_lines)
+    {
+      max_lines += 10;
+      *pwdgrp_buf = realloc (*pwdgrp_buf, max_lines * pwdgrp_buf_elem_size);
+    }
+  (void) (this->*parse) (line);
 }
 
 bool
-etc::file_changed (int n)
+pwdgrp::load (const char *posix_fname)
 {
-  bool res = false;
-  if (!fn[n])
-    res = true;
-  else if (dir_changed (n))
-    {
-      HANDLE h;
-      WIN32_FIND_DATA data;
+  if (buf)
+    free (buf);
+  buf = NULL;
+
+  pc.check (posix_fname);
+  pwd_ix = etc::init (pwd_ix, pc);
+
+  paranoid_printf ("%s", posix_fname);
 
-      if ((h = FindFirstFile (fn[n], &data)) == INVALID_HANDLE_VALUE)
-       res = true;
+  bool res;
+  if (pc.error || !pc.exists () || !pc.isdisk () || pc.isdir ())
+    res = false;
+  else
+    {
+      HANDLE fh = CreateFile (pc, GENERIC_READ, wincap.shared (), NULL,
+                             OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
+      if (fh == INVALID_HANDLE_VALUE)
+       res = false;
       else
        {
-         FindClose (h);
-         if (CompareFileTime (&data.ftLastWriteTime, last_modified + n) > 0)
-           res = true;
+         DWORD size = GetFileSize (fh, NULL), read_bytes;
+         buf = (char *) malloc (size + 1);
+         if (!ReadFile (fh, buf, size, &read_bytes, NULL))
+           {
+             CloseHandle (fh);
+             if (buf)
+               free (buf);
+             buf = NULL;
+             fh = NULL;
+             res = false;
+           }
+         else
+           {
+             CloseHandle (fh);
+             buf[read_bytes] = '\0';
+             char *eptr = buf;
+             eptr = buf;
+             char *line;
+             curr_lines = 0;
+             while ((line = gets (eptr)) != NULL)
+               add_line (line);
+             debug_printf ("%s curr_lines %d", posix_fname, curr_lines);
+             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;
+  state = loaded;
+  return res;
 }