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 /* the only restriction is that this must be less than PIPE_HANDLE_OFFSET */
27 #define MAX_FNUMS 4096
29 #define VALID_FNUM(fnum) (((fnum) >= 0) && ((fnum) < MAX_FNUMS))
31 #define FILE_HANDLE_OFFSET 0x1000
33 static struct bitmap *file_bmap;
35 #ifdef USE_FILES_ARRAY
36 static files_struct *Files[MAX_FNUMS];
38 static files_struct *Files;
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;
47 * Indirection for file fd's. Needed as POSIX locking
48 * is based on file/process, not fd/process.
50 static file_fd_struct *FileFd;
52 static int files_used, fd_ptr_used;
54 /****************************************************************************
55 find first available file slot
56 ****************************************************************************/
57 files_struct *file_new(void )
60 static int first_file;
61 files_struct *fsp, *next;
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;
72 i = bitmap_find(file_bmap, first_file);
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.
83 #ifdef USE_FILES_ARRAY
84 for(i = 0; i < MAX_FNUMS; i++) {
85 if((fsp = Files[i]) == NULL)
87 if (attempt_close_oplocked_file(fsp))
91 for (fsp=Files;fsp;fsp=next) {
93 if (attempt_close_oplocked_file(fsp)) {
99 DEBUG(0,("ERROR! Out of file structures\n"));
103 fsp = (files_struct *)malloc(sizeof(*fsp));
104 if (!fsp) return NULL;
108 first_file = (i+1) % MAX_FNUMS;
110 bitmap_set(file_bmap, i);
113 fsp->fnum = i + FILE_HANDLE_OFFSET;
114 string_init(&fsp->fsp_name,"");
116 #ifdef USE_FILES_ARRAY
119 DLIST_ADD(Files, fsp);
122 DEBUG(5,("allocated file structure %d, fnum = %d (%d used)\n",
123 i, fsp->fnum, files_used));
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)
138 file_fd_struct *fd_ptr;
140 if(!sbuf) return NULL;
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)) {
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,
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)
167 extern struct current_user current_user;
168 file_fd_struct *fd_ptr;
170 fd_ptr = (file_fd_struct *)malloc(sizeof(*fd_ptr));
172 DEBUG(0,("ERROR! malloc fail for file_fd struct.\n"));
176 ZERO_STRUCTP(fd_ptr);
178 fd_ptr->dev = (SMB_DEV_T)-1;
179 fd_ptr->inode = (SMB_INO_T)-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);
189 DLIST_ADD(FileFd, fd_ptr);
191 DEBUG(5,("allocated fd_ptr structure (%d used)\n", fd_ptr_used));
197 /****************************************************************************
198 close all open files for a connection
199 ****************************************************************************/
200 void file_close_conn(connection_struct *conn)
202 files_struct *fsp, *next;
204 #ifdef USE_FILES_ARRAY
206 for (i = 0; i < MAX_FNUMS; i++) {
207 if((fsp = Files[i]) == NULL)
209 if(fsp->conn == conn && fsp->open) {
210 if (fsp->is_directory)
211 close_directory(fsp);
213 close_file(fsp,False);
217 for (fsp=Files;fsp;fsp=next) {
219 if (fsp->conn == conn && fsp->open) {
220 if (fsp->is_directory)
221 close_directory(fsp);
223 close_file(fsp,False);
229 /****************************************************************************
230 initialise file structures
231 ****************************************************************************/
234 file_bmap = bitmap_allocate(MAX_FNUMS);
237 exit_server("out of memory in file_init");
240 #if (defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE))
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
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",
259 /****************************************************************************
260 close files open by a specified vuid
261 ****************************************************************************/
262 void file_close_user(int vuid)
264 files_struct *fsp, *next;
266 #ifdef USE_FILES_ARRAY
268 for(i = 0; i < MAX_FNUMS; i++) {
269 if((fsp = Files[i]) == NULL)
271 if((fsp->vuid == vuid) && fsp->open) {
272 if(!fsp->is_directory)
273 close_file(fsp,False);
275 close_directory(fsp);
279 for (fsp=Files;fsp;fsp=next) {
281 if ((fsp->vuid == vuid) && fsp->open) {
282 if(!fsp->is_directory)
283 close_file(fsp,False);
285 close_directory(fsp);
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 ****************************************************************************/
297 files_struct *file_find_dit(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval)
302 #ifdef USE_FILES_ARRAY
303 for(count = 0; count < MAX_FNUMS; count++) {
304 if((fsp = Files[count]) == NULL)
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))
314 for (fsp=Files;fsp;fsp=fsp->next,count++) {
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 )) {
321 DLIST_PROMOTE(Files, fsp);
332 /****************************************************************************
333 find a fsp that is open for printing
334 ****************************************************************************/
335 files_struct *file_find_print(void)
339 #ifdef USE_FILES_ARRAY
341 for(i = 0; i < MAX_FNUMS; i++) {
342 if((fsp = Files[i]) == NULL)
344 if (fsp->open && fsp->print_file) return fsp;
347 for (fsp=Files;fsp;fsp=fsp->next) {
348 if (fsp->open && fsp->print_file) return fsp;
356 /****************************************************************************
357 sync open files on a connection
358 ****************************************************************************/
359 void file_sync_all(connection_struct *conn)
361 files_struct *fsp, *next;
363 #ifdef USE_FILES_ARRAY
365 for(i = 0; i < MAX_FNUMS; i++) {
366 if((fsp = Files[i]) == NULL)
368 if (fsp->open && conn == fsp->conn)
372 for (fsp=Files;fsp;fsp=next) {
374 if (fsp->open && conn == fsp->conn) {
382 /****************************************************************************
384 ****************************************************************************/
385 void fd_ptr_free(file_fd_struct *fd_ptr)
387 DLIST_REMOVE(FileFd, fd_ptr);
391 DEBUG(5,("freed fd_ptr structure (%d used)\n", fd_ptr_used));
394 ZERO_STRUCTP(fd_ptr);
400 /****************************************************************************
402 ****************************************************************************/
403 void file_free(files_struct *fsp)
405 #ifdef USE_FILES_ARRAY
406 files_struct *fsp1 = Files[fsp->fnum - FILE_HANDLE_OFFSET];
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;
413 DLIST_REMOVE(Files, fsp);
416 string_free(&fsp->fsp_name);
418 if (fsp->fd_ptr && fsp->fd_ptr->ref_count == 0) {
419 fd_ptr_free(fsp->fd_ptr);
422 bitmap_clear(file_bmap, fsp->fnum - FILE_HANDLE_OFFSET);
425 DEBUG(5,("freed files structure %d (%d used)\n",
426 fsp->fnum, files_used));
428 /* this is paranoia, just in case someone tries to reuse the
432 if (fsp == chain_fsp) chain_fsp = NULL;
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)
446 if (chain_fsp) return chain_fsp;
448 fnum = SVAL(buf, where);
450 #ifdef USE_FILES_ARRAY
451 fsp = Files[fnum - FILE_HANDLE_OFFSET];
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);
457 return (chain_fsp = fsp);
459 for (fsp=Files;fsp;fsp=fsp->next, count++) {
460 if (fsp->fnum == fnum) {
463 DLIST_PROMOTE(Files, fsp);
472 /****************************************************************************
473 Reset the chained fsp - done at the start of a packet reply
474 ****************************************************************************/
476 void file_chain_reset(void)
481 /****************************************************************************
482 Save the chained fsp - done when about to do an oplock break.
483 ****************************************************************************/
485 void file_chain_save(void)
487 oplock_save_chain_fsp = chain_fsp;
490 /****************************************************************************
491 Restore the chained fsp - done after an oplock break.
492 ****************************************************************************/
493 void file_chain_restore(void)
495 chain_fsp = oplock_save_chain_fsp;