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