2 Unix SMB/Netbios implementation.
4 Files[] structure handling
5 Copyright (C) Andrew Tridgell 1998
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.
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.
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.
24 extern int DEBUGLEVEL;
26 static int real_max_open_files;
28 #define VALID_FNUM(fnum) (((fnum) >= 0) && ((fnum) < real_max_open_files))
30 #define FILE_HANDLE_OFFSET 0x1000
32 static struct bitmap *file_bmap;
34 #ifdef USE_FILES_ARRAY
35 static files_struct **Files;
37 static files_struct *Files;
40 /* a fsp to use when chaining */
41 static files_struct *chain_fsp = NULL;
42 /* a fsp to use to save when breaking an oplock. */
43 static files_struct *oplock_save_chain_fsp = NULL;
46 * Indirection for file fd's. Needed as POSIX locking
47 * is based on file/process, not fd/process.
49 static file_fd_struct *FileFd;
51 static int files_used, fd_ptr_used;
53 /****************************************************************************
54 find first available file slot
55 ****************************************************************************/
56 files_struct *file_new(void )
59 static int first_file;
60 files_struct *fsp, *next;
62 /* we want to give out file handles differently on each new
63 connection because of a common bug in MS clients where they try to
64 reuse a file descriptor from an earlier smb connection. This code
65 increases the chance that the errant client will get an error rather
66 than causing corruption */
67 if (first_file == 0) {
68 first_file = (getpid() ^ (int)time(NULL)) % real_max_open_files;
71 i = bitmap_find(file_bmap, first_file);
74 * Before we give up, go through the open files
75 * and see if there are any files opened with a
76 * batch oplock. If so break the oplock and then
77 * re-use that entry (if it becomes closed).
78 * This may help as NT/95 clients tend to keep
79 * files batch oplocked for quite a long time
80 * after they have finished with them.
82 #ifdef USE_FILES_ARRAY
83 for(i = 0; i < real_max_open_files; i++) {
84 if((fsp = Files[i]) == NULL)
86 if (attempt_close_oplocked_file(fsp))
90 for (fsp=Files;fsp;fsp=next) {
92 if (attempt_close_oplocked_file(fsp)) {
98 DEBUG(0,("ERROR! Out of file structures\n"));
102 fsp = (files_struct *)malloc(sizeof(*fsp));
103 if (!fsp) return NULL;
107 first_file = (i+1) % real_max_open_files;
109 bitmap_set(file_bmap, i);
112 fsp->fnum = i + FILE_HANDLE_OFFSET;
113 string_init(&fsp->fsp_name,"");
115 #ifdef USE_FILES_ARRAY
118 DLIST_ADD(Files, fsp);
121 DEBUG(5,("allocated file structure %d, fnum = %d (%d used)\n",
122 i, fsp->fnum, files_used));
131 /****************************************************************************
132 fd support routines - attempt to find an already open file by dev
133 and inode - increments the ref_count of the returned file_fd_struct *.
134 ****************************************************************************/
135 file_fd_struct *fd_get_already_open(SMB_STRUCT_STAT *sbuf)
137 file_fd_struct *fd_ptr;
139 if(!sbuf) return NULL;
141 for (fd_ptr=FileFd;fd_ptr;fd_ptr=fd_ptr->next) {
142 if ((fd_ptr->ref_count > 0) &&
143 (sbuf->st_dev == fd_ptr->dev) &&
144 (sbuf->st_ino == fd_ptr->inode)) {
147 DEBUG(3,("Re-used file_fd_struct dev = %x, inode = %.0f, ref_count = %d\n",
148 (unsigned int)fd_ptr->dev, (double)fd_ptr->inode,
160 /****************************************************************************
161 fd support routines - attempt to find a empty slot in the FileFd array.
162 Increments the ref_count of the returned entry.
163 ****************************************************************************/
164 file_fd_struct *fd_get_new(void)
166 extern struct current_user current_user;
167 file_fd_struct *fd_ptr;
169 fd_ptr = (file_fd_struct *)malloc(sizeof(*fd_ptr));
171 DEBUG(0,("ERROR! malloc fail for file_fd struct.\n"));
175 ZERO_STRUCTP(fd_ptr);
177 fd_ptr->dev = (SMB_DEV_T)-1;
178 fd_ptr->inode = (SMB_INO_T)-1;
180 fd_ptr->fd_readonly = -1;
181 fd_ptr->fd_writeonly = -1;
182 fd_ptr->real_open_flags = -1;
183 fd_add_to_uid_cache(fd_ptr, (uid_t)current_user.uid);
188 DLIST_ADD(FileFd, fd_ptr);
190 DEBUG(5,("allocated fd_ptr structure (%d used)\n", fd_ptr_used));
196 /****************************************************************************
197 close all open files for a connection
198 ****************************************************************************/
199 void file_close_conn(connection_struct *conn)
201 files_struct *fsp, *next;
203 #ifdef USE_FILES_ARRAY
205 for (i = 0; i < real_max_open_files; i++) {
206 if((fsp = Files[i]) == NULL)
208 if(fsp->conn == conn && fsp->open) {
209 if (fsp->is_directory)
210 close_directory(fsp);
212 close_file(fsp,False);
216 for (fsp=Files;fsp;fsp=next) {
218 if (fsp->conn == conn && fsp->open) {
219 if (fsp->is_directory)
220 close_directory(fsp);
222 close_file(fsp,False);
228 /****************************************************************************
229 initialise file structures
230 ****************************************************************************/
232 #define MAX_OPEN_FUDGEFACTOR 10
236 real_max_open_files = lp_max_open_files();
238 #if (defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE))
241 getrlimit(RLIMIT_NOFILE, &rlp);
242 /* Set the fd limit to be real_max_open_files + MAX_OPEN_FUDGEFACTOR to
243 * account for the extra fd we need
244 * as well as the log files and standard
246 rlp.rlim_cur = (real_max_open_files+MAX_OPEN_FUDGEFACTOR>rlp.rlim_max)?
247 rlp.rlim_max:real_max_open_files+MAX_OPEN_FUDGEFACTOR;
248 setrlimit(RLIMIT_NOFILE, &rlp);
249 getrlimit(RLIMIT_NOFILE, &rlp);
250 if(rlp.rlim_cur != (real_max_open_files + MAX_OPEN_FUDGEFACTOR))
251 DEBUG(0,("file_init: Maximum number of open files requested per session \
252 was %d, actual files available per session = %d\n",
253 real_max_open_files, (int)rlp.rlim_cur - MAX_OPEN_FUDGEFACTOR ));
255 DEBUG(2,("Maximum number of open files per session is %d\n",
256 (int)rlp.rlim_cur - MAX_OPEN_FUDGEFACTOR));
258 real_max_open_files = (int)rlp.rlim_cur - MAX_OPEN_FUDGEFACTOR;
262 file_bmap = bitmap_allocate(real_max_open_files);
265 exit_server("out of memory in file_init");
268 #ifdef USE_FILES_ARRAY
269 Files = (files_struct **)malloc( sizeof(files_struct *) * real_max_open_files);
271 exit_server("out of memory for file array in file_init");
275 * Ensure that pipe_handle_oppset is set correctly.
277 set_pipe_handle_offset(real_max_open_files);
281 /****************************************************************************
282 close files open by a specified vuid
283 ****************************************************************************/
284 void file_close_user(int vuid)
286 files_struct *fsp, *next;
288 #ifdef USE_FILES_ARRAY
290 for(i = 0; i < real_max_open_files; i++) {
291 if((fsp = Files[i]) == NULL)
293 if((fsp->vuid == vuid) && fsp->open) {
294 if(!fsp->is_directory)
295 close_file(fsp,False);
297 close_directory(fsp);
301 for (fsp=Files;fsp;fsp=next) {
303 if ((fsp->vuid == vuid) && fsp->open) {
304 if(!fsp->is_directory)
305 close_file(fsp,False);
307 close_directory(fsp);
314 /****************************************************************************
315 Find a fsp given a device, inode and timevalue
316 If this is from a kernel oplock break request then tval may be NULL.
317 ****************************************************************************/
319 files_struct *file_find_dit(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval)
324 #ifdef USE_FILES_ARRAY
325 for(count = 0; count < real_max_open_files; count++) {
326 if((fsp = Files[count]) == NULL)
329 fsp->fd_ptr->dev == dev &&
330 fsp->fd_ptr->inode == inode &&
331 (tval ? (fsp->open_time.tv_sec == tval->tv_sec) : True) &&
332 (tval ? (fsp->open_time.tv_usec == tval->tv_usec) : True))
336 for (fsp=Files;fsp;fsp=fsp->next,count++) {
338 fsp->fd_ptr->dev == dev &&
339 fsp->fd_ptr->inode == inode &&
340 (tval ? (fsp->open_time.tv_sec == tval->tv_sec) : True ) &&
341 (tval ? (fsp->open_time.tv_usec == tval->tv_usec) : True )) {
343 DLIST_PROMOTE(Files, fsp);
354 /****************************************************************************
355 find a fsp that is open for printing
356 ****************************************************************************/
357 files_struct *file_find_print(void)
361 #ifdef USE_FILES_ARRAY
363 for(i = 0; i < real_max_open_files; i++) {
364 if((fsp = Files[i]) == NULL)
366 if (fsp->open && fsp->print_file) return fsp;
369 for (fsp=Files;fsp;fsp=fsp->next) {
370 if (fsp->open && fsp->print_file) return fsp;
378 /****************************************************************************
379 sync open files on a connection
380 ****************************************************************************/
381 void file_sync_all(connection_struct *conn)
383 files_struct *fsp, *next;
385 #ifdef USE_FILES_ARRAY
387 for(i = 0; i < real_max_open_files; i++) {
388 if((fsp = Files[i]) == NULL)
390 if (fsp->open && conn == fsp->conn)
394 for (fsp=Files;fsp;fsp=next) {
396 if (fsp->open && conn == fsp->conn) {
404 /****************************************************************************
406 ****************************************************************************/
407 void fd_ptr_free(file_fd_struct *fd_ptr)
409 DLIST_REMOVE(FileFd, fd_ptr);
413 DEBUG(5,("freed fd_ptr structure (%d used)\n", fd_ptr_used));
416 ZERO_STRUCTP(fd_ptr);
422 /****************************************************************************
424 ****************************************************************************/
425 void file_free(files_struct *fsp)
427 #ifdef USE_FILES_ARRAY
428 files_struct *fsp1 = Files[fsp->fnum - FILE_HANDLE_OFFSET];
430 DEBUG(0,("file_free: fnum = %d (array offset %d) <> fsp = %x, fnum = %d!\n",
431 fsp->fnum, fsp->fnum - FILE_HANDLE_OFFSET, fsp1, fsp1->fnum));
432 SMB_ASSERT(fsp == fsp1);
433 Files[fsp->fnum - FILE_HANDLE_OFFSET] = NULL;
435 DLIST_REMOVE(Files, fsp);
438 string_free(&fsp->fsp_name);
440 if (fsp->fd_ptr && fsp->fd_ptr->ref_count == 0) {
441 fd_ptr_free(fsp->fd_ptr);
444 bitmap_clear(file_bmap, fsp->fnum - FILE_HANDLE_OFFSET);
447 DEBUG(5,("freed files structure %d (%d used)\n",
448 fsp->fnum, files_used));
450 /* this is paranoia, just in case someone tries to reuse the
454 if (fsp == chain_fsp) chain_fsp = NULL;
460 /****************************************************************************
461 get a fsp from a packet given the offset of a 16 bit fnum
462 ****************************************************************************/
463 files_struct *file_fsp(char *buf, int where)
468 if (chain_fsp) return chain_fsp;
470 fnum = SVAL(buf, where);
472 #ifdef USE_FILES_ARRAY
473 fsp = Files[fnum - FILE_HANDLE_OFFSET];
475 DEBUG(0,("file_fsp: fnum = %d (array offset %d) gave null fsp !\n",
476 fnum, fnum - FILE_HANDLE_OFFSET));
477 SMB_ASSERT(fsp != NULL);
479 return (chain_fsp = fsp);
481 for (fsp=Files;fsp;fsp=fsp->next, count++) {
482 if (fsp->fnum == fnum) {
485 DLIST_PROMOTE(Files, fsp);
494 /****************************************************************************
495 Reset the chained fsp - done at the start of a packet reply
496 ****************************************************************************/
498 void file_chain_reset(void)
503 /****************************************************************************
504 Save the chained fsp - done when about to do an oplock break.
505 ****************************************************************************/
507 void file_chain_save(void)
509 oplock_save_chain_fsp = chain_fsp;
512 /****************************************************************************
513 Restore the chained fsp - done after an oplock break.
514 ****************************************************************************/
515 void file_chain_restore(void)
517 chain_fsp = oplock_save_chain_fsp;