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