7bd5501de532b9cdd96e6b5bd07cc58bd18e63e2
[ira/wip.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 static struct bitmap *fd_bmap;
35
36 static files_struct *Files;
37
38 /* a fsp to use when chaining */
39 static files_struct *chain_fsp = NULL;
40
41
42 /*
43  * Indirection for file fd's. Needed as POSIX locking
44  * is based on file/process, not fd/process.
45  */
46 static file_fd_struct *FileFd;
47
48 static int files_used, fd_ptr_used;
49
50 /****************************************************************************
51   find first available file slot
52 ****************************************************************************/
53 files_struct *file_new(void )
54 {
55         int i;
56         static int first_file;
57         files_struct *fsp, *next;
58
59         /* we want to give out file handles differently on each new
60            connection because of a common bug in MS clients where they try to
61            reuse a file descriptor from an earlier smb connection. This code
62            increases the chance that the errant client will get an error rather
63            than causing corruption */
64         if (first_file == 0) {
65                 first_file = (getpid() ^ (int)time(NULL)) % MAX_FNUMS;
66         }
67
68         i = bitmap_find(file_bmap, first_file);
69         if (i == -1) {
70                 /* 
71                  * Before we give up, go through the open files 
72                  * and see if there are any files opened with a
73                  * batch oplock. If so break the oplock and then
74                  * re-use that entry (if it becomes closed).
75                  * This may help as NT/95 clients tend to keep
76                  * files batch oplocked for quite a long time
77                  * after they have finished with them.
78                  */
79                 for (fsp=Files;fsp;fsp=next) {
80                         next=fsp->next;
81                         if (attempt_close_oplocked_file(fsp)) {
82                                 return file_new();
83                         }
84                 }
85
86                 DEBUG(0,("ERROR! Out of file structures\n"));
87                 return NULL;
88         }
89
90         fsp = (files_struct *)malloc(sizeof(*fsp));
91         if (!fsp) return NULL;
92
93         memset(fsp, 0, sizeof(*fsp));
94
95         first_file = (i+1) % MAX_FNUMS;
96
97         bitmap_set(file_bmap, i);
98         files_used++;
99
100         fsp->fnum = i + FILE_HANDLE_OFFSET;
101         string_init(&fsp->fsp_name,"");
102         
103         /* hook into the front of the list */
104         if (!Files) {
105                 Files = fsp;
106         } else {
107                 Files->prev = fsp;
108                 fsp->next = Files;
109                 Files = fsp;
110         }
111
112         DEBUG(5,("allocated file structure %d (%d used)\n",
113                  i, files_used));
114
115         chain_fsp = fsp;
116         
117         return fsp;
118 }
119
120
121
122 /****************************************************************************
123 fd support routines - attempt to find an already open file by dev
124 and inode - increments the ref_count of the returned file_fd_struct *.
125 ****************************************************************************/
126 file_fd_struct *fd_get_already_open(struct stat *sbuf)
127 {
128         file_fd_struct *fd_ptr;
129
130         if(!sbuf) return NULL;
131
132         for (fd_ptr=FileFd;fd_ptr;fd_ptr=fd_ptr->next) {
133                 if ((fd_ptr->ref_count > 0) &&
134                     (((uint32)sbuf->st_dev) == fd_ptr->dev) &&
135                     (((uint32)sbuf->st_ino) == fd_ptr->inode)) {
136                         fd_ptr->ref_count++;
137                         DEBUG(3,("Re-used file_fd_struct dev = %x, inode = %x, ref_count = %d\n",
138                                  fd_ptr->dev, fd_ptr->inode, 
139                                  fd_ptr->ref_count));
140                         return fd_ptr;
141                 }
142         }
143
144         return NULL;
145 }
146
147
148
149 /****************************************************************************
150 fd support routines - attempt to find a empty slot in the FileFd array.
151 Increments the ref_count of the returned entry.
152 ****************************************************************************/
153 file_fd_struct *fd_get_new(void)
154 {
155         extern struct current_user current_user;
156         int i;
157         file_fd_struct *fd_ptr;
158
159         i = bitmap_find(fd_bmap, 1);
160         if (i == -1) {
161                 DEBUG(0,("ERROR! Out of file_fd structures\n"));
162                 return NULL;
163         }
164
165         fd_ptr = (file_fd_struct *)malloc(sizeof(*fd_ptr));
166         if (!fd_ptr) return NULL;
167         
168         memset(fd_ptr, 0, sizeof(*fd_ptr));
169         
170         fd_ptr->fdnum = i;
171         fd_ptr->dev = (uint32)-1;
172         fd_ptr->inode = (uint32)-1;
173         fd_ptr->fd = -1;
174         fd_ptr->fd_readonly = -1;
175         fd_ptr->fd_writeonly = -1;
176         fd_ptr->real_open_flags = -1;
177         fd_add_to_uid_cache(fd_ptr, (uid_t)current_user.uid);
178         fd_ptr->ref_count++;
179
180         bitmap_set(fd_bmap, i);
181         fd_ptr_used++;
182
183         /* hook into the front of the list */
184         if (!FileFd) {
185                 FileFd = fd_ptr;
186         } else {
187                 FileFd->prev = fd_ptr;
188                 fd_ptr->next = FileFd;
189                 FileFd = fd_ptr;
190         }
191
192         DEBUG(5,("allocated fd_ptr structure %d (%d used)\n",
193                  i, fd_ptr_used));
194
195         return fd_ptr;
196 }
197
198
199 /****************************************************************************
200 close all open files for a connection
201 ****************************************************************************/
202 void file_close_conn(connection_struct *conn)
203 {
204         files_struct *fsp, *next;
205         
206         for (fsp=Files;fsp;fsp=next) {
207                 next = fsp->next;
208                 if (fsp->conn == conn && fsp->open) {
209                         if (fsp->is_directory)
210                                 close_directory(fsp); 
211                         else                  
212                                 close_file(fsp,False); 
213                 }
214         }
215 }
216
217 /****************************************************************************
218 initialise file structures
219 ****************************************************************************/
220 void file_init(void)
221 {
222         file_bmap = bitmap_allocate(MAX_FNUMS);
223         fd_bmap = bitmap_allocate(MAX_FNUMS);
224
225         if (!file_bmap || !fd_bmap) {
226                 exit_server("out of memory in file_init");
227         }
228
229 #if (defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE))
230         {
231                 struct rlimit rlp;
232                 getrlimit(RLIMIT_NOFILE, &rlp);
233                 /* Set the fd limit to be MAX_FNUMS + 10 to
234                  * account for the extra fd we need 
235                  * as well as the log files and standard
236                  * handles etc.  */
237                 rlp.rlim_cur = (MAX_FNUMS+10>rlp.rlim_max)? 
238                         rlp.rlim_max:MAX_FNUMS+10;
239                 setrlimit(RLIMIT_NOFILE, &rlp);
240                 getrlimit(RLIMIT_NOFILE, &rlp);
241                 DEBUG(3,("Maximum number of open files per session is %d\n",
242                          (int)rlp.rlim_cur));
243         }
244 #endif
245 }
246
247
248 /****************************************************************************
249 close files open by a specified vuid
250 ****************************************************************************/
251 void file_close_user(int vuid)
252 {
253         files_struct *fsp, *next;
254
255         for (fsp=Files;fsp;fsp=next) {
256                 next=fsp->next;
257                 if ((fsp->vuid == vuid) && fsp->open) {
258                         if(!fsp->is_directory)
259                                 close_file(fsp,False);
260                         else
261                                 close_directory(fsp);
262                 }
263         }
264 }
265
266
267 /****************************************************************************
268 find a fsp given a device, inode and timevalue
269 ****************************************************************************/
270 files_struct *file_find_dit(int dev, int inode, struct timeval *tval)
271 {
272         files_struct *fsp;
273
274         for (fsp=Files;fsp;fsp=fsp->next) {
275                 if (fsp->open && 
276                     fsp->fd_ptr->dev == dev && 
277                     fsp->fd_ptr->inode == inode &&
278                     fsp->open_time.tv_sec == tval->tv_sec &&
279                     fsp->open_time.tv_usec == tval->tv_usec) {
280                         return fsp;
281                 }
282         }
283
284         return NULL;
285 }
286
287
288 /****************************************************************************
289 find a fsp that is open for printing
290 ****************************************************************************/
291 files_struct *file_find_print(void)
292 {
293         files_struct *fsp;
294
295         for (fsp=Files;fsp;fsp=fsp->next) {
296                 if (fsp->open && fsp->print_file) return fsp;
297         } 
298         return NULL;
299 }
300
301
302 /****************************************************************************
303 sync open files on a connection
304 ****************************************************************************/
305 void file_sync_all(connection_struct *conn)
306 {
307         files_struct *fsp, *next;
308
309         for (fsp=Files;fsp;fsp=next) {
310                 next=fsp->next;
311                 if (fsp->open && conn == fsp->conn) {
312                         sync_file(conn,fsp);
313                 }
314         }
315 }
316
317
318 /****************************************************************************
319 free up a fd_ptr
320 ****************************************************************************/
321 static void fd_ptr_free(file_fd_struct *fd_ptr)
322 {
323         if (fd_ptr == FileFd) {
324                 FileFd = fd_ptr->next;
325                 if (FileFd) FileFd->prev = NULL;
326         } else {
327                 fd_ptr->prev->next = fd_ptr->next;
328                 if (fd_ptr->next) fd_ptr->next->prev = fd_ptr->prev;
329         }
330
331         bitmap_clear(fd_bmap, fd_ptr->fdnum);
332         fd_ptr_used--;
333
334         DEBUG(5,("freed fd_ptr structure %d (%d used)\n",
335                  fd_ptr->fdnum, fd_ptr_used));
336
337         /* paranoia */
338         memset(fd_ptr, 0, sizeof(*fd_ptr));
339
340         free(fd_ptr);
341 }
342
343
344 /****************************************************************************
345 free up a fsp
346 ****************************************************************************/
347 void file_free(files_struct *fsp)
348 {
349         if (fsp == Files) {
350                 Files = fsp->next;
351                 if (Files) Files->prev = NULL;
352         } else {
353                 fsp->prev->next = fsp->next;
354                 if (fsp->next) fsp->next->prev = fsp->prev;
355         }
356
357         string_free(&fsp->fsp_name);
358
359         if (fsp->fd_ptr && fsp->fd_ptr->ref_count == 0) {
360                 fd_ptr_free(fsp->fd_ptr);
361         }
362
363         bitmap_clear(file_bmap, fsp->fnum - FILE_HANDLE_OFFSET);
364         files_used--;
365
366         DEBUG(5,("freed files structure %d (%d used)\n",
367                  fsp->fnum, files_used));
368
369         /* this is paranoia, just in case someone tries to reuse the 
370            information */
371         memset(fsp, 0, sizeof(*fsp));
372
373         if (fsp == chain_fsp) chain_fsp = NULL;
374
375         free(fsp);
376 }
377
378
379 /****************************************************************************
380 get a fsp from a packet given the offset of a 16 bit fnum
381 ****************************************************************************/
382 files_struct *file_fsp(char *buf, int where)
383 {
384         int fnum;
385         files_struct *fsp;
386
387         if (chain_fsp) return chain_fsp;
388
389         fnum = SVAL(buf, where);
390
391         for (fsp=Files;fsp;fsp=fsp->next) {
392                 if (fsp->fnum == fnum) {
393                         chain_fsp = fsp;
394                         return fsp;
395                 }
396         }
397
398         return NULL;
399 }
400
401
402 /****************************************************************************
403 reset the chained fsp - done at the start of a packet reply
404 ****************************************************************************/
405 void file_chain_reset(void)
406 {
407         chain_fsp = NULL;
408 }