Fix disk quotas support on HP/UX (patch by David Nixon)
[ira/wip.git] / source3 / smbd / files.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Files[] structure handling
4    Copyright (C) Andrew Tridgell 1998
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22
23 static int real_max_open_files;
24
25 #define VALID_FNUM(fnum)   (((fnum) >= 0) && ((fnum) < real_max_open_files))
26
27 #define FILE_HANDLE_OFFSET 0x1000
28
29 static struct bitmap *file_bmap;
30
31 static files_struct *Files;
32  
33 /* a fsp to use when chaining */
34 static files_struct *chain_fsp = NULL;
35 /* a fsp to use to save when breaking an oplock. */
36 static files_struct *oplock_save_chain_fsp = NULL;
37
38 static int files_used;
39
40 /****************************************************************************
41  Return a unique number identifying this fsp over the life of this pid.
42 ****************************************************************************/
43
44 static unsigned long get_gen_count(void)
45 {
46         static unsigned long file_gen_counter;
47
48         if ((++file_gen_counter) == 0)
49                 return ++file_gen_counter;
50         return file_gen_counter;
51 }
52
53 /****************************************************************************
54  Find first available file slot.
55 ****************************************************************************/
56
57 files_struct *file_new(connection_struct *conn)
58 {
59         int i;
60         static int first_file;
61         files_struct *fsp, *next;
62
63         /* we want to give out file handles differently on each new
64            connection because of a common bug in MS clients where they try to
65            reuse a file descriptor from an earlier smb connection. This code
66            increases the chance that the errant client will get an error rather
67            than causing corruption */
68         if (first_file == 0) {
69                 first_file = (sys_getpid() ^ (int)time(NULL)) % real_max_open_files;
70         }
71
72         i = bitmap_find(file_bmap, first_file);
73         if (i == -1) {
74                 /* 
75                  * Before we give up, go through the open files 
76                  * and see if there are any files opened with a
77                  * batch oplock. If so break the oplock and then
78                  * re-use that entry (if it becomes closed).
79                  * This may help as NT/95 clients tend to keep
80                  * files batch oplocked for quite a long time
81                  * after they have finished with them.
82                  */
83                 for (fsp=Files;fsp;fsp=next) {
84                         next=fsp->next;
85                         if (attempt_close_oplocked_file(fsp)) {
86                                 return file_new(conn);
87                         }
88                 }
89
90                 DEBUG(0,("ERROR! Out of file structures\n"));
91                 unix_ERR_class = ERRSRV;
92                 unix_ERR_code = ERRnofids;
93                 return NULL;
94         }
95
96         fsp = (files_struct *)malloc(sizeof(*fsp));
97         if (!fsp) {
98                 unix_ERR_class = ERRSRV;
99                 unix_ERR_code = ERRnofids;
100                 return NULL;
101         }
102
103         ZERO_STRUCTP(fsp);
104         fsp->fd = -1;
105         fsp->conn = conn;
106         fsp->file_id = get_gen_count();
107         GetTimeOfDay(&fsp->open_time);
108
109         first_file = (i+1) % real_max_open_files;
110
111         bitmap_set(file_bmap, i);
112         files_used++;
113
114         fsp->fnum = i + FILE_HANDLE_OFFSET;
115         SMB_ASSERT(fsp->fnum < 65536);
116
117         string_set(&fsp->fsp_name,"");
118         
119         DLIST_ADD(Files, fsp);
120
121         DEBUG(5,("allocated file structure %d, fnum = %d (%d used)\n",
122                  i, fsp->fnum, files_used));
123
124         chain_fsp = fsp;
125         
126         return fsp;
127 }
128
129 /****************************************************************************
130  Close all open files for a connection.
131 ****************************************************************************/
132
133 void file_close_conn(connection_struct *conn)
134 {
135         files_struct *fsp, *next;
136         
137         for (fsp=Files;fsp;fsp=next) {
138                 next = fsp->next;
139                 if (fsp->conn == conn) {
140                         close_file(fsp,False); 
141                 }
142         }
143 }
144
145 /****************************************************************************
146  Initialise file structures.
147 ****************************************************************************/
148
149 #define MAX_OPEN_FUDGEFACTOR 20
150
151 void file_init(void)
152 {
153         int request_max_open_files = lp_max_open_files();
154         int real_lim;
155
156         /*
157          * Set the max_open files to be the requested
158          * max plus a fudgefactor to allow for the extra
159          * fd's we need such as log files etc...
160          */
161         real_lim = set_maxfiles(request_max_open_files + MAX_OPEN_FUDGEFACTOR);
162
163         real_max_open_files = real_lim - MAX_OPEN_FUDGEFACTOR;
164
165         if (real_max_open_files + FILE_HANDLE_OFFSET + MAX_OPEN_PIPES > 65536)
166                 real_max_open_files = 65536 - FILE_HANDLE_OFFSET - MAX_OPEN_PIPES;
167
168         if(real_max_open_files != request_max_open_files) {
169                 DEBUG(1,("file_init: Information only: requested %d \
170 open files, %d are available.\n", request_max_open_files, real_max_open_files));
171         }
172
173         SMB_ASSERT(real_max_open_files > 100);
174
175         file_bmap = bitmap_allocate(real_max_open_files);
176         
177         if (!file_bmap) {
178                 exit_server("out of memory in file_init");
179         }
180         
181         /*
182          * Ensure that pipe_handle_oppset is set correctly.
183          */
184         set_pipe_handle_offset(real_max_open_files);
185 }
186
187 /****************************************************************************
188  Close files open by a specified vuid.
189 ****************************************************************************/
190
191 void file_close_user(int vuid)
192 {
193         files_struct *fsp, *next;
194
195         for (fsp=Files;fsp;fsp=next) {
196                 next=fsp->next;
197                 if (fsp->vuid == vuid) {
198                         close_file(fsp,False);
199                 }
200         }
201 }
202
203 /****************************************************************************
204  Find a fsp given a file descriptor.
205 ****************************************************************************/
206
207 files_struct *file_find_fd(int fd)
208 {
209         int count=0;
210         files_struct *fsp;
211
212         for (fsp=Files;fsp;fsp=fsp->next,count++) {
213                 if (fsp->fd == fd) {
214                         if (count > 10) {
215                                 DLIST_PROMOTE(Files, fsp);
216                         }
217                         return fsp;
218                 }
219         }
220
221         return NULL;
222 }
223
224 /****************************************************************************
225  Find a fsp given a device, inode and file_id.
226 ****************************************************************************/
227
228 files_struct *file_find_dif(SMB_DEV_T dev, SMB_INO_T inode, unsigned long file_id)
229 {
230         int count=0;
231         files_struct *fsp;
232
233         for (fsp=Files;fsp;fsp=fsp->next,count++) {
234                 if (fsp->fd != -1 &&
235                     fsp->dev == dev && 
236                     fsp->inode == inode &&
237                     fsp->file_id == file_id ) {
238                         if (count > 10) {
239                                 DLIST_PROMOTE(Files, fsp);
240                         }
241                         return fsp;
242                 }
243         }
244
245         return NULL;
246 }
247
248 /****************************************************************************
249  Check if an fsp still exists.
250 ****************************************************************************/
251
252 files_struct *file_find_fsp(files_struct *orig_fsp)
253 {
254         files_struct *fsp;
255
256     for (fsp=Files;fsp;fsp=fsp->next) {
257         if (fsp == orig_fsp)
258             return fsp;
259     }
260
261     return NULL;
262 }
263
264 /****************************************************************************
265  Find the first fsp given a device and inode.
266 ****************************************************************************/
267
268 files_struct *file_find_di_first(SMB_DEV_T dev, SMB_INO_T inode)
269 {
270     files_struct *fsp;
271
272     for (fsp=Files;fsp;fsp=fsp->next) {
273         if ( fsp->fd != -1 &&
274             fsp->dev == dev &&
275             fsp->inode == inode )
276             return fsp;
277     }
278
279     return NULL;
280 }
281
282 /****************************************************************************
283  Find the next fsp having the same device and inode.
284 ****************************************************************************/
285
286 files_struct *file_find_di_next(files_struct *start_fsp)
287 {
288     files_struct *fsp;
289
290     for (fsp = start_fsp->next;fsp;fsp=fsp->next) {
291         if ( fsp->fd != -1 &&
292             fsp->dev == start_fsp->dev &&
293             fsp->inode == start_fsp->inode )
294             return fsp;
295     }
296
297     return NULL;
298 }
299
300 /****************************************************************************
301  Find a fsp that is open for printing.
302 ****************************************************************************/
303
304 files_struct *file_find_print(void)
305 {
306         files_struct *fsp;
307
308         for (fsp=Files;fsp;fsp=fsp->next) {
309                 if (fsp->print_file) return fsp;
310         } 
311
312         return NULL;
313 }
314
315 /****************************************************************************
316  Sync open files on a connection.
317 ****************************************************************************/
318
319 void file_sync_all(connection_struct *conn)
320 {
321         files_struct *fsp, *next;
322
323         for (fsp=Files;fsp;fsp=next) {
324                 next=fsp->next;
325                 if ((conn == fsp->conn) && (fsp->fd != -1)) {
326                         sync_file(conn,fsp);
327                 }
328         }
329 }
330
331 /****************************************************************************
332  Free up a fsp.
333 ****************************************************************************/
334
335 void file_free(files_struct *fsp)
336 {
337         DLIST_REMOVE(Files, fsp);
338
339         string_free(&fsp->fsp_name);
340
341         bitmap_clear(file_bmap, fsp->fnum - FILE_HANDLE_OFFSET);
342         files_used--;
343
344         DEBUG(5,("freed files structure %d (%d used)\n",
345                  fsp->fnum, files_used));
346
347         /* this is paranoia, just in case someone tries to reuse the 
348            information */
349         ZERO_STRUCTP(fsp);
350
351         if (fsp == chain_fsp) chain_fsp = NULL;
352
353         SAFE_FREE(fsp);
354 }
355
356 /****************************************************************************
357  Get a fsp from a packet given the offset of a 16 bit fnum.
358 ****************************************************************************/
359
360 files_struct *file_fsp(char *buf, int where)
361 {
362         int fnum, count=0;
363         files_struct *fsp;
364
365         if (chain_fsp)
366                 return chain_fsp;
367
368         fnum = SVAL(buf, where);
369
370         for (fsp=Files;fsp;fsp=fsp->next, count++) {
371                 if (fsp->fnum == fnum) {
372                         chain_fsp = fsp;
373                         if (count > 10) {
374                                 DLIST_PROMOTE(Files, fsp);
375                         }
376                         return fsp;
377                 }
378         }
379         return NULL;
380 }
381
382 /****************************************************************************
383  Reset the chained fsp - done at the start of a packet reply.
384 ****************************************************************************/
385
386 void file_chain_reset(void)
387 {
388         chain_fsp = NULL;
389 }
390
391 /****************************************************************************
392 Save the chained fsp - done when about to do an oplock break.
393 ****************************************************************************/
394
395 void file_chain_save(void)
396 {
397         oplock_save_chain_fsp = chain_fsp;
398 }
399
400 /****************************************************************************
401 Restore the chained fsp - done after an oplock break.
402 ****************************************************************************/
403
404 void file_chain_restore(void)
405 {
406         chain_fsp = oplock_save_chain_fsp;
407 }