From fb441e4efd6e89d918c17d42206a95ef66e0bf90 Mon Sep 17 00:00:00 2001
From: rswindell <>
Date: Mon, 7 Dec 2015 09:16:05 +0000
Subject: [PATCH] Split getuserdat() into 3 functions: - openuserdat() -
 readuserdat() - parseuserdat()

getuserdat() still exists and just calls those 3 functions. This allows other
code (e.g. the control panel) to optimize iterative calls to getuserdat() by
opening the file just once or even reading the entire contents at once and then
parsing each user record from memory.

Updated style of arguments in userdat.h (i.e. remove argument name if obvious
from the type).
---
 src/sbbs3/userdat.c | 100 ++++++++++++++++++++++++++++++++++----------
 src/sbbs3/userdat.h |  77 ++++++++++++++++++----------------
 2 files changed, 118 insertions(+), 59 deletions(-)

diff --git a/src/sbbs3/userdat.c b/src/sbbs3/userdat.c
index e1ce249401..5a783de9f9 100644
--- a/src/sbbs3/userdat.c
+++ b/src/sbbs3/userdat.c
@@ -193,34 +193,45 @@ BOOL DLLCALL del_lastuser(scfg_t* cfg)
 	return(TRUE);
 }
 
-
 /****************************************************************************/
-/* Fills the structure 'user' with info for user.number	from user.dat		*/
-/* Called from functions useredit, waitforcall and main_sec					*/
+/* Opens the user database returning the file descriptor or -1 on error		*/
 /****************************************************************************/
-int DLLCALL getuserdat(scfg_t* cfg, user_t *user)
+int DLLCALL openuserdat(scfg_t* cfg)
 {
-	char userdat[U_LEN+1],str[U_LEN+1];
-	int i,file;
-	unsigned user_number;
+	char path[MAX_PATH+1];
 
-	if(user==NULL)
-		return(-1);
+	if(!VALID_CFG(cfg))
+		return(-1); 
 
-	user_number=user->number;
-	memset(user,0,sizeof(user_t));
+	SAFEPRINTF(path,"%suser/user.dat",cfg->data_dir);
+	return nopen(path,O_RDONLY|O_DENYNONE); 
+}
+
+/****************************************************************************/
+/* Locks and reads a single user record from an open user.dat file into a	*/
+/* buffer of U_LEN+1 in size.												*/
+/* Returns 0 on success.													*/
+/****************************************************************************/
+int DLLCALL readuserdat(scfg_t* cfg, unsigned user_number, char* userdat, int infile)
+{
+	int i,file;
 
 	if(!VALID_CFG(cfg) || user_number<1)
 		return(-1); 
 
-	SAFEPRINTF(userdat,"%suser/user.dat",cfg->data_dir);
-	if((file=nopen(userdat,O_RDONLY|O_DENYNONE))==-1)
-		return(errno); 
+	if(infile > 0)
+		file = infile;
+	else {
+		if((file = openuserdat(cfg)) < 0)
+			return file;
+	}
 
 	if(user_number > (unsigned)(filelength(file)/U_LEN)) {
-		close(file);
+		if(file != infile)
+			close(file);
 		return(-1);	/* no such user record */
 	}
+
 	lseek(file,(long)((long)(user_number-1)*U_LEN),SEEK_SET);
 	i=0;
 	while(i<LOOP_NODEDAB
@@ -229,21 +240,43 @@ int DLLCALL getuserdat(scfg_t* cfg, user_t *user)
 			mswait(100);
 		i++; 
 	}
-
 	if(i>=LOOP_NODEDAB) {
-		close(file);
+		if(file != infile)
+			close(file);
 		return(-2); 
 	}
 
 	if(read(file,userdat,U_LEN)!=U_LEN) {
 		unlock(file,(long)((long)(user_number-1)*U_LEN),U_LEN);
-		close(file);
+		if(file != infile)
+			close(file);
 		return(-3); 
 	}
-
 	unlock(file,(long)((long)(user_number-1)*U_LEN),U_LEN);
-	close(file);
+	if(file != infile)
+		close(file);
+	return 0;
+}
+
+/****************************************************************************/
+/* Fills the structure 'user' with info for user.number	from userdat		*/
+/* (a buffer representing a single user 'record' from the user.dat file		*/
+/****************************************************************************/
+int DLLCALL parseuserdat(scfg_t* cfg, char *userdat, user_t *user)
+{
+	char str[U_LEN+1];
+	int i;
+	unsigned user_number;
+
+	if(user==NULL)
+		return(-1);
+
+	user_number=user->number;
+	memset(user,0,sizeof(user_t));
 
+	if(!VALID_CFG(cfg) || user_number < 1)
+		return(-1); 
+	
 	/* The user number needs to be set here
 	   before calling chk_ar() below for user-number comparisons in AR strings to function correctly */
 	user->number=user_number;	/* Signal of success */
@@ -352,7 +385,6 @@ int DLLCALL getuserdat(scfg_t* cfg, user_t *user)
 
 	getrec(userdat,U_CHAT,8,str);
 	user->chat=ahtoul(str);
-
 	/* Reset daily stats if not already logged on today */
 	if(user->ltoday || user->etoday || user->ptoday || user->ttoday) {
 		time_t		now;
@@ -368,10 +400,34 @@ int DLLCALL getuserdat(scfg_t* cfg, user_t *user)
 				resetdailyuserdat(cfg,user,/* write: */FALSE);
 		}
 	}
