b9b27ad5ff921fe1ca2bd587db59c2ca7880d310
[samba.git] / source / 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                 /* We can have a fsp->fd == -1 here as it could be a stat open. */
235                 if (fsp->dev == dev && 
236                     fsp->inode == inode &&
237                     fsp->file_id == file_id ) {
238                         if (count > 10) {
239                                 DLIST_PROMOTE(Files, fsp);
240                         }
241                         /* Paranoia check. */
242                         if (fsp->fd == -1 && fsp->oplock_type != NO_OPLOCK) {
243                                 DEBUG(0,("file_find_dif: file %s dev = %x, inode = %.0f, file_id = %u \
244 oplock_type = %u is a stat open with oplock type !\n", fsp->fsp_name, (unsigned int)fsp->dev,
245                                                 (double)fsp->inode, (unsigned int)fsp->file_id,
246                                                 (unsigned int)fsp->oplock_type ));
247                                 smb_panic("file_find_dif\n");
248                         }
249                         return fsp;
250                 }
251         }
252
253         return NULL;
254 }
255
256 /****************************************************************************
257  Check if an fsp still exists.
258 ****************************************************************************/
259
260 files_struct *file_find_fsp(files_struct *orig_fsp)
261 {
262         files_struct *fsp;
263
264     for (fsp=Files;fsp;fsp=fsp->next) {
265         if (fsp == orig_fsp)
266             return fsp;
267     }
268
269     return NULL;
270 }
271
272 /****************************************************************************
273  Find the first fsp given a device and inode.
274 ****************************************************************************/
275
276 files_struct *file_find_di_first(SMB_DEV_T dev, SMB_INO_T inode)
277 {
278     files_struct *fsp;
279
280     for (fsp=Files;fsp;fsp=fsp->next) {
281         if ( fsp->fd != -1 &&
282             fsp->dev == dev &&
283             fsp->inode == inode )
284             return fsp;
285     }
286
287     return NULL;
288 }
289
290 /****************************************************************************
291  Find the next fsp having the same device and inode.
292 ****************************************************************************/
293
294 files_struct *file_find_di_next(files_struct *start_fsp)
295 {
296     files_struct *fsp;
297
298     for (fsp = start_fsp->next;fsp;fsp=fsp->next) {
299         if ( fsp->fd != -1 &&
300             fsp->dev == start_fsp->dev &&
301             fsp->inode == start_fsp->inode )
302             return fsp;
303     }
304
305     return NULL;
306 }
307
308 /****************************************************************************
309  Find a fsp that is open for printing.
310 ****************************************************************************/
311
312 files_struct *file_find_print(void)
313 {
314         files_struct *fsp;
315
316         for (fsp=Files;fsp;fsp=fsp->next) {
317                 if (fsp->print_file) return fsp;
318         } 
319
320         return NULL;
321 }
322
323 /****************************************************************************
324  Sync open files on a connection.
325 ****************************************************************************/
326
327 void file_sync_all(connection_struct *conn)
328 {
329         files_struct *fsp, *next;
330
331         for (fsp=Files;fsp;fsp=next) {
332                 next=fsp->next;
333                 if ((conn == fsp->conn) && (fsp->fd != -1)) {
334                         sync_file(conn,fsp);
335                 }
336         }
337 }
338
339 /****************************************************************************
340  Free up a fsp.
341 ****************************************************************************/
342
343 void file_free(files_struct *fsp)
344 {
345         DLIST_REMOVE(Files, fsp);
346
347         string_free(&fsp->fsp_name);
348
349         bitmap_clear(file_bmap, fsp->fnum - FILE_HANDLE_OFFSET);
350         files_used--;
351
352         DEBUG(5,("freed files structure %d (%d used)\n",
353                  fsp->fnum, files_used));
354
355         /* this is paranoia, just in case someone tries to reuse the 
356            information */
357         ZERO_STRUCTP(fsp);
358
359         if (fsp == chain_fsp) chain_fsp = NULL;
360
361         SAFE_FREE(fsp);
362 }
363
364 /****************************************************************************
365  Get a fsp from a packet given the offset of a 16 bit fnum.
366 ****************************************************************************/
367
368 files_struct *file_fsp(char *buf, int where)
369 {
370         int fnum, count=0;
371         files_struct *fsp;
372
373         if (chain_fsp)
374                 return chain_fsp;
375
376         fnum = SVAL(buf, where);
377
378         for (fsp=Files;fsp;fsp=fsp->next, count++) {
379                 if (fsp->fnum == fnum) {
380                         chain_fsp = fsp;
381                         if (count > 10) {
382                                 DLIST_PROMOTE(Files, fsp);
383                         }
384                         return fsp;
385                 }
386         }
387         return NULL;
388 }
389
390 /****************************************************************************
391  Reset the chained fsp - done at the start of a packet reply.
392 ****************************************************************************/
393
394 void file_chain_reset(void)
395 {
396         chain_fsp = NULL;
397 }
398
399 /****************************************************************************
400 Save the chained fsp - done when about to do an oplock break.
401 ****************************************************************************/
402
403 void file_chain_save(void)
404 {
405         oplock_save_chain_fsp = chain_fsp;
406 }
407
408 /****************************************************************************
409 Restore the chained fsp - done after an oplock break.
410 ****************************************************************************/
411
412 void file_chain_restore(void)
413 {
414         chain_fsp = oplock_save_chain_fsp;
415 }