2 Unix SMB/CIFS implementation.
3 Files[] structure handling
4 Copyright (C) Andrew Tridgell 1998
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.
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.
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/>.
21 #include "smbd/smbd.h"
22 #include "smbd/globals.h"
23 #include "libcli/security/security.h"
25 #include <ccan/hash/hash.h>
26 #include "lib/util/bitmap.h"
28 #define FILE_HANDLE_OFFSET 0x1000
30 /****************************************************************************
31 Return a unique number identifying this fsp over the life of this pid,
32 and try to make it as globally unique as possible.
33 See bug #8995 for the details.
34 ****************************************************************************/
36 static unsigned long get_gen_count(struct smbd_server_connection
*sconn
)
39 * While fsp->fh->gen_id is 'unsigned long' currently
40 * (which might by 8 bytes),
41 * there's some oplock code which truncates it to
42 * uint32_t(using IVAL()).
44 if (sconn
->file_gen_counter
== 0) {
45 sconn
->file_gen_counter
= generate_random();
47 sconn
->file_gen_counter
+= 1;
48 if (sconn
->file_gen_counter
>= UINT32_MAX
) {
49 sconn
->file_gen_counter
= 0;
51 if (sconn
->file_gen_counter
== 0) {
52 sconn
->file_gen_counter
+= 1;
54 return sconn
->file_gen_counter
;
58 * create new fsp to be used for file_new or a durable handle reconnect
60 NTSTATUS
fsp_new(struct connection_struct
*conn
, TALLOC_CTX
*mem_ctx
,
61 files_struct
**result
)
63 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
64 files_struct
*fsp
= NULL
;
65 struct smbd_server_connection
*sconn
= conn
->sconn
;
67 fsp
= talloc_zero(mem_ctx
, struct files_struct
);
73 * This can't be a child of fsp because the file_handle can be ref'd
74 * when doing a dos/fcb open, which will then share the file_handle
75 * across multiple fsps.
77 fsp
->fh
= talloc_zero(mem_ctx
, struct fd_handle
);
78 if (fsp
->fh
== NULL
) {
82 fsp
->fh
->ref_count
= 1;
85 fsp
->fnum
= FNUM_FIELD_INVALID
;
88 DLIST_ADD(sconn
->files
, fsp
);
89 sconn
->num_files
+= 1;
91 conn
->num_files_open
++;
105 /****************************************************************************
106 Find first available file slot.
107 ****************************************************************************/
109 NTSTATUS
file_new(struct smb_request
*req
, connection_struct
*conn
,
110 files_struct
**result
)
112 struct smbd_server_connection
*sconn
= conn
->sconn
;
117 status
= fsp_new(conn
, conn
, &fsp
);
118 if (!NT_STATUS_IS_OK(status
)) {
122 GetTimeOfDay(&fsp
->open_time
);
124 if (sconn
->file_bmap
!= NULL
) {
127 * we want to give out file handles differently on each new
128 * connection because of a common bug in MS clients where they
129 * try to reuse a file descriptor from an earlier smb
130 * connection. This code increases the chance that the errant
131 * client will get an error rather than causing corruption
133 if (sconn
->first_file
== 0) {
134 sconn
->first_file
= (getpid() ^ (int)time(NULL
));
135 sconn
->first_file
%= sconn
->real_max_open_files
;
138 /* TODO: Port the id-tree implementation from Samba4 */
140 i
= bitmap_find(sconn
->file_bmap
, sconn
->first_file
);
142 DEBUG(0,("ERROR! Out of file structures\n"));
144 * TODO: We have to unconditionally return a DOS error
145 * here, W2k3 even returns ERRDOS/ERRnofids for
146 * ntcreate&x with NTSTATUS negotiated
148 return NT_STATUS_TOO_MANY_OPENED_FILES
;
151 sconn
->first_file
= (i
+1) % (sconn
->real_max_open_files
);
153 bitmap_set(sconn
->file_bmap
, i
);
155 fsp
->fnum
= i
+ FILE_HANDLE_OFFSET
;
156 SMB_ASSERT(fsp
->fnum
< 65536);
158 fsp
->fh
->gen_id
= get_gen_count(sconn
);
162 * Create an smb_filename with "" for the base_name. There are very
163 * few NULL checks, so make sure it's initialized with something. to
164 * be safe until an audit can be done.
166 status
= create_synthetic_smb_fname(fsp
, "", NULL
, NULL
,
168 if (!NT_STATUS_IS_OK(status
)) {
169 file_free(NULL
, fsp
);
173 DEBUG(5,("allocated file structure %d, %s (%u used)\n",
174 i
, fsp_fnum_dbg(fsp
), (unsigned int)sconn
->num_files
));
177 req
->chain_fsp
= fsp
;
180 /* A new fsp invalidates the positive and
181 negative fsp_fi_cache as the new fsp is pushed
182 at the start of the list and we search from
183 a cache hit to the *end* of the list. */
185 ZERO_STRUCT(sconn
->fsp_fi_cache
);
191 /****************************************************************************
192 Close all open files for a connection.
193 ****************************************************************************/
195 void file_close_conn(connection_struct
*conn
)
197 files_struct
*fsp
, *next
;
199 for (fsp
=conn
->sconn
->files
; fsp
; fsp
=next
) {
201 if (fsp
->conn
== conn
) {
202 close_file(NULL
, fsp
, SHUTDOWN_CLOSE
);
207 /****************************************************************************
208 Close all open files for a pid and a vuid.
209 ****************************************************************************/
211 void file_close_pid(struct smbd_server_connection
*sconn
, uint16 smbpid
,
214 files_struct
*fsp
, *next
;
216 for (fsp
=sconn
->files
;fsp
;fsp
=next
) {
218 if ((fsp
->file_pid
== smbpid
) && (fsp
->vuid
== vuid
)) {
219 close_file(NULL
, fsp
, SHUTDOWN_CLOSE
);
224 /****************************************************************************
225 Initialise file structures.
226 ****************************************************************************/
228 static int files_max_open_fds
;
230 bool file_init_global(void)
232 int request_max
= lp_max_open_files();
236 if (files_max_open_fds
!= 0) {
241 * Set the max_open files to be the requested
242 * max plus a fudgefactor to allow for the extra
243 * fd's we need such as log files etc...
245 real_lim
= set_maxfiles(request_max
+ MAX_OPEN_FUDGEFACTOR
);
247 real_max
= real_lim
- MAX_OPEN_FUDGEFACTOR
;
249 if (real_max
+ FILE_HANDLE_OFFSET
+ MAX_OPEN_PIPES
> 65536) {
250 real_max
= 65536 - FILE_HANDLE_OFFSET
- MAX_OPEN_PIPES
;
253 if (real_max
!= request_max
) {
254 DEBUG(1, ("file_init_global: Information only: requested %d "
255 "open files, %d are available.\n",
256 request_max
, real_max
));
259 SMB_ASSERT(real_max
> 100);
261 files_max_open_fds
= real_max
;
265 bool file_init(struct smbd_server_connection
*sconn
)
269 ok
= file_init_global();
274 sconn
->real_max_open_files
= files_max_open_fds
;
276 sconn
->file_bmap
= bitmap_talloc(sconn
, sconn
->real_max_open_files
);
277 if (!sconn
->file_bmap
) {
284 /****************************************************************************
285 Close files open by a specified vuid.
286 ****************************************************************************/
288 void file_close_user(struct smbd_server_connection
*sconn
, uint64_t vuid
)
290 files_struct
*fsp
, *next
;
292 for (fsp
=sconn
->files
; fsp
; fsp
=next
) {
294 if (fsp
->vuid
== vuid
) {
295 close_file(NULL
, fsp
, SHUTDOWN_CLOSE
);
301 * Walk the files table until "fn" returns non-NULL
304 struct files_struct
*files_forall(
305 struct smbd_server_connection
*sconn
,
306 struct files_struct
*(*fn
)(struct files_struct
*fsp
,
310 struct files_struct
*fsp
, *next
;
312 for (fsp
= sconn
->files
; fsp
; fsp
= next
) {
313 struct files_struct
*ret
;
315 ret
= fn(fsp
, private_data
);
323 /****************************************************************************
324 Find a fsp given a file descriptor.
325 ****************************************************************************/
327 files_struct
*file_find_fd(struct smbd_server_connection
*sconn
, int fd
)
332 for (fsp
=sconn
->files
; fsp
; fsp
=fsp
->next
,count
++) {
333 if (fsp
->fh
->fd
== fd
) {
335 DLIST_PROMOTE(sconn
->files
, fsp
);
344 /****************************************************************************
345 Find a fsp given a device, inode and file_id.
346 ****************************************************************************/
348 files_struct
*file_find_dif(struct smbd_server_connection
*sconn
,
349 struct file_id id
, unsigned long gen_id
)
358 for (fsp
=sconn
->files
; fsp
; fsp
=fsp
->next
,count
++) {
359 /* We can have a fsp->fh->fd == -1 here as it could be a stat open. */
360 if (file_id_equal(&fsp
->file_id
, &id
) &&
361 fsp
->fh
->gen_id
== gen_id
) {
363 DLIST_PROMOTE(sconn
->files
, fsp
);
365 /* Paranoia check. */
366 if ((fsp
->fh
->fd
== -1) &&
367 (fsp
->oplock_type
!= NO_OPLOCK
) &&
368 (fsp
->oplock_type
!= FAKE_LEVEL_II_OPLOCK
)) {
369 DEBUG(0,("file_find_dif: file %s file_id = "
370 "%s, gen = %u oplock_type = %u is a "
371 "stat open with oplock type !\n",
373 file_id_string_tos(&fsp
->file_id
),
374 (unsigned int)fsp
->fh
->gen_id
,
375 (unsigned int)fsp
->oplock_type
));
376 smb_panic("file_find_dif");
385 /****************************************************************************
386 Find the first fsp given a device and inode.
387 We use a singleton cache here to speed up searching from getfilepathinfo
389 ****************************************************************************/
391 files_struct
*file_find_di_first(struct smbd_server_connection
*sconn
,
396 if (file_id_equal(&sconn
->fsp_fi_cache
.id
, &id
)) {
397 /* Positive or negative cache hit. */
398 return sconn
->fsp_fi_cache
.fsp
;
401 sconn
->fsp_fi_cache
.id
= id
;
403 for (fsp
=sconn
->files
;fsp
;fsp
=fsp
->next
) {
404 if (file_id_equal(&fsp
->file_id
, &id
)) {
405 /* Setup positive cache. */
406 sconn
->fsp_fi_cache
.fsp
= fsp
;
411 /* Setup negative cache. */
412 sconn
->fsp_fi_cache
.fsp
= NULL
;
416 /****************************************************************************
417 Find the next fsp having the same device and inode.
418 ****************************************************************************/
420 files_struct
*file_find_di_next(files_struct
*start_fsp
)
424 for (fsp
= start_fsp
->next
;fsp
;fsp
=fsp
->next
) {
425 if (file_id_equal(&fsp
->file_id
, &start_fsp
->file_id
)) {
433 /****************************************************************************
434 Find any fsp open with a pathname below that of an already open path.
435 ****************************************************************************/
437 bool file_find_subpath(files_struct
*dir_fsp
)
441 char *d_fullname
= NULL
;
443 d_fullname
= talloc_asprintf(talloc_tos(), "%s/%s",
444 dir_fsp
->conn
->connectpath
,
445 dir_fsp
->fsp_name
->base_name
);
451 dlen
= strlen(d_fullname
);
453 for (fsp
=dir_fsp
->conn
->sconn
->files
; fsp
; fsp
=fsp
->next
) {
456 if (fsp
== dir_fsp
) {
460 d1_fullname
= talloc_asprintf(talloc_tos(),
462 fsp
->conn
->connectpath
,
463 fsp
->fsp_name
->base_name
);
466 * If the open file has a path that is a longer
467 * component, then it's a subpath.
469 if (strnequal(d_fullname
, d1_fullname
, dlen
) &&
470 (d1_fullname
[dlen
] == '/')) {
471 TALLOC_FREE(d1_fullname
);
472 TALLOC_FREE(d_fullname
);
475 TALLOC_FREE(d1_fullname
);
478 TALLOC_FREE(d_fullname
);
482 /****************************************************************************
483 Sync open files on a connection.
484 ****************************************************************************/
486 void file_sync_all(connection_struct
*conn
)
488 files_struct
*fsp
, *next
;
490 for (fsp
=conn
->sconn
->files
; fsp
; fsp
=next
) {
492 if ((conn
== fsp
->conn
) && (fsp
->fh
->fd
!= -1)) {
493 sync_file(conn
, fsp
, True
/* write through */);
498 /****************************************************************************
500 ****************************************************************************/
502 void fsp_free(files_struct
*fsp
)
504 struct smbd_server_connection
*sconn
= fsp
->conn
->sconn
;
506 DLIST_REMOVE(sconn
->files
, fsp
);
507 SMB_ASSERT(sconn
->num_files
> 0);
510 TALLOC_FREE(fsp
->fake_file_handle
);
512 if (fsp
->fh
->ref_count
== 1) {
513 TALLOC_FREE(fsp
->fh
);
515 fsp
->fh
->ref_count
--;
518 fsp
->conn
->num_files_open
--;
520 /* this is paranoia, just in case someone tries to reuse the
524 /* fsp->fsp_name is a talloc child and is free'd automatically. */
528 void file_free(struct smb_request
*req
, files_struct
*fsp
)
530 struct smbd_server_connection
*sconn
= fsp
->conn
->sconn
;
531 uint64_t fnum
= fsp
->fnum
;
534 struct notify_context
*notify_ctx
=
535 fsp
->conn
->sconn
->notify_ctx
;
536 notify_remove(notify_ctx
, fsp
);
537 TALLOC_FREE(fsp
->notify
);
540 /* Ensure this event will never fire. */
541 TALLOC_FREE(fsp
->update_write_time_event
);
543 if (sconn
->file_bmap
!= NULL
) {
544 bitmap_clear(sconn
->file_bmap
, fsp
->fnum
- FILE_HANDLE_OFFSET
);
547 if ((req
!= NULL
) && (fsp
== req
->chain_fsp
)) {
548 req
->chain_fsp
= NULL
;
552 * Clear all possible chained fsp
553 * pointers in the SMB2 request queue.
555 if (req
!= NULL
&& req
->smb2req
) {
556 remove_smb2_chained_fsp(fsp
);
559 /* Closing a file can invalidate the positive cache. */
560 if (fsp
== sconn
->fsp_fi_cache
.fsp
) {
561 ZERO_STRUCT(sconn
->fsp_fi_cache
);
564 /* Drop all remaining extensions. */
565 vfs_remove_all_fsp_extensions(fsp
);
569 DEBUG(5,("freed files structure %llu (%u used)\n",
570 (unsigned long long)fnum
, (unsigned int)sconn
->num_files
));
573 /****************************************************************************
574 Get an fsp from a 16 bit fnum.
575 ****************************************************************************/
577 static struct files_struct
*file_fnum(struct smbd_server_connection
*sconn
,
583 for (fsp
=sconn
->files
; fsp
; fsp
=fsp
->next
, count
++) {
584 if (fsp
->fnum
== FNUM_FIELD_INVALID
) {
588 if (fsp
->fnum
== fnum
) {
590 DLIST_PROMOTE(sconn
->files
, fsp
);
598 /****************************************************************************
599 Get an fsp from a packet given a 16 bit fnum.
600 ****************************************************************************/
602 files_struct
*file_fsp(struct smb_request
*req
, uint16 fid
)
608 * We should never get here. req==NULL could in theory
609 * only happen from internal opens with a non-zero
610 * root_dir_fid. Internal opens just don't do that, at
611 * least they are not supposed to do so. And if they
612 * start to do so, they better fake up a smb_request
613 * from which we get the right smbd_server_conn. While
614 * this should never happen, let's return NULL here.
619 if (req
->chain_fsp
!= NULL
) {
620 return req
->chain_fsp
;
623 fsp
= file_fnum(req
->sconn
, fid
);
625 req
->chain_fsp
= fsp
;
630 uint64_t fsp_persistent_id(const struct files_struct
*fsp
)
632 uint64_t persistent_id
;
635 * This calculates a number that is most likely
636 * globally unique. In future we will have a database
637 * to make it completely unique.
639 * 32-bit random gen_id
640 * 16-bit truncated open_time
641 * 16-bit fnum (valatile_id)
643 persistent_id
= fsp
->fh
->gen_id
& UINT32_MAX
;
644 persistent_id
<<= 16;
645 persistent_id
&= 0x0000FFFFFFFF0000LLU
;
646 persistent_id
|= fsp
->open_time
.tv_usec
& UINT16_MAX
;
647 persistent_id
<<= 16;
648 persistent_id
&= 0xFFFFFFFFFFFF0000LLU
;
649 persistent_id
|= fsp
->fnum
& UINT16_MAX
;
651 return persistent_id
;
654 struct files_struct
*file_fsp_smb2(struct smbd_smb2_request
*smb2req
,
655 uint64_t persistent_id
,
656 uint64_t volatile_id
)
658 struct files_struct
*fsp
;
659 uint64_t fsp_persistent
;
661 if (smb2req
->compat_chain_fsp
!= NULL
) {
662 return smb2req
->compat_chain_fsp
;
665 if (volatile_id
> UINT16_MAX
) {
669 fsp
= file_fnum(smb2req
->sconn
, (uint16_t)volatile_id
);
673 fsp_persistent
= fsp_persistent_id(fsp
);
675 if (persistent_id
!= fsp_persistent
) {
679 if (smb2req
->tcon
== NULL
) {
683 if (smb2req
->tcon
->compat
!= fsp
->conn
) {
687 if (smb2req
->session
== NULL
) {
691 if (smb2req
->session
->compat
== NULL
) {
695 if (smb2req
->session
->compat
->vuid
!= fsp
->vuid
) {
699 smb2req
->compat_chain_fsp
= fsp
;
703 /****************************************************************************
704 Duplicate the file handle part for a DOS or FCB open.
705 ****************************************************************************/
707 NTSTATUS
dup_file_fsp(struct smb_request
*req
, files_struct
*from
,
708 uint32 access_mask
, uint32 share_access
,
709 uint32 create_options
, files_struct
*to
)
711 /* this can never happen for print files */
712 SMB_ASSERT(from
->print_file
== NULL
);
719 to
->file_id
= from
->file_id
;
720 to
->initial_allocation_size
= from
->initial_allocation_size
;
721 to
->file_pid
= from
->file_pid
;
722 to
->vuid
= from
->vuid
;
723 to
->open_time
= from
->open_time
;
724 to
->access_mask
= access_mask
;
725 to
->share_access
= share_access
;
726 to
->oplock_type
= from
->oplock_type
;
727 to
->can_lock
= from
->can_lock
;
728 to
->can_read
= ((access_mask
& FILE_READ_DATA
) != 0);
730 CAN_WRITE(from
->conn
) &&
731 ((access_mask
& (FILE_WRITE_DATA
| FILE_APPEND_DATA
)) != 0);
732 to
->modified
= from
->modified
;
733 to
->is_directory
= from
->is_directory
;
734 to
->aio_write_behind
= from
->aio_write_behind
;
736 return fsp_set_smb_fname(to
, from
->fsp_name
);
740 * Return a jenkins hash of a pathname on a connection.
743 NTSTATUS
file_name_hash(connection_struct
*conn
,
744 const char *name
, uint32_t *p_name_hash
)
746 char *fullpath
= NULL
;
748 /* Set the hash of the full pathname. */
749 fullpath
= talloc_asprintf(talloc_tos(),
754 return NT_STATUS_NO_MEMORY
;
756 *p_name_hash
= hash(fullpath
, talloc_get_size(fullpath
), 0);
758 DEBUG(10,("file_name_hash: %s hash 0x%x\n",
760 (unsigned int)*p_name_hash
));
762 TALLOC_FREE(fullpath
);
767 * The only way that the fsp->fsp_name field should ever be set.
769 NTSTATUS
fsp_set_smb_fname(struct files_struct
*fsp
,
770 const struct smb_filename
*smb_fname_in
)
773 struct smb_filename
*smb_fname_new
;
775 status
= copy_smb_filename(fsp
, smb_fname_in
, &smb_fname_new
);
776 if (!NT_STATUS_IS_OK(status
)) {
780 TALLOC_FREE(fsp
->fsp_name
);
781 fsp
->fsp_name
= smb_fname_new
;
783 return file_name_hash(fsp
->conn
,
784 smb_fname_str_dbg(fsp
->fsp_name
),