-
 	return(0);
 }
 
+/****************************************************************************/
+/* Fills the structure 'user' with info for user.number	from user.dat file	*/
+/****************************************************************************/
+int DLLCALL getuserdat(scfg_t* cfg, user_t *user)
+{
+	int		retval;
+	int		file;
+	char	userdat[U_LEN+1];
+
+	if(!VALID_CFG(cfg) || user==NULL || user->number < 1)
+		return(-1); 
+
+	if((file = openuserdat(cfg)) < 0)
+		return file;
+
+	memset(userdat, 0, sizeof(userdat));
+	if((retval = readuserdat(cfg, user->number, userdat, file)) != 0) {
+		close(file);
+		return retval;
+	}
+	retval = parseuserdat(cfg, userdat, user);
+	close(file);
+	return retval;
+}
+
 /****************************************************************************/
 /****************************************************************************/
 static void dirtyuserdat(scfg_t* cfg, uint usernumber)
diff --git a/src/sbbs3/userdat.h b/src/sbbs3/userdat.h
index 0e02a5e86b..0f8496aad4 100644
--- a/src/sbbs3/userdat.h
+++ b/src/sbbs3/userdat.h
@@ -77,33 +77,36 @@ extern "C" {
 extern char* crlf;
 extern char* nulstr;
 
-DLLEXPORT int	DLLCALL getuserdat(scfg_t* cfg, user_t* user); 	/* Fill userdat struct with user data   */
-DLLEXPORT int	DLLCALL putuserdat(scfg_t* cfg, user_t* user);	/* Put userdat struct into user file	*/
-DLLEXPORT int	DLLCALL newuserdat(scfg_t* cfg, user_t* user);	/* Create new userdat in user file */
-DLLEXPORT uint	DLLCALL matchuser(scfg_t* cfg, const char *str, BOOL sysop_alias); /* Checks for a username match */
-DLLEXPORT char* DLLCALL alias(scfg_t* cfg, const char* name, char* buf);
-DLLEXPORT int	DLLCALL putusername(scfg_t* cfg, int number, char * name);
-DLLEXPORT uint	DLLCALL total_users(scfg_t* cfg);
-DLLEXPORT uint	DLLCALL lastuser(scfg_t* cfg);
-DLLEXPORT BOOL	DLLCALL del_lastuser(scfg_t* cfg);
-DLLEXPORT uint	DLLCALL getage(scfg_t* cfg, char *birthdate);
-DLLEXPORT char*	DLLCALL username(scfg_t* cfg, int usernumber, char * str);
-DLLEXPORT char* DLLCALL usermailaddr(scfg_t* cfg, char* addr, const char* name);
-DLLEXPORT int	DLLCALL getnodedat(scfg_t* cfg, uint number, node_t *node, int* file);
-DLLEXPORT int	DLLCALL putnodedat(scfg_t* cfg, uint number, node_t *node, int file);
-DLLEXPORT char* DLLCALL nodestatus(scfg_t* cfg, node_t* node, char* buf, size_t buflen);
-DLLEXPORT void	DLLCALL printnodedat(scfg_t* cfg, uint number, node_t* node);
+DLLEXPORT int	DLLCALL openuserdat(scfg_t*);
+DLLEXPORT int	DLLCALL readuserdat(scfg_t*, unsigned user_number, char* userdat, int infile);
+DLLEXPORT int	DLLCALL parseuserdat(scfg_t*, char* userdat, user_t*);
+DLLEXPORT int	DLLCALL getuserdat(scfg_t*, user_t*); 	/* Fill userdat struct with user data   */
+DLLEXPORT int	DLLCALL putuserdat(scfg_t*, user_t*);	/* Put userdat struct into user file	*/
+DLLEXPORT int	DLLCALL newuserdat(scfg_t*, user_t*);	/* Create new userdat in user file */
+DLLEXPORT uint	DLLCALL matchuser(scfg_t*, const char *str, BOOL sysop_alias); /* Checks for a username match */
+DLLEXPORT char* DLLCALL alias(scfg_t*, const char* name, char* buf);
+DLLEXPORT int	DLLCALL putusername(scfg_t*, int number, char * name);
+DLLEXPORT uint	DLLCALL total_users(scfg_t*);
+DLLEXPORT uint	DLLCALL lastuser(scfg_t*);
+DLLEXPORT BOOL	DLLCALL del_lastuser(scfg_t*);
+DLLEXPORT uint	DLLCALL getage(scfg_t*, char *birthdate);
+DLLEXPORT char*	DLLCALL username(scfg_t*, int usernumber, char * str);
+DLLEXPORT char* DLLCALL usermailaddr(scfg_t*, char* addr, const char* name);
+DLLEXPORT int	DLLCALL getnodedat(scfg_t*, uint number, node_t *node, int* file);
+DLLEXPORT int	DLLCALL putnodedat(scfg_t*, uint number, node_t *node, int file);
+DLLEXPORT char* DLLCALL nodestatus(scfg_t*, node_t* node, char* buf, size_t buflen);
+DLLEXPORT void	DLLCALL printnodedat(scfg_t*, uint number, node_t* node);
 DLLEXPORT void	DLLCALL packchatpass(char *pass, node_t* node);
 DLLEXPORT char* DLLCALL unpackchatpass(char *pass, node_t* node);
-DLLEXPORT char* DLLCALL getsmsg(scfg_t* cfg, int usernumber);
-DLLEXPORT int	DLLCALL putsmsg(scfg_t* cfg, int usernumber, char *strin);
-DLLEXPORT char* DLLCALL getnmsg(scfg_t* cfg, int node_num);
-DLLEXPORT int	DLLCALL putnmsg(scfg_t* cfg, int num, char *strin);
+DLLEXPORT char* DLLCALL getsmsg(scfg_t*, int usernumber);
+DLLEXPORT int	DLLCALL putsmsg(scfg_t*, int usernumber, char *strin);
+DLLEXPORT char* DLLCALL getnmsg(scfg_t*, int node_num);
+DLLEXPORT int	DLLCALL putnmsg(scfg_t*, int num, char *strin);
 
-DLLEXPORT uint	DLLCALL userdatdupe(scfg_t* cfg, uint usernumber, uint offset, uint datlen, char *dat
+DLLEXPORT uint	DLLCALL userdatdupe(scfg_t*, uint usernumber, uint offset, uint datlen, char *dat
 							,BOOL del, BOOL next);
 
-DLLEXPORT BOOL	DLLCALL chk_ar(scfg_t* cfg, uchar* str, user_t*, client_t*); /* checks access requirements */
+DLLEXPORT BOOL	DLLCALL chk_ar(scfg_t*, uchar* str, user_t*, client_t*); /* checks access requirements */
 
 DLLEXPORT int	DLLCALL getuserrec(scfg_t*, int usernumber, int start, int length, char *str);
 DLLEXPORT int	DLLCALL putuserrec(scfg_t*, int usernumber, int start, uint length, const char *str);
@@ -112,13 +115,13 @@ DLLEXPORT BOOL	DLLCALL logoutuserdat(scfg_t*, user_t*, time_t now, time_t logont
 DLLEXPORT void	DLLCALL resetdailyuserdat(scfg_t*, user_t*, BOOL write);
 DLLEXPORT void	DLLCALL subtract_cdt(scfg_t*, user_t*, long amt);
 DLLEXPORT int	DLLCALL user_rec_len(int offset);
-DLLEXPORT BOOL	DLLCALL can_user_access_sub(scfg_t* cfg, uint subnum, user_t* user, client_t* client);
-DLLEXPORT BOOL	DLLCALL can_user_read_sub(scfg_t* cfg, uint subnum, user_t* user, client_t* client);
-DLLEXPORT BOOL	DLLCALL can_user_post(scfg_t* cfg, uint subnum, user_t* user, client_t* client, uint* reason);
-DLLEXPORT BOOL	DLLCALL can_user_send_mail(scfg_t* cfg, enum smb_net_type, uint usernumber, user_t* user, uint* reason);
-DLLEXPORT BOOL	DLLCALL is_user_subop(scfg_t* cfg, uint subnum, user_t* user, client_t* client);
-DLLEXPORT BOOL	DLLCALL is_download_free(scfg_t* cfg, uint dirnum, user_t* user, client_t* client);
-DLLEXPORT BOOL	DLLCALL filter_ip(scfg_t* cfg, const char* prot, const char* reason, const char* host
+DLLEXPORT BOOL	DLLCALL can_user_access_sub(scfg_t*, uint subnum, user_t*, client_t* client);
+DLLEXPORT BOOL	DLLCALL can_user_read_sub(scfg_t*, uint subnum, user_t*, client_t* client);
+DLLEXPORT BOOL	DLLCALL can_user_post(scfg_t*, uint subnum, user_t*, client_t* client, uint* reason);
+DLLEXPORT BOOL	DLLCALL can_user_send_mail(scfg_t*, enum smb_net_type, uint usernumber, user_t*, uint* reason);
+DLLEXPORT BOOL	DLLCALL is_user_subop(scfg_t*, uint subnum, user_t*, client_t* client);
+DLLEXPORT BOOL	DLLCALL is_download_free(scfg_t*, uint dirnum, user_t*, client_t* client);
+DLLEXPORT BOOL	DLLCALL filter_ip(scfg_t*, const char* prot, const char* reason, const char* host
 								  ,const char* ip_addr, const char* username, const char* fname);
 
 /* New-message-scan pointer functions: */
@@ -129,16 +132,16 @@ DLLEXPORT BOOL	DLLCALL initmsgptrs(scfg_t*, subscan_t*, unsigned days);
 
 
 /* New atomic numeric user field adjustment functions: */
-DLLEXPORT BOOL	DLLCALL user_posted_msg(scfg_t* cfg, user_t* user, int count);
-DLLEXPORT BOOL	DLLCALL user_sent_email(scfg_t* cfg, user_t* user, int count, BOOL feedback);
-DLLEXPORT BOOL	DLLCALL user_downloaded(scfg_t* cfg, user_t* user, int files, long bytes);
-DLLEXPORT BOOL	DLLCALL user_uploaded(scfg_t* cfg, user_t* user, int files, long bytes);
-DLLEXPORT BOOL	DLLCALL user_adjust_credits(scfg_t* cfg, user_t* user, long amount);
-DLLEXPORT BOOL	DLLCALL user_adjust_minutes(scfg_t* cfg, user_t* user, long amount);
+DLLEXPORT BOOL	DLLCALL user_posted_msg(scfg_t*, user_t*, int count);
+DLLEXPORT BOOL	DLLCALL user_sent_email(scfg_t*, user_t*, int count, BOOL feedback);
+DLLEXPORT BOOL	DLLCALL user_downloaded(scfg_t*, user_t*, int files, long bytes);
+DLLEXPORT BOOL	DLLCALL user_uploaded(scfg_t*, user_t*, int files, long bytes);
+DLLEXPORT BOOL	DLLCALL user_adjust_credits(scfg_t*, user_t*, long amount);
+DLLEXPORT BOOL	DLLCALL user_adjust_minutes(scfg_t*, user_t*, long amount);
 
-DLLEXPORT time_t DLLCALL gettimeleft(scfg_t* cfg, user_t* user, time_t starttime);
+DLLEXPORT time_t DLLCALL gettimeleft(scfg_t*, user_t*, time_t starttime);
 
-DLLEXPORT BOOL	DLLCALL check_name(scfg_t* cfg, const char* name);
+DLLEXPORT BOOL	DLLCALL check_name(scfg_t*, const char* name);
 
 /* Login attempt/hack tracking */
 typedef struct {
-- 
GitLab