First cut at kernel oplocks. This should have no effect unless runnin
[samba.git] / source / smbd / files.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    Files[] structure handling
5    Copyright (C) Andrew Tridgell 1998
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23
24 extern int DEBUGLEVEL;
25
26 /* the only restriction is that this must be less than PIPE_HANDLE_OFFSET */
27 #define MAX_FNUMS 4096
28
29 #define VALID_FNUM(fnum)   (((fnum) >= 0) && ((fnum) < MAX_FNUMS))
30
31 #define FILE_HANDLE_OFFSET 0x1000
32
33 static struct bitmap *file_bmap;
34
35 #ifdef USE_FILES_ARRAY
36 static files_struct *Files[MAX_FNUMS];
37 #else
38 static files_struct *Files;
39 #endif
40  
41 /* a fsp to use when chaining */
42 static files_struct *chain_fsp = NULL;
43 /* a fsp to use to save when breaking an oplock. */
44 static files_struct *oplock_save_chain_fsp = NULL;
45
46 /*
47  * Indirection for file fd's. Needed as POSIX locking
48  * is based on file/process, not fd/process.
49  */
50 static file_fd_struct *FileFd;
51
52 static int files_used, fd_ptr_used;
53
54 /****************************************************************************
55   find first available file slot
56 ****************************************************************************/
57 files_struct *file_new(void )
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 = (getpid() ^ (int)time(NULL)) % MAX_FNUMS;
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 #ifdef USE_FILES_ARRAY
84                 for(i = 0; i < MAX_FNUMS; i++) {
85                   if((fsp = Files[i]) == NULL)
86                     continue;
87                   if (attempt_close_oplocked_file(fsp)) 
88                     return file_new();
89                 }
90 #else
91                 for (fsp=Files;fsp;fsp=next) {
92                         next=fsp->next;
93                         if (attempt_close_oplocked_file(fsp)) {
94                                 return file_new();
95                         }
96                 }
97 #endif
98
99                 DEBUG(0,("ERROR! Out of file structures\n"));
100                 return NULL;
101         }
102
103         fsp = (files_struct *)malloc(sizeof(*fsp));
104         if (!fsp) return NULL;
105
106         ZERO_STRUCTP(fsp);
107
108         first_file = (i+1) % MAX_FNUMS;
109
110         bitmap_set(file_bmap, i);
111         files_used++;
112
113         fsp->fnum = i + FILE_HANDLE_OFFSET;
114         string_init(&fsp->fsp_name,"");
115         
116 #ifdef USE_FILES_ARRAY
117         Files[i] = fsp;
118 #else
119         DLIST_ADD(Files, fsp);
120 #endif
121
122         DEBUG(5,("allocated file structure %d, fnum = %d (%d used)\n",
123                  i, fsp->fnum, files_used));
124
125         chain_fsp = fsp;
126         
127         return fsp;
128 }
129
130
131
132 /****************************************************************************
133 fd support routines - attempt to find an already open file by dev
134 and inode - increments the ref_count of the returned file_fd_struct *.
135 ****************************************************************************/
136 file_fd_struct *fd_get_already_open(SMB_STRUCT_STAT *sbuf)
137 {
138         file_fd_struct *fd_ptr;
139
140         if(!sbuf) return NULL;
141
142         for (fd_ptr=FileFd;fd_ptr;fd_ptr=fd_ptr->next) {
143                 if ((fd_ptr->ref_count > 0) &&
144                     (sbuf->st_dev == fd_ptr->dev) &&
145                     (sbuf->st_ino == fd_ptr->inode)) {
146                         fd_ptr->ref_count++;
147
148                         DEBUG(3,("Re-used file_fd_struct dev = %x, inode = %.0f, ref_count = %d\n",
149                                  (unsigned int)fd_ptr->dev, (double)fd_ptr->inode, 
150                                  fd_ptr->ref_count));
151
152                         return fd_ptr;
153                 }
154         }
155
156         return NULL;
157 }
158
159
160
161 /****************************************************************************
162 fd support routines - attempt to find a empty slot in the FileFd array.
163 Increments the ref_count of the returned entry.
164 ****************************************************************************/
165 file_fd_struct *fd_get_new(void)
166 {
167         extern struct current_user current_user;
168         file_fd_struct *fd_ptr;
169
170         fd_ptr = (file_fd_struct *)malloc(sizeof(*fd_ptr));
171         if (!fd_ptr) {
172           DEBUG(0,("ERROR! malloc fail for file_fd struct.\n"));
173           return NULL;
174         }
175         
176         ZERO_STRUCTP(fd_ptr);
177         
178         fd_ptr->dev = (SMB_DEV_T)-1;
179         fd_ptr->inode = (SMB_INO_T)-1;
180         fd_ptr->fd = -1;
181         fd_ptr->fd_readonly = -1;
182         fd_ptr->fd_writeonly = -1;
183         fd_ptr->real_open_flags = -1;
184         fd_add_to_uid_cache(fd_ptr, (uid_t)current_user.uid);
185         fd_ptr->ref_count++;
186
187         fd_ptr_used++;
188
189         DLIST_ADD(FileFd, fd_ptr);
190
191         DEBUG(5,("allocated fd_ptr structure (%d used)\n", fd_ptr_used));
192
193         return fd_ptr;
194 }
195
196
197 /****************************************************************************
198 close all open files for a connection
199 ****************************************************************************/
200 void file_close_conn(connection_struct *conn)
201 {
202         files_struct *fsp, *next;
203         
204 #ifdef USE_FILES_ARRAY
205         int i;
206         for (i = 0; i < MAX_FNUMS; i++) {
207           if((fsp = Files[i]) == NULL)
208             continue;
209           if(fsp->conn == conn && fsp->open) {
210             if (fsp->is_directory)
211               close_directory(fsp);
212             else
213               close_file(fsp,False);
214           }
215         }
216 #else
217         for (fsp=Files;fsp;fsp=next) {
218                 next = fsp->next;
219                 if (fsp->conn == conn && fsp->open) {
220                         if (fsp->is_directory)
221                                 close_directory(fsp); 
222                         else                  
223                                 close_file(fsp,False); 
224                 }
225         }
226 #endif
227 }
228
229 /****************************************************************************
230 initialise file structures
231 ****************************************************************************/
232 void file_init(void)
233 {
234         file_bmap = bitmap_allocate(MAX_FNUMS);
235
236         if (!file_bmap) {
237                 exit_server("out of memory in file_init");
238         }
239
240 #if (defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE))
241         {
242                 struct rlimit rlp;
243                 getrlimit(RLIMIT_NOFILE, &rlp);
244                 /* Set the fd limit to be MAX_FNUMS + 10 to
245                  * account for the extra fd we need 
246                  * as well as the log files and standard
247                  * handles etc.  */
248                 rlp.rlim_cur = (MAX_FNUMS+10>rlp.rlim_max)? 
249                         rlp.rlim_max:MAX_FNUMS+10;
250                 setrlimit(RLIMIT_NOFILE, &rlp);
251                 getrlimit(RLIMIT_NOFILE, &rlp);
252                 DEBUG(3,("Maximum number of open files per session is %d\n",
253                          (int)rlp.rlim_cur));
254         }
255 #endif
256 }
257
258
259 /****************************************************************************
260 close files open by a specified vuid
261 ****************************************************************************/
262 void file_close_user(int vuid)
263 {
264         files_struct *fsp, *next;
265
266 #ifdef USE_FILES_ARRAY
267         int i;
268         for(i = 0; i < MAX_FNUMS; i++) {
269           if((fsp = Files[i]) == NULL)
270             continue;
271           if((fsp->vuid == vuid) && fsp->open) {
272             if(!fsp->is_directory)
273               close_file(fsp,False);
274             else
275               close_directory(fsp);
276           }
277         }
278 #else
279         for (fsp=Files;fsp;fsp=next) {
280                 next=fsp->next;
281                 if ((fsp->vuid == vuid) && fsp->open) {
282                         if(!fsp->is_directory)
283                                 close_file(fsp,False);
284                         else
285                                 close_directory(fsp);
286                 }
287         }
288 #endif
289 }
290
291
292 /****************************************************************************
293  Find a fsp given a device, inode and timevalue
294  If this is from a kernel oplock break request then tval may be NULL.
295 ****************************************************************************/
296
297 files_struct *file_find_dit(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval)
298 {
299         int count=0;
300         files_struct *fsp;
301
302 #ifdef USE_FILES_ARRAY
303         for(count = 0; count < MAX_FNUMS; count++) {
304                 if((fsp = Files[count]) == NULL)
305                         continue;
306                 if (fsp->open &&
307                         fsp->fd_ptr->dev == dev &&
308                         fsp->fd_ptr->inode == inode &&
309                         (tval ? (fsp->open_time.tv_sec == tval->tv_sec) : True) &&
310                         (tval ? (fsp->open_time.tv_usec == tval->tv_usec) : True)) 
311                                 return fsp;
312                 }
313 #else
314         for (fsp=Files;fsp;fsp=fsp->next,count++) {
315                 if (fsp->open && 
316                     fsp->fd_ptr->dev == dev && 
317                     fsp->fd_ptr->inode == inode &&
318                     (tval ? (fsp->open_time.tv_sec == tval->tv_sec) : True ) &&
319                     (tval ? (fsp->open_time.tv_usec == tval->tv_usec) : True )) {
320                         if (count > 10) {
321                                 DLIST_PROMOTE(Files, fsp);
322                         }
323                         return fsp;
324                 }
325         }
326 #endif
327
328         return NULL;
329 }
330
331
332 /****************************************************************************
333 find a fsp that is open for printing
334 ****************************************************************************/
335 files_struct *file_find_print(void)
336 {
337         files_struct *fsp;
338
339 #ifdef USE_FILES_ARRAY
340         int i;
341         for(i = 0; i < MAX_FNUMS; i++) {
342           if((fsp = Files[i]) == NULL)
343             continue;
344           if (fsp->open && fsp->print_file) return fsp;
345         }
346 #else
347         for (fsp=Files;fsp;fsp=fsp->next) {
348                 if (fsp->open && fsp->print_file) return fsp;
349         } 
350 #endif
351
352         return NULL;
353 }
354
355
356 /****************************************************************************
357 sync open files on a connection
358 ****************************************************************************/
359 void file_sync_all(connection_struct *conn)
360 {
361         files_struct *fsp, *next;
362
363 #ifdef USE_FILES_ARRAY
364         int i;
365         for(i = 0; i < MAX_FNUMS; i++) {
366           if((fsp = Files[i]) == NULL)
367             continue;
368           if (fsp->open && conn == fsp->conn)
369             sync_file(conn,fsp);
370         }
371 #else
372         for (fsp=Files;fsp;fsp=next) {
373                 next=fsp->next;
374                 if (fsp->open && conn == fsp->conn) {
375                         sync_file(conn,fsp);
376                 }
377         }
378 #endif
379 }
380
381
382 /****************************************************************************
383 free up a fd_ptr
384 ****************************************************************************/
385 void fd_ptr_free(file_fd_struct *fd_ptr)
386 {
387         DLIST_REMOVE(FileFd, fd_ptr);
388
389         fd_ptr_used--;
390
391         DEBUG(5,("freed fd_ptr structure (%d used)\n", fd_ptr_used));
392
393         /* paranoia */
394         ZERO_STRUCTP(fd_ptr);
395
396         free(fd_ptr);
397 }
398
399
400 /****************************************************************************
401 free up a fsp
402 ****************************************************************************/
403 void file_free(files_struct *fsp)
404 {
405 #ifdef USE_FILES_ARRAY
406     files_struct *fsp1 = Files[fsp->fnum - FILE_HANDLE_OFFSET];
407     if(fsp != fsp1)
408       DEBUG(0,("file_free: fnum = %d (array offset %d) <> fsp = %x, fnum = %d!\n",
409             fsp->fnum, fsp->fnum - FILE_HANDLE_OFFSET, fsp1, fsp1->fnum));
410     SMB_ASSERT(fsp == fsp1);
411     Files[fsp->fnum - FILE_HANDLE_OFFSET] = NULL;
412 #else
413         DLIST_REMOVE(Files, fsp);
414 #endif
415
416         string_free(&fsp->fsp_name);
417
418         if (fsp->fd_ptr && fsp->fd_ptr->ref_count == 0) {
419                 fd_ptr_free(fsp->fd_ptr);
420         }
421
422         bitmap_clear(file_bmap, fsp->fnum - FILE_HANDLE_OFFSET);
423         files_used--;
424
425         DEBUG(5,("freed files structure %d (%d used)\n",
426                  fsp->fnum, files_used));
427
428         /* this is paranoia, just in case someone tries to reuse the 
429            information */
430         ZERO_STRUCTP(fsp);
431
432         if (fsp == chain_fsp) chain_fsp = NULL;
433
434         free(fsp);
435 }
436
437
438 /****************************************************************************
439 get a fsp from a packet given the offset of a 16 bit fnum
440 ****************************************************************************/
441 files_struct *file_fsp(char *buf, int where)
442 {
443         int fnum, count=0;
444         files_struct *fsp;
445
446         if (chain_fsp) return chain_fsp;
447
448         fnum = SVAL(buf, where);
449
450 #ifdef USE_FILES_ARRAY
451         fsp = Files[fnum - FILE_HANDLE_OFFSET];
452         if(!fsp)
453           DEBUG(0,("file_fsp: fnum = %d (array offset %d) gave null fsp !\n",
454                 fnum, fnum - FILE_HANDLE_OFFSET));
455         SMB_ASSERT(fsp != NULL);
456
457         return (chain_fsp = fsp);
458 #else
459         for (fsp=Files;fsp;fsp=fsp->next, count++) {
460                 if (fsp->fnum == fnum) {
461                         chain_fsp = fsp;
462                         if (count > 10) {
463                                 DLIST_PROMOTE(Files, fsp);
464                         }
465                         return fsp;
466                 }
467         }
468         return NULL;
469 #endif
470 }
471
472 /****************************************************************************
473  Reset the chained fsp - done at the start of a packet reply
474 ****************************************************************************/
475
476 void file_chain_reset(void)
477 {
478         chain_fsp = NULL;
479 }
480
481 /****************************************************************************
482 Save the chained fsp - done when about to do an oplock break.
483 ****************************************************************************/
484
485 void file_chain_save(void)
486 {
487         oplock_save_chain_fsp = chain_fsp;
488 }
489
490 /****************************************************************************
491 Restore the chained fsp - done after an oplock break.
492 ****************************************************************************/
493 void file_chain_restore(void)
494 {
495         chain_fsp = oplock_save_chain_fsp;
496 }