1 /*****************************************************************
2 **	@(#) filep.c
3 *****************************************************************/
4 # include <sys/resource.h>
5 # include <stdio.h>
6 # include <stdlib.h>
7 # include <string.h>
8 # include <assert.h>
9 // # include <ctype.h>
10 
11 # include "debug.h"
12 #define extern
13 # include "filep.h"
14 #undef extern
15 
16 static	filep_t		filep[HASHSIZE];	/* the hash table */
17 static	int		filep_nofiles;		/* no of current open files in filep */
18 static	int		filep_maxfp;		/* no of max open files in filep */
19 static	const char	*filep_filemode;	/* filemode e.g. "w" or "a" */
20 static	const char	*filep_fnametmpl;	/* file name template e.g. "db%04x" or NULL*/
21 static	unsigned long	hashfunc (const char *val);
22 
filep_init(const char * fnametmpl,const char * filemode)23 int	filep_init (const char *fnametmpl, const char *filemode)
24 {
25 	int	i;
26 	struct  rlimit  rl;
27 
28 	if ( getrlimit (RLIMIT_NOFILE, &rl) < 0 )
29 	{
30 		fprintf (stderr, "Can't get max file limit\n");
31 		return 0;
32 	}
33 	// fprintf (stderr, "soft=%d hard=%d\n", rl.rlim_cur, rl.rlim_max);
34 	filep_nofiles = 0;		/* no of used slots in hash array */
35 	filep_maxfp = rl.rlim_cur;	/* curr limit of fd */
36 	filep_maxfp -= 3;		/* stdin, stdout, stderr */
37 	filep_maxfp -= 1;		/* reserve another one */
38 	filep_fnametmpl = fnametmpl;
39 	filep_filemode = filemode;
40 
41 	for ( i = 0; i < HASHSIZE; i++ )
42 	{
43 		filep[i].fp = NULL;
44 		filep[i].name = NULL;
45 		filep[i].zone = NULL;
46 	}
47 
48 	return filep_maxfp;
49 }
50 
filep_close(void)51 int	filep_close (void)
52 {
53 	int	i;
54 
55 	/* close all open filepointer */
56 	for ( i = 0; i < HASHSIZE; i++ )
57 	{
58 		if ( filep[i].fp )
59 		{
60 			fclose (filep[i].fp);
61 			filep_nofiles--;
62 		}
63 		if ( filep[i].name )
64 			free (filep[i].name);
65 	}
66 	//fprintf (stderr, "nofiles = %d\n", filep_nofiles);
67 	assert ( filep_nofiles == 0 );
68 
69 	return 1;
70 }
71 
filep_open(const char * name)72 FILE	*filep_open (const char *name)
73 {
74 	int	ind;
75 	int	loopcnt;
76 	unsigned long	hash;
77 	const	char	*fname;
78 	char	fnamebuf[MAXFNAME+1];
79 
80 	/* build hash from name (name is just the variable part of the filename) */
81 	hash = hashfunc (name);
82 
83 	/* looking for hash in filep array */
84 	ind = hash % (HASHSIZE);
85 	assert ( ind >= 0 && ind < HASHSIZE );
86 
87 	loopcnt = 0;		/* counter to detect if we are going another time through the hash list */
88 				/* This should never happen, it is just an "emergency break"  */
89 	while ( loopcnt < HASHSIZE && filep[ind].name != NULL && strcmp (filep[ind].name, name) != 0 )
90 	{
91 		if ( ++ind >= HASHSIZE )
92 			ind = 0;
93 		loopcnt++;
94 	}
95 	dbg_val2 ("loopcnt %d HASHSIZE %d\n", loopcnt, HASHSIZE);
96 	assert ( loopcnt < HASHSIZE );	/* this should never happen ! */
97 
98 	/* the slot for this file and the file is indeed open ? */
99 	if ( filep[ind].fp && filep[ind].name )
100 		return filep[ind].fp;
101 
102 	if ( filep_nofiles >= filep_maxfp )	/* no more filepointers available */
103 	{
104 		int	i;
105 
106 		/* free one entry */
107 		i = ind;
108 		do {
109 			if ( i > 0 )
110 				i--;
111 			else
112 				i = HASHSIZE - 1;
113 		} while ( filep[i].fp == NULL );
114 
115 		fclose (filep[i].fp);
116 		filep[i].fp = NULL;
117 		filep_nofiles--;
118 
119 		dbg_val3 ("%3d close (%d) (interim) file %s \n", filep_nofiles, i, filep[i].name);
120 	}
121 
122 	/* open or reopen the file */
123 	if ( filep_fnametmpl )		/* do we have a file name template ? */
124 	{
125 		snprintf (fnamebuf, sizeof (fnamebuf), filep_fnametmpl, name);	/* create the real name */
126 		fname = fnamebuf;
127 	}
128 	else
129 		fname = name;
130 
131 	if ( filep[ind].name == NULL )	/* this is the slot for the new file */
132 	{
133 		if ( filep_nofiles >= MAXFILEP )	/* no space left in hasharray ? */
134 		{
135 			fprintf (stderr, "Maximum no of files (%d) reached !\n", filep_nofiles);
136 			exit (3);
137 		}
138 
139 		if ( (filep[ind].fp = fopen (fname, filep_filemode)) == NULL )
140 		{
141 			dbg_val2 ("error in opening %s: # of open files = %d\n", fname, filep_nofiles);
142 			return NULL;
143 		}
144 		filep[ind].name = strdup (name);
145 		filep_nofiles++;
146 
147 		dbg_val3 ("%3d open (%d) file %s \n", filep_nofiles, ind, fname);
148 	}
149 	else				/* the slot for a already known file */
150 	{
151 		/* reopen the file */
152 		if ( (filep[ind].fp = fopen (fname, "a")) == NULL )
153 		{
154 			dbg_val2 ("error in re-opening %s: # of open files = %d\n", fname, filep_nofiles);
155 			return NULL;
156 		}
157 		filep_nofiles++;
158 
159 		dbg_val3 ("%3d re-open (%d) file %s \n", filep_nofiles, ind, fname);
160 	}
161 
162 	return filep[ind].fp;
163 }
164 
filep_first(int * ind)165 int	filep_first (int *ind)
166 {
167 	int	i = 0;
168 
169 	while ( i < HASHSIZE && filep[i].fp == NULL )
170 		i++;
171 	*ind = i;
172 
173 	return i >= HASHSIZE;
174 }
175 
filep_next(int * ind)176 int	filep_next (int *ind)
177 {
178 	int	i = *ind + 1;
179 
180 	while ( i < HASHSIZE && filep[i].fp == NULL )
181 		i++;
182 	*ind = i;
183 
184 	return i >= HASHSIZE;
185 }
186 
filep_getname(int * ind)187 char	*filep_getname (int *ind)
188 {
189 	assert ( *ind >= 0 && *ind < HASHSIZE );
190 
191 	return filep[*ind].name;
192 }
193 
filep_getzone(int * ind)194 const	char	*filep_getzone (int *ind)
195 {
196 	assert ( *ind >= 0 && *ind < HASHSIZE );
197 
198 	return filep[*ind].zone;
199 }
200 
201 
hashfunc(const char * val)202 static	unsigned long	hashfunc (const char *val)
203 {
204 	unsigned long	hash = 0L;
205 	unsigned long	pot = 1L;
206 
207 	while ( *val )
208 	{
209 		hash += *val++ * pot;
210 		pot *= 10;
211 	}
212 
213 	return hash;
214 }
215 
216 
217 #ifdef TEST
218 #define	NFILES	MAXFILEP
main()219 int	main ()
220 {
221 	int	i;
222 	FILE	*fp;
223 	char	name[10+1];
224 
225 	i = filep_init ("test/t%s.db", "w");
226 	fprintf (stdout, "No of concurrent open files is %d \n", i);
227 
228 	/* open more files than the actual limit allows */
229 	srandom (27);
230 	fprintf (stdout, "First loop\n");
231 	for ( i = 0; i < NFILES; i++ )
232 	{
233 		snprintf (name, sizeof name, "%ld", random ());
234 		if ( (fp = filep_open (name)) == NULL )
235 			fprintf (stderr, "Error in access to file %s\n", name);
236 		fprintf (fp, "First line of file %d\n", i);
237 	}
238 
239 	/* Now write again into each file */
240 	srandom (27);
241 	fprintf (stdout, "Second loop\n");
242 	for ( i = 0; i < NFILES; i++ )
243 	{
244 		snprintf (name, sizeof name, "%ld", random ());
245 		if ( (fp = filep_open (name)) == NULL )
246 			fprintf (stderr, "Error in access to file %s\n", name);
247 		fprintf (fp, "Second line of file %d\n", i);
248 	}
249 
250 	/* Now close all files */
251 	filep_close ();
252 }
253 #endif
254