From 7905c4f158c479c3d08e112c55f91be38aa70dae Mon Sep 17 00:00:00 2001 From: Christopher Faylor Date: Mon, 20 Jan 2003 02:57:54 +0000 Subject: [PATCH] * 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. --- winsup/cygwin/ChangeLog | 51 ++++++++++++++ winsup/cygwin/grp.cc | 58 ++++++---------- winsup/cygwin/passwd.cc | 48 +++++-------- winsup/cygwin/path.cc | 101 +++++++++++++++++++++++++++ winsup/cygwin/path.h | 17 +++++ winsup/cygwin/pwdgrp.h | 122 ++++++++++----------------------- winsup/cygwin/uinfo.cc | 148 ++++++++++++++++++++-------------------- 7 files changed, 314 insertions(+), 231 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 00936c30d..8d17d97af 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,54 @@ +2003-01-19 Christopher Faylor + + * 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 * cygheap.cc: Change most 'int's to 'unsigned's. diff --git a/winsup/cygwin/grp.cc b/winsup/cygwin/grp.cc index 85ec51dc6..dc1330429 100644 --- a/winsup/cygwin/grp.cc +++ b/winsup/cygwin/grp.cc @@ -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; } diff --git a/winsup/cygwin/passwd.cc b/winsup/cygwin/passwd.cc index 113255afb..91cbfa62f 100644 --- a/winsup/cygwin/passwd.cc +++ b/winsup/cygwin/passwd.cc @@ -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; diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index aeeea9d87..835fa9838 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -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; +} diff --git a/winsup/cygwin/path.h b/winsup/cygwin/path.h index 9d8291a59..7fab2044d 100644 --- a/winsup/cygwin/path.h +++ b/winsup/cygwin/path.h @@ -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; +}; diff --git a/winsup/cygwin/pwdgrp.h b/winsup/cygwin/pwdgrp.h index 7f7434b80..07a618ce1 100644 --- a/winsup/cygwin/pwdgrp.h +++ b/winsup/cygwin/pwdgrp.h @@ -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); } }; diff --git a/winsup/cygwin/uinfo.cc b/winsup/cygwin/uinfo.cc index 438ff4a45..868fc7d96 100644 --- a/winsup/cygwin/uinfo.cc +++ b/winsup/cygwin/uinfo.cc @@ -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) + lptr = eptr; + eptr = strchr (lptr, '\n'); + if (eptr) { - 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) - { - (void) FindNextChangeNotification (changed_h); - memset (sawchange, true, sizeof sawchange); - res = true; + if (eptr > lptr && *(eptr - 1) == '\r') + *(eptr - 1) = 0; + *eptr++ = '\0'; } } - - 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; + return lptr; } void -etc::set_last_modified (int n, FILETIME& ft) +pwdgrp::add_line (char *line) { - last_modified[n] = ft; - sawchange[n] = false; + if (curr_lines >= max_lines) + { + max_lines += 10; + *pwdgrp_buf = realloc (*pwdgrp_buf, max_lines * pwdgrp_buf_elem_size); + } + (void) (this->*parse) (line); +} + +bool +pwdgrp::load (const char *posix_fname) +{ + if (buf) + free (buf); + buf = NULL; + + pc.check (posix_fname); + pwd_ix = etc::init (pwd_ix, pc); + + 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)) + { + 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; + } + } + } + + state = loaded; + return res; }