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
23static 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
29static struct bitmap *file_bmap;
30
31static files_struct *Files;
32
33/* a fsp to use when chaining */
34static files_struct *chain_fsp = NULL;
35/* a fsp to use to save when breaking an oplock. */
36static files_struct *oplock_save_chain_fsp = NULL;
37
38static int files_used;
39
40/* A singleton cache to speed up searching by dev/inode. */
41static struct fsp_singleton_cache {
42	files_struct *fsp;
43	SMB_DEV_T dev;
44	SMB_INO_T inode;
45} fsp_fi_cache;
46
47/****************************************************************************
48 Return a unique number identifying this fsp over the life of this pid.
49****************************************************************************/
50
51static unsigned long get_gen_count(void)
52{
53	static unsigned long file_gen_counter;
54
55	if ((++file_gen_counter) == 0)
56		return ++file_gen_counter;
57	return file_gen_counter;
58}
59
60/****************************************************************************
61 Find first available file slot.
62****************************************************************************/
63
64files_struct *file_new(connection_struct *conn)
65{
66	int i;
67	static int first_file;
68	files_struct *fsp, *next;
69
70	/* we want to give out file handles differently on each new
71	   connection because of a common bug in MS clients where they try to
72	   reuse a file descriptor from an earlier smb connection. This code
73	   increases the chance that the errant client will get an error rather
74	   than causing corruption */
75	if (first_file == 0) {
76		first_file = (sys_getpid() ^ (int)time(NULL)) % real_max_open_files;
77	}
78
79	i = bitmap_find(file_bmap, first_file);
80	if (i == -1) {
81		/*
82		 * Before we give up, go through the open files
83		 * and see if there are any files opened with a
84		 * batch oplock. If so break the oplock and then
85		 * re-use that entry (if it becomes closed).
86		 * This may help as NT/95 clients tend to keep
87		 * files batch oplocked for quite a long time
88		 * after they have finished with them.
89		 */
90		for (fsp=Files;fsp;fsp=next) {
91			next=fsp->next;
92			if (attempt_close_oplocked_file(fsp)) {
93				return file_new(conn);
94			}
95		}
96
97		DEBUG(0,("ERROR! Out of file structures\n"));
98		unix_ERR_class = ERRSRV;
99		unix_ERR_code = ERRnofids;
100		return NULL;
101	}
102
103	fsp = SMB_MALLOC_P(files_struct);
104	if (!fsp) {
105		unix_ERR_class = ERRSRV;
106		unix_ERR_code = ERRnofids;
107		return NULL;
108	}
109
110	ZERO_STRUCTP(fsp);
111	fsp->fd = -1;
112	fsp->conn = conn;
113	fsp->file_id = get_gen_count();
114	GetTimeOfDay(&fsp->open_time);
115
116	first_file = (i+1) % real_max_open_files;
117
118	bitmap_set(file_bmap, i);
119	files_used++;
120
121	fsp->fnum = i + FILE_HANDLE_OFFSET;
122	SMB_ASSERT(fsp->fnum < 65536);
123
124	string_set(&fsp->fsp_name,"");
125
126	DLIST_ADD(Files, fsp);
127
128	DEBUG(5,("allocated file structure %d, fnum = %d (%d used)\n",
129		 i, fsp->fnum, files_used));
130
131	chain_fsp = fsp;
132
133	/* A new fsp invalidates a negative fsp_fi_cache. */
134	if (fsp_fi_cache.fsp == NULL) {
135		ZERO_STRUCT(fsp_fi_cache);
136	}
137
138	return fsp;
139}
140
141/****************************************************************************
142 Close all open files for a connection.
143****************************************************************************/
144
145void file_close_conn(connection_struct *conn)
146{
147	files_struct *fsp, *next;
148
149	for (fsp=Files;fsp;fsp=next) {
150		next = fsp->next;
151		if (fsp->conn == conn) {
152			close_file(fsp,False);
153		}
154	}
155}
156
157/****************************************************************************
158 Close all open files for a pid.
159****************************************************************************/
160
161void file_close_pid(uint16 smbpid)
162{
163	files_struct *fsp, *next;
164
165	for (fsp=Files;fsp;fsp=next) {
166		next = fsp->next;
167		if (fsp->file_pid == smbpid) {
168			close_file(fsp,False);
169		}
170	}
171}
172
173/****************************************************************************
174 Initialise file structures.
175****************************************************************************/
176
177#define MAX_OPEN_FUDGEFACTOR 20
178
179void file_init(void)
180{
181	int request_max_open_files = lp_max_open_files();
182	int real_lim;
183
184	/*
185	 * Set the max_open files to be the requested
186	 * max plus a fudgefactor to allow for the extra
187	 * fd's we need such as log files etc...
188	 */
189	real_lim = set_maxfiles(request_max_open_files + MAX_OPEN_FUDGEFACTOR);
190
191	real_max_open_files = real_lim - MAX_OPEN_FUDGEFACTOR;
192
193	if (real_max_open_files + FILE_HANDLE_OFFSET + MAX_OPEN_PIPES > 65536)
194		real_max_open_files = 65536 - FILE_HANDLE_OFFSET - MAX_OPEN_PIPES;
195
196	if(real_max_open_files != request_max_open_files) {
197		DEBUG(1,("file_init: Information only: requested %d \
198open files, %d are available.\n", request_max_open_files, real_max_open_files));
199	}
200
201	SMB_ASSERT(real_max_open_files > 100);
202
203	file_bmap = bitmap_allocate(real_max_open_files);
204
205	if (!file_bmap) {
206		exit_server("out of memory in file_init");
207	}
208
209	/*
210	 * Ensure that pipe_handle_oppset is set correctly.
211	 */
212	set_pipe_handle_offset(real_max_open_files);
213}
214
215/****************************************************************************
216 Close files open by a specified vuid.
217****************************************************************************/
218
219void file_close_user(int vuid)
220{
221	files_struct *fsp, *next;
222
223	for (fsp=Files;fsp;fsp=next) {
224		next=fsp->next;
225		if (fsp->vuid == vuid) {
226			close_file(fsp,False);
227		}
228	}
229}
230
231void file_dump_open_table(void)
232{
233	int count=0;
234	files_struct *fsp;
235
236	for (fsp=Files;fsp;fsp=fsp->next,count++) {
237		DEBUG(10,("Files[%d], fnum = %d, name %s, fd = %d, fileid = %lu, dev = %x, inode = %.0f\n",
238			count, fsp->fnum, fsp->fsp_name, fsp->fd, (unsigned long)fsp->file_id,
239			(unsigned int)fsp->dev, (double)fsp->inode ));
240	}
241}
242
243/****************************************************************************
244 Find a fsp given a file descriptor.
245****************************************************************************/
246
247files_struct *file_find_fd(int fd)
248{
249	int count=0;
250	files_struct *fsp;
251
252	for (fsp=Files;fsp;fsp=fsp->next,count++) {
253		if (fsp->fd == fd) {
254			if (count > 10) {
255				DLIST_PROMOTE(Files, fsp);
256			}
257			return fsp;
258		}
259	}
260
261	return NULL;
262}
263
264/****************************************************************************
265 Find a fsp given a device, inode and file_id.
266****************************************************************************/
267
268files_struct *file_find_dif(SMB_DEV_T dev, SMB_INO_T inode, unsigned long file_id)
269{
270	int count=0;
271	files_struct *fsp;
272
273	for (fsp=Files;fsp;fsp=fsp->next,count++) {
274		/* We can have a fsp->fd == -1 here as it could be a stat open. */
275		if (fsp->dev == dev &&
276		    fsp->inode == inode &&
277		    fsp->file_id == file_id ) {
278			if (count > 10) {
279				DLIST_PROMOTE(Files, fsp);
280			}
281			/* Paranoia check. */
282			if (fsp->fd == -1 && fsp->oplock_type != NO_OPLOCK) {
283				DEBUG(0,("file_find_dif: file %s dev = %x, inode = %.0f, file_id = %u \
284oplock_type = %u is a stat open with oplock type !\n", fsp->fsp_name, (unsigned int)fsp->dev,
285						(double)fsp->inode, (unsigned int)fsp->file_id,
286						(unsigned int)fsp->oplock_type ));
287				smb_panic("file_find_dif\n");
288			}
289			return fsp;
290		}
291	}
292
293	return NULL;
294}
295
296/****************************************************************************
297 Check if an fsp still exists.
298****************************************************************************/
299
300files_struct *file_find_fsp(files_struct *orig_fsp)
301{
302	files_struct *fsp;
303
304	for (fsp=Files;fsp;fsp=fsp->next) {
305		if (fsp == orig_fsp)
306			return fsp;
307	}
308
309	return NULL;
310}
311
312/****************************************************************************
313 Find the first fsp given a device and inode.
314 We use a singleton cache here to speed up searching from getfilepathinfo
315 calls.
316****************************************************************************/
317
318files_struct *file_find_di_first(SMB_DEV_T dev, SMB_INO_T inode)
319{
320	files_struct *fsp;
321
322	if (fsp_fi_cache.dev == dev && fsp_fi_cache.inode == inode) {
323		/* Positive or negative cache hit. */
324		return fsp_fi_cache.fsp;
325	}
326
327	fsp_fi_cache.dev = dev;
328	fsp_fi_cache.inode = inode;
329
330	for (fsp=Files;fsp;fsp=fsp->next) {
331		if ( fsp->fd != -1 &&
332				fsp->dev == dev &&
333				fsp->inode == inode ) {
334			/* Setup positive cache. */
335			fsp_fi_cache.fsp = fsp;
336			return fsp;
337		}
338	}
339
340	/* Setup negative cache. */
341	fsp_fi_cache.fsp = NULL;
342	return NULL;
343}
344
345/****************************************************************************
346 Find the next fsp having the same device and inode.
347****************************************************************************/
348
349files_struct *file_find_di_next(files_struct *start_fsp)
350{
351	files_struct *fsp;
352
353	for (fsp = start_fsp->next;fsp;fsp=fsp->next) {
354		if ( fsp->fd != -1 &&
355				fsp->dev == start_fsp->dev &&
356				fsp->inode == start_fsp->inode )
357			return fsp;
358	}
359
360	return NULL;
361}
362
363/****************************************************************************
364 Find a fsp that is open for printing.
365****************************************************************************/
366
367files_struct *file_find_print(void)
368{
369	files_struct *fsp;
370
371	for (fsp=Files;fsp;fsp=fsp->next) {
372		if (fsp->print_file) {
373			return fsp;
374		}
375	}
376
377	return NULL;
378}
379
380/****************************************************************************
381 Set a pending modtime across all files with a given dev/ino pair.
382 Record the owner of that modtime.
383****************************************************************************/
384
385void fsp_set_pending_modtime(files_struct *tfsp, time_t pmod)
386{
387	files_struct *fsp;
388
389	if (null_mtime(pmod)) {
390		return;
391	}
392
393	for (fsp = Files;fsp;fsp=fsp->next) {
394		if ( fsp->fd != -1 &&
395				fsp->dev == tfsp->dev &&
396				fsp->inode == tfsp->inode ) {
397			fsp->pending_modtime = pmod;
398			fsp->pending_modtime_owner = False;
399		}
400	}
401
402	tfsp->pending_modtime_owner = True;
403}
404
405/****************************************************************************
406 Sync open files on a connection.
407****************************************************************************/
408
409void file_sync_all(connection_struct *conn)
410{
411	files_struct *fsp, *next;
412
413	for (fsp=Files;fsp;fsp=next) {
414		next=fsp->next;
415		if ((conn == fsp->conn) && (fsp->fd != -1)) {
416			sync_file(conn,fsp);
417		}
418	}
419}
420
421/****************************************************************************
422 Free up a fsp.
423****************************************************************************/
424
425void file_free(files_struct *fsp)
426{
427	DLIST_REMOVE(Files, fsp);
428
429	string_free(&fsp->fsp_name);
430
431	if (fsp->fake_file_handle) {
432		destroy_fake_file_handle(&fsp->fake_file_handle);
433	}
434
435	bitmap_clear(file_bmap, fsp->fnum - FILE_HANDLE_OFFSET);
436	files_used--;
437
438	DEBUG(5,("freed files structure %d (%d used)\n",
439		 fsp->fnum, files_used));
440
441	/* this is paranoia, just in case someone tries to reuse the
442	   information */
443	ZERO_STRUCTP(fsp);
444
445	if (fsp == chain_fsp) {
446		chain_fsp = NULL;
447	}
448
449	/* Closing a file can invalidate the positive cache. */
450	if (fsp == fsp_fi_cache.fsp) {
451		ZERO_STRUCT(fsp_fi_cache);
452	}
453
454	SAFE_FREE(fsp);
455}
456
457/****************************************************************************
458 Get a fsp from a packet given the offset of a 16 bit fnum.
459****************************************************************************/
460
461files_struct *file_fsp(char *buf, int where)
462{
463	int fnum, count=0;
464	files_struct *fsp;
465
466	if (chain_fsp)
467		return chain_fsp;
468
469	if (!buf)
470		return NULL;
471	fnum = SVAL(buf, where);
472
473	for (fsp=Files;fsp;fsp=fsp->next, count++) {
474		if (fsp->fnum == fnum) {
475			chain_fsp = fsp;
476			if (count > 10) {
477				DLIST_PROMOTE(Files, fsp);
478			}
479			return fsp;
480		}
481	}
482	return NULL;
483}
484
485/****************************************************************************
486 Reset the chained fsp - done at the start of a packet reply.
487****************************************************************************/
488
489void file_chain_reset(void)
490{
491	chain_fsp = NULL;
492}
493
494/****************************************************************************
495Save the chained fsp - done when about to do an oplock break.
496****************************************************************************/
497
498void file_chain_save(void)
499{
500	oplock_save_chain_fsp = chain_fsp;
501}
502
503/****************************************************************************
504Restore the chained fsp - done after an oplock break.
505****************************************************************************/
506
507void file_chain_restore(void)
508{
509	chain_fsp = oplock_save_chain_fsp;
510}
511