2 Unix SMB/CIFS implementation.
3 Directory handling routines
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Jeremy Allison 2007
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 3 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, see <http://www.gnu.org/licenses/>.
22 #include "system/filesys.h"
23 #include "smbd/smbd.h"
24 #include "smbd/globals.h"
25 #include "libcli/security/security.h"
26 #include "lib/util/bitmap.h"
27 #include "../lib/util/memcache.h"
28 #include "../librpc/gen_ndr/open_files.h"
31 This module implements directory related functions for Samba.
34 /* "Special" directory offsets. */
35 #define END_OF_DIRECTORY_OFFSET ((long)-1)
36 #define START_OF_DIRECTORY_OFFSET ((long)0)
37 #define DOT_DOT_DIRECTORY_OFFSET ((long)0x80000000)
39 /* "Special" directory offsets in 32-bit wire format. */
40 #define WIRE_END_OF_DIRECTORY_OFFSET ((uint32_t)0xFFFFFFFF)
41 #define WIRE_START_OF_DIRECTORY_OFFSET ((uint32_t)0)
42 #define WIRE_DOT_DOT_DIRECTORY_OFFSET ((uint32_t)0x80000000)
44 /* Make directory handle internals available. */
46 struct name_cache_entry {
52 connection_struct *conn;
55 struct smb_filename *dir_smb_fname;
56 size_t name_cache_size;
57 struct name_cache_entry *name_cache;
58 unsigned int name_cache_index;
59 unsigned int file_number;
60 files_struct *fsp; /* Back pointer to containing fsp, only
61 set from OpenDir_fsp(). */
62 bool fallback_opendir;
66 struct dptr_struct *next, *prev;
69 struct connection_struct *conn;
70 struct smb_Dir *dir_hnd;
74 struct smb_filename *smb_dname;
75 bool has_wild; /* Set to true if the wcard entry has MS wildcard characters in it. */
76 bool did_stat; /* Optimisation for non-wcard searches. */
77 bool priv; /* Directory handle opened with privilege. */
79 struct memcache *dptr_cache;
82 static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn,
87 static void DirCacheAdd(struct smb_Dir *dir_hnd, const char *name, long offset);
89 static struct smb_Dir *open_dir_safely(TALLOC_CTX *ctx,
90 connection_struct *conn,
91 const struct smb_filename *smb_dname,
94 static int smb_Dir_destructor(struct smb_Dir *dir_hnd);
96 #define INVALID_DPTR_KEY (-3)
98 /****************************************************************************
99 Initialise the dir bitmap.
100 ****************************************************************************/
102 bool init_dptrs(struct smbd_server_connection *sconn)
104 if (sconn->searches.dptr_bmap) {
108 sconn->searches.dptr_bmap = bitmap_talloc(
109 sconn, MAX_DIRECTORY_HANDLES);
111 if (sconn->searches.dptr_bmap == NULL) {
118 /****************************************************************************
119 Get the struct dptr_struct for a dir index.
120 ****************************************************************************/
122 static struct dptr_struct *dptr_get(struct smbd_server_connection *sconn,
125 struct dptr_struct *dptr;
127 for (dptr = sconn->searches.dirptrs; dptr != NULL; dptr = dptr->next) {
128 if(dptr->dnum != key) {
131 DLIST_PROMOTE(sconn->searches.dirptrs, dptr);
137 /****************************************************************************
138 Get the dir path for a dir index.
139 ****************************************************************************/
141 const char *dptr_path(struct smbd_server_connection *sconn, int key)
143 struct dptr_struct *dptr = dptr_get(sconn, key);
145 return(dptr->smb_dname->base_name);
149 /****************************************************************************
150 Get the dir wcard for a dir index.
151 ****************************************************************************/
153 const char *dptr_wcard(struct smbd_server_connection *sconn, int key)
155 struct dptr_struct *dptr = dptr_get(sconn, key);
161 /****************************************************************************
162 Get the dir attrib for a dir index.
163 ****************************************************************************/
165 uint16_t dptr_attr(struct smbd_server_connection *sconn, int key)
167 struct dptr_struct *dptr = dptr_get(sconn, key);
173 /****************************************************************************
174 Close a dptr (internal func).
175 ****************************************************************************/
177 static void dptr_close_internal(struct dptr_struct *dptr)
179 struct smbd_server_connection *sconn = dptr->conn->sconn;
181 DEBUG(4,("closing dptr key %d\n",dptr->dnum));
187 if (sconn->using_smb2) {
191 DLIST_REMOVE(sconn->searches.dirptrs, dptr);
194 * Free the dnum in the bitmap. Remember the dnum value is always
195 * biased by one with respect to the bitmap.
198 if (!bitmap_query(sconn->searches.dptr_bmap, dptr->dnum - 1)) {
199 DEBUG(0,("dptr_close_internal : Error - closing dnum = %d and bitmap not set !\n",
203 bitmap_clear(sconn->searches.dptr_bmap, dptr->dnum - 1);
206 TALLOC_FREE(dptr->dir_hnd);
210 /****************************************************************************
211 Close all dptrs for a cnum.
212 ****************************************************************************/
214 void dptr_closecnum(connection_struct *conn)
216 struct dptr_struct *dptr, *next;
217 struct smbd_server_connection *sconn = conn->sconn;
223 for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
225 if (dptr->conn == conn) {
226 files_struct *fsp = dptr->dir_hnd->fsp;
227 close_file(NULL, fsp, NORMAL_CLOSE);
233 /****************************************************************************
234 Create a new dir ptr. If the flag old_handle is true then we must allocate
235 from the bitmap range 0 - 255 as old SMBsearch directory handles are only
236 one byte long. If old_handle is false we allocate from the range
237 256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
238 a directory handle is never zero.
239 wcard must not be zero.
240 ****************************************************************************/
242 NTSTATUS dptr_create(connection_struct *conn,
243 struct smb_request *req,
251 struct dptr_struct **dptr_ret)
253 struct smbd_server_connection *sconn = conn->sconn;
254 struct dptr_struct *dptr = NULL;
255 struct smb_Dir *dir_hnd;
257 DBG_INFO("dir=%s\n", fsp_str_dbg(fsp));
260 DEBUG(0,("dptr_create: called with fake connection_struct\n"));
261 return NT_STATUS_INTERNAL_ERROR;
265 return NT_STATUS_INVALID_PARAMETER;
268 if (!(fsp->access_mask & SEC_DIR_LIST)) {
269 DBG_INFO("dptr_create: directory %s "
270 "not open for LIST access\n",
272 return NT_STATUS_ACCESS_DENIED;
274 dir_hnd = OpenDir_fsp(NULL, conn, fsp, wcard, attr);
276 return map_nt_error_from_unix(errno);
279 dptr = talloc_zero(NULL, struct dptr_struct);
281 DEBUG(0,("talloc fail in dptr_create.\n"));
282 TALLOC_FREE(dir_hnd);
283 return NT_STATUS_NO_MEMORY;
286 dptr->smb_dname = cp_smb_filename(dptr, fsp->fsp_name);
287 if (dptr->smb_dname == NULL) {
289 TALLOC_FREE(dir_hnd);
290 return NT_STATUS_NO_MEMORY;
293 dptr->dir_hnd = dir_hnd;
295 dptr->expect_close = expect_close;
296 dptr->wcard = talloc_strdup(dptr, wcard);
299 TALLOC_FREE(dir_hnd);
300 return NT_STATUS_NO_MEMORY;
302 if ((req != NULL && req->posix_pathnames) ||
303 (wcard[0] == '.' && wcard[1] == 0)) {
304 dptr->has_wild = True;
306 dptr->has_wild = wcard_has_wild;
311 if (sconn->using_smb2) {
318 * This is an old-style SMBsearch request. Ensure the
319 * value we return will fit in the range 1-255.
322 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 0);
324 if(dptr->dnum == -1 || dptr->dnum > 254) {
325 DBG_ERR("returned %d: Error - all old "
326 "dirptrs in use ?\n",
329 TALLOC_FREE(dir_hnd);
330 return NT_STATUS_TOO_MANY_OPENED_FILES;
335 * This is a new-style trans2 request. Allocate from
336 * a range that will return 256 - MAX_DIRECTORY_HANDLES.
339 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 255);
341 if(dptr->dnum == -1 || dptr->dnum < 255) {
342 DBG_ERR("returned %d: Error - all new "
343 "dirptrs in use ?\n",
346 TALLOC_FREE(dir_hnd);
347 return NT_STATUS_TOO_MANY_OPENED_FILES;
351 bitmap_set(sconn->searches.dptr_bmap, dptr->dnum);
353 dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
355 DLIST_ADD(sconn->searches.dirptrs, dptr);
358 DBG_INFO("creating new dirptr [%d] for path [%s], expect_close = %d\n",
359 dptr->dnum, fsp_str_dbg(fsp), expect_close);
367 /****************************************************************************
368 Wrapper functions to access the lower level directory handles.
369 ****************************************************************************/
371 void dptr_CloseDir(files_struct *fsp)
375 * The destructor for the struct smb_Dir
376 * (fsp->dptr->dir_hnd) now handles
377 * all resource deallocation.
379 dptr_close_internal(fsp->dptr);
384 void dptr_SeekDir(struct dptr_struct *dptr, long offset)
386 SeekDir(dptr->dir_hnd, offset);
389 long dptr_TellDir(struct dptr_struct *dptr)
391 return TellDir(dptr->dir_hnd);
394 bool dptr_has_wild(struct dptr_struct *dptr)
396 return dptr->has_wild;
399 int dptr_dnum(struct dptr_struct *dptr)
404 bool dptr_get_priv(struct dptr_struct *dptr)
409 void dptr_set_priv(struct dptr_struct *dptr)
414 /****************************************************************************
415 Return the next visible file name, skipping veto'd and invisible files.
416 ****************************************************************************/
418 static const char *dptr_normal_ReadDirName(struct dptr_struct *dptr,
419 long *poffset, SMB_STRUCT_STAT *pst,
422 /* Normal search for the next file. */
424 char *talloced = NULL;
426 while ((name = ReadDirName(dptr->dir_hnd, poffset, pst, &talloced))
428 if (is_visible_file(dptr->conn,
429 dptr->smb_dname->base_name,
433 *ptalloced = talloced;
436 TALLOC_FREE(talloced);
441 /****************************************************************************
442 Return the next visible file name, skipping veto'd and invisible files.
443 ****************************************************************************/
445 static char *dptr_ReadDirName(TALLOC_CTX *ctx,
446 struct dptr_struct *dptr,
448 SMB_STRUCT_STAT *pst)
450 struct smb_filename smb_fname_base;
452 const char *name_temp = NULL;
453 char *talloced = NULL;
454 char *pathreal = NULL;
455 char *found_name = NULL;
458 SET_STAT_INVALID(*pst);
460 if (dptr->has_wild || dptr->did_stat) {
461 name_temp = dptr_normal_ReadDirName(dptr, poffset, pst,
463 if (name_temp == NULL) {
466 if (talloced != NULL) {
467 return talloc_move(ctx, &talloced);
469 return talloc_strdup(ctx, name_temp);
472 /* If poffset is -1 then we know we returned this name before and we
473 * have no wildcards. We're at the end of the directory. */
474 if (*poffset == END_OF_DIRECTORY_OFFSET) {
478 /* We know the stored wcard contains no wildcard characters.
479 * See if we can match with a stat call. If we can't, then set
480 * did_stat to true to ensure we only do this once and keep
483 dptr->did_stat = true;
485 /* First check if it should be visible. */
486 if (!is_visible_file(dptr->conn,
487 dptr->smb_dname->base_name,
491 /* This only returns false if the file was found, but
492 is explicitly not visible. Set us to end of
493 directory, but return NULL as we know we can't ever
498 if (VALID_STAT(*pst)) {
499 name = talloc_strdup(ctx, dptr->wcard);
503 pathreal = talloc_asprintf(ctx,
505 dptr->smb_dname->base_name,
510 /* Create an smb_filename with stream_name == NULL. */
511 smb_fname_base = (struct smb_filename) { .base_name = pathreal };
513 if (SMB_VFS_STAT(dptr->conn, &smb_fname_base) == 0) {
514 *pst = smb_fname_base.st;
515 name = talloc_strdup(ctx, dptr->wcard);
518 /* If we get any other error than ENOENT or ENOTDIR
519 then the file exists we just can't stat it. */
520 if (errno != ENOENT && errno != ENOTDIR) {
521 name = talloc_strdup(ctx, dptr->wcard);
526 /* Stat failed. We know this is authoratiative if we are
527 * providing case sensitive semantics or the underlying
528 * filesystem is case sensitive.
530 if (dptr->conn->case_sensitive ||
531 !(dptr->conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH))
537 * Try case-insensitive stat if the fs has the ability. This avoids
538 * scanning the whole directory.
540 ret = SMB_VFS_GET_REAL_FILENAME(dptr->conn,
541 dptr->smb_dname->base_name,
548 } else if (errno == ENOENT) {
549 /* The case-insensitive lookup was authoritative. */
553 TALLOC_FREE(pathreal);
555 name_temp = dptr_normal_ReadDirName(dptr, poffset, pst, &talloced);
556 if (name_temp == NULL) {
559 if (talloced != NULL) {
560 return talloc_move(ctx, &talloced);
562 return talloc_strdup(ctx, name_temp);
565 TALLOC_FREE(pathreal);
567 /* We need to set the underlying dir_hnd offset to -1
568 * also as this function is usually called with the
569 * output from TellDir. */
570 dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
574 /****************************************************************************
575 Search for a file by name, skipping veto'ed and not visible files.
576 ****************************************************************************/
578 bool dptr_SearchDir(struct dptr_struct *dptr, const char *name, long *poffset, SMB_STRUCT_STAT *pst)
580 SET_STAT_INVALID(*pst);
582 if (!dptr->has_wild && (dptr->dir_hnd->offset == END_OF_DIRECTORY_OFFSET)) {
583 /* This is a singleton directory and we're already at the end. */
584 *poffset = END_OF_DIRECTORY_OFFSET;
588 return SearchDir(dptr->dir_hnd, name, poffset);
591 /****************************************************************************
592 Map a native directory offset to a 32-bit cookie.
593 ****************************************************************************/
595 static uint32_t map_dir_offset_to_wire(struct dptr_struct *dptr, long offset)
600 if (offset == END_OF_DIRECTORY_OFFSET) {
601 return WIRE_END_OF_DIRECTORY_OFFSET;
602 } else if(offset == START_OF_DIRECTORY_OFFSET) {
603 return WIRE_START_OF_DIRECTORY_OFFSET;
604 } else if (offset == DOT_DOT_DIRECTORY_OFFSET) {
605 return WIRE_DOT_DOT_DIRECTORY_OFFSET;
607 if (sizeof(long) == 4) {
608 /* 32-bit machine. We can cheat... */
609 return (uint32_t)offset;
611 if (dptr->dptr_cache == NULL) {
612 /* Lazy initialize cache. */
613 dptr->dptr_cache = memcache_init(dptr, 0);
614 if (dptr->dptr_cache == NULL) {
615 return WIRE_END_OF_DIRECTORY_OFFSET;
618 /* Have we seen this offset before ? */
619 key.data = (void *)&offset;
620 key.length = sizeof(offset);
621 if (memcache_lookup(dptr->dptr_cache,
622 SMB1_SEARCH_OFFSET_MAP,
625 uint32_t wire_offset;
626 SMB_ASSERT(val.length == sizeof(wire_offset));
627 memcpy(&wire_offset, val.data, sizeof(wire_offset));
628 DEBUG(10,("found wire %u <-> offset %ld\n",
629 (unsigned int)wire_offset,
634 /* Allocate a new wire cookie. */
637 } while (dptr->counter == WIRE_START_OF_DIRECTORY_OFFSET ||
638 dptr->counter == WIRE_END_OF_DIRECTORY_OFFSET ||
639 dptr->counter == WIRE_DOT_DOT_DIRECTORY_OFFSET);
640 /* Store it in the cache. */
641 key.data = (void *)&offset;
642 key.length = sizeof(offset);
643 val.data = (void *)&dptr->counter;
644 val.length = sizeof(dptr->counter); /* MUST BE uint32_t ! */
645 memcache_add(dptr->dptr_cache,
646 SMB1_SEARCH_OFFSET_MAP,
649 /* And the reverse mapping for lookup from
650 map_wire_to_dir_offset(). */
651 memcache_add(dptr->dptr_cache,
652 SMB1_SEARCH_OFFSET_MAP,
655 DEBUG(10,("stored wire %u <-> offset %ld\n",
656 (unsigned int)dptr->counter,
658 return dptr->counter;
661 /****************************************************************************
662 Fill the 5 byte server reserved dptr field.
663 ****************************************************************************/
665 bool dptr_fill(struct smbd_server_connection *sconn,
666 char *buf1,unsigned int key)
668 unsigned char *buf = (unsigned char *)buf1;
669 struct dptr_struct *dptr = dptr_get(sconn, key);
670 uint32_t wire_offset;
672 DEBUG(1,("filling null dirptr %d\n",key));
675 wire_offset = map_dir_offset_to_wire(dptr,TellDir(dptr->dir_hnd));
676 DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key,
677 (long)dptr->dir_hnd,(int)wire_offset));
679 SIVAL(buf,1,wire_offset);
683 /****************************************************************************
684 Map a 32-bit wire cookie to a native directory offset.
685 ****************************************************************************/
687 static long map_wire_to_dir_offset(struct dptr_struct *dptr, uint32_t wire_offset)
692 if (wire_offset == WIRE_END_OF_DIRECTORY_OFFSET) {
693 return END_OF_DIRECTORY_OFFSET;
694 } else if(wire_offset == WIRE_START_OF_DIRECTORY_OFFSET) {
695 return START_OF_DIRECTORY_OFFSET;
696 } else if (wire_offset == WIRE_DOT_DOT_DIRECTORY_OFFSET) {
697 return DOT_DOT_DIRECTORY_OFFSET;
699 if (sizeof(long) == 4) {
700 /* 32-bit machine. We can cheat... */
701 return (long)wire_offset;
703 if (dptr->dptr_cache == NULL) {
704 /* Logic error, cache should be initialized. */
705 return END_OF_DIRECTORY_OFFSET;
707 key.data = (void *)&wire_offset;
708 key.length = sizeof(wire_offset);
709 if (memcache_lookup(dptr->dptr_cache,
710 SMB1_SEARCH_OFFSET_MAP,
715 SMB_ASSERT(val.length == sizeof(offset));
716 memcpy(&offset, val.data, sizeof(offset));
717 DEBUG(10,("lookup wire %u <-> offset %ld\n",
718 (unsigned int)wire_offset,
722 return END_OF_DIRECTORY_OFFSET;
725 /****************************************************************************
726 Return the associated fsp and seek the dir_hnd on it it given the 5 byte
728 ****************************************************************************/
730 files_struct *dptr_fetch_fsp(struct smbd_server_connection *sconn,
733 unsigned int key = *(unsigned char *)buf;
734 struct dptr_struct *dptr = dptr_get(sconn, key);
735 uint32_t wire_offset;
739 DEBUG(3,("fetched null dirptr %d\n",key));
743 wire_offset = IVAL(buf,1);
744 seekoff = map_wire_to_dir_offset(dptr, wire_offset);
745 SeekDir(dptr->dir_hnd,seekoff);
746 DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
747 key, dptr->smb_dname->base_name, (int)seekoff));
748 return dptr->dir_hnd->fsp;
751 /****************************************************************************
752 Fetch the fsp associated with the dptr_num.
753 ****************************************************************************/
755 files_struct *dptr_fetch_lanman2_fsp(struct smbd_server_connection *sconn,
758 struct dptr_struct *dptr = dptr_get(sconn, dptr_num);
762 DBG_NOTICE("fetching dirptr %d for path %s\n",
764 dptr->smb_dname->base_name);
765 return dptr->dir_hnd->fsp;
768 static bool mangle_mask_match(connection_struct *conn,
769 const char *filename,
774 if (!name_to_8_3(filename,mname,False,conn->params)) {
777 return mask_match_search(mname,mask,False);
780 bool smbd_dirptr_get_entry(TALLOC_CTX *ctx,
781 struct dptr_struct *dirptr,
787 bool (*match_fn)(TALLOC_CTX *ctx,
792 bool (*mode_fn)(TALLOC_CTX *ctx,
794 struct smb_filename *smb_fname,
799 struct smb_filename **_smb_fname,
803 connection_struct *conn = dirptr->conn;
806 const char *dpath = dirptr->smb_dname->base_name;
807 bool dirptr_path_is_dot = ISDOT(dpath);
812 pathlen = strlen(dpath);
813 slashlen = ( dpath[pathlen-1] != '/') ? 1 : 0;
818 SMB_STRUCT_STAT sbuf = { 0 };
822 char *pathreal = NULL;
823 struct smb_filename smb_fname;
827 cur_offset = dptr_TellDir(dirptr);
828 prev_offset = cur_offset;
829 dname = dptr_ReadDirName(ctx, dirptr, &cur_offset, &sbuf);
831 DEBUG(6,("smbd_dirptr_get_entry: dirptr 0x%lx now at offset %ld\n",
832 (long)dirptr, cur_offset));
838 isdots = (ISDOT(dname) || ISDOTDOT(dname));
839 if (dont_descend && !isdots) {
845 * fname may get mangled, dname is never mangled.
846 * Whenever we're accessing the filesystem we use
847 * pathreal which is composed from dname.
850 ok = match_fn(ctx, private_data, dname, mask, &fname);
858 * pathreal = talloc_asprintf(ctx, "%s%s%s", dirptr->path,
859 * needslash?"/":"", dname);
860 * but this was measurably slower than doing the memcpy.
863 pathreal = talloc_array(
865 pathlen + slashlen + talloc_get_size(dname));
873 * We don't want to pass ./xxx to modules below us so don't
874 * add the path if it is just . by itself.
876 if (dirptr_path_is_dot) {
877 memcpy(pathreal, dname, talloc_get_size(dname));
879 memcpy(pathreal, dpath, pathlen);
880 pathreal[pathlen] = '/';
881 memcpy(pathreal + slashlen + pathlen, dname,
882 talloc_get_size(dname));
885 /* Create smb_fname with NULL stream_name. */
886 smb_fname = (struct smb_filename) {
887 .base_name = pathreal, .st = sbuf
890 ok = mode_fn(ctx, private_data, &smb_fname, get_dosmode, &mode);
894 TALLOC_FREE(pathreal);
898 if (!dir_check_ftype(mode, dirtype)) {
899 DEBUG(5,("[%s] attribs 0x%x didn't match 0x%x\n",
900 fname, (unsigned int)mode, (unsigned int)dirtype));
903 TALLOC_FREE(pathreal);
908 struct timespec write_time_ts;
909 struct file_id fileid;
911 fileid = vfs_file_id_from_sbuf(conn,
913 get_file_infos(fileid, 0, NULL, &write_time_ts);
914 if (!null_timespec(write_time_ts)) {
915 update_stat_ex_mtime(&smb_fname.st,
920 DEBUG(3,("smbd_dirptr_get_entry mask=[%s] found %s "
922 mask, smb_fname_str_dbg(&smb_fname),
925 if (!conn->sconn->using_smb2) {
927 * The dircache is only needed for SMB1 because SMB1
928 * uses a name for the resume wheras SMB2 always
929 * continues from the next position (unless it's told to
930 * restart or close-and-reopen the listing).
932 DirCacheAdd(dirptr->dir_hnd, dname, cur_offset);
937 *_smb_fname = cp_smb_filename(ctx, &smb_fname);
938 TALLOC_FREE(pathreal);
939 if (*_smb_fname == NULL) {
944 *_prev_offset = prev_offset;
952 /****************************************************************************
953 Get an 8.3 directory entry.
954 ****************************************************************************/
956 static bool smbd_dirptr_8_3_match_fn(TALLOC_CTX *ctx,
962 connection_struct *conn = (connection_struct *)private_data;
964 if ((strcmp(mask,"*.*") == 0) ||
965 mask_match_search(dname, mask, false) ||
966 mangle_mask_match(conn, dname, mask)) {
970 * Ensure we can push the original name as UCS2. If
971 * not, then just don't return this name.
975 size_t len = (strlen(dname) + 2) * 4; /* Allow enough space. */
976 uint8_t *tmp = talloc_array(talloc_tos(),
980 status = srvstr_push(NULL,
981 FLAGS2_UNICODE_STRINGS,
990 if (!NT_STATUS_IS_OK(status)) {
994 if (!mangle_is_8_3(dname, false, conn->params)) {
995 bool ok = name_to_8_3(dname, mname, false,
1005 *_fname = talloc_strdup(ctx, fname);
1006 if (*_fname == NULL) {
1016 static bool smbd_dirptr_8_3_mode_fn(TALLOC_CTX *ctx,
1018 struct smb_filename *smb_fname,
1022 connection_struct *conn = (connection_struct *)private_data;
1024 if (!VALID_STAT(smb_fname->st)) {
1025 if ((SMB_VFS_STAT(conn, smb_fname)) != 0) {
1026 DEBUG(5,("smbd_dirptr_8_3_mode_fn: "
1027 "Couldn't stat [%s]. Error "
1029 smb_fname_str_dbg(smb_fname),
1035 *_mode = dos_mode(conn, smb_fname);
1039 bool get_dir_entry(TALLOC_CTX *ctx,
1040 struct dptr_struct *dirptr,
1046 struct timespec *_date,
1050 connection_struct *conn = dirptr->conn;
1052 struct smb_filename *smb_fname = NULL;
1057 ok = smbd_dirptr_get_entry(ctx,
1064 smbd_dirptr_8_3_match_fn,
1065 smbd_dirptr_8_3_mode_fn,
1075 *_fname = talloc_move(ctx, &fname);
1076 *_size = smb_fname->st.st_ex_size;
1078 *_date = smb_fname->st.st_ex_mtime;
1079 TALLOC_FREE(smb_fname);
1083 /*******************************************************************
1084 Check to see if a user can read a file. This is only approximate,
1085 it is used as part of the "hide unreadable" option. Don't
1086 use it for anything security sensitive.
1087 ********************************************************************/
1089 static bool user_can_read_file(connection_struct *conn,
1090 struct smb_filename *smb_fname)
1093 uint32_t rejected_share_access = 0;
1094 uint32_t rejected_mask = 0;
1095 struct security_descriptor *sd = NULL;
1096 uint32_t access_mask = FILE_READ_DATA|
1098 FILE_READ_ATTRIBUTES|
1099 SEC_STD_READ_CONTROL;
1102 * Never hide files from the root user.
1103 * We use (uid_t)0 here not sec_initial_uid()
1104 * as make test uses a single user context.
1107 if (get_current_uid(conn) == (uid_t)0) {
1112 * We can't directly use smbd_check_access_rights()
1113 * here, as this implicitly grants FILE_READ_ATTRIBUTES
1114 * which the Windows access-based-enumeration code
1115 * explicitly checks for on the file security descriptor.
1118 * https://bugzilla.samba.org/show_bug.cgi?id=10252
1120 * and the smb2.acl2.ACCESSBASED test for details.
1123 rejected_share_access = access_mask & ~(conn->share_access);
1124 if (rejected_share_access) {
1125 DEBUG(10, ("rejected share access 0x%x "
1127 (unsigned int)access_mask,
1128 smb_fname_str_dbg(smb_fname),
1129 (unsigned int)rejected_share_access ));
1133 status = SMB_VFS_GET_NT_ACL(conn,
1141 if (!NT_STATUS_IS_OK(status)) {
1142 DEBUG(10, ("Could not get acl "
1144 smb_fname_str_dbg(smb_fname),
1145 nt_errstr(status)));
1149 status = se_file_access_check(sd,
1150 get_current_nttok(conn),
1157 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1158 DEBUG(10,("rejected bits 0x%x read access for %s\n",
1159 (unsigned int)rejected_mask,
1160 smb_fname_str_dbg(smb_fname) ));
1166 /*******************************************************************
1167 Check to see if a user can write a file (and only files, we do not
1168 check dirs on this one). This is only approximate,
1169 it is used as part of the "hide unwriteable" option. Don't
1170 use it for anything security sensitive.
1171 ********************************************************************/
1173 static bool user_can_write_file(connection_struct *conn,
1174 const struct smb_filename *smb_fname)
1177 * Never hide files from the root user.
1178 * We use (uid_t)0 here not sec_initial_uid()
1179 * as make test uses a single user context.
1182 if (get_current_uid(conn) == (uid_t)0) {
1186 SMB_ASSERT(VALID_STAT(smb_fname->st));
1188 /* Pseudo-open the file */
1190 if(S_ISDIR(smb_fname->st.st_ex_mode)) {
1194 return can_write_to_file(conn, smb_fname);
1197 /*******************************************************************
1198 Is a file a "special" type ?
1199 ********************************************************************/
1201 static bool file_is_special(connection_struct *conn,
1202 const struct smb_filename *smb_fname)
1205 * Never hide files from the root user.
1206 * We use (uid_t)0 here not sec_initial_uid()
1207 * as make test uses a single user context.
1210 if (get_current_uid(conn) == (uid_t)0) {
1214 SMB_ASSERT(VALID_STAT(smb_fname->st));
1216 if (S_ISREG(smb_fname->st.st_ex_mode) ||
1217 S_ISDIR(smb_fname->st.st_ex_mode) ||
1218 S_ISLNK(smb_fname->st.st_ex_mode))
1224 /*******************************************************************
1225 Should the file be seen by the client?
1226 NOTE: A successful return is no guarantee of the file's existence.
1227 ********************************************************************/
1229 bool is_visible_file(connection_struct *conn, const char *dir_path,
1230 const char *name, SMB_STRUCT_STAT *pst, bool use_veto)
1232 bool hide_unreadable = lp_hide_unreadable(SNUM(conn));
1233 bool hide_unwriteable = lp_hide_unwriteable_files(SNUM(conn));
1234 bool hide_special = lp_hide_special_files(SNUM(conn));
1235 int hide_new_files_timeout = lp_hide_new_files_timeout(SNUM(conn));
1237 struct smb_filename *smb_fname_base = NULL;
1240 if ((strcmp(".",name) == 0) || (strcmp("..",name) == 0)) {
1241 return True; /* . and .. are always visible. */
1244 /* If it's a vetoed file, pretend it doesn't even exist */
1245 if (use_veto && IS_VETO_PATH(conn, name)) {
1246 DEBUG(10,("is_visible_file: file %s is vetoed.\n", name ));
1250 if (hide_unreadable ||
1253 (hide_new_files_timeout != 0))
1255 entry = talloc_asprintf(talloc_tos(), "%s/%s", dir_path, name);
1261 /* Create an smb_filename with stream_name == NULL. */
1262 smb_fname_base = synthetic_smb_fname(talloc_tos(),
1267 if (smb_fname_base == NULL) {
1272 /* If the file name does not exist, there's no point checking
1273 * the configuration options. We succeed, on the basis that the
1274 * checks *might* have passed if the file was present.
1276 if (!VALID_STAT(*pst)) {
1277 if (SMB_VFS_STAT(conn, smb_fname_base) != 0) {
1281 *pst = smb_fname_base->st;
1284 /* Honour _hide unreadable_ option */
1285 if (hide_unreadable &&
1286 !user_can_read_file(conn, smb_fname_base)) {
1287 DEBUG(10,("is_visible_file: file %s is unreadable.\n",
1292 /* Honour _hide unwriteable_ option */
1293 if (hide_unwriteable && !user_can_write_file(conn,
1295 DEBUG(10,("is_visible_file: file %s is unwritable.\n",
1300 /* Honour _hide_special_ option */
1301 if (hide_special && file_is_special(conn, smb_fname_base)) {
1302 DEBUG(10,("is_visible_file: file %s is special.\n",
1308 if (hide_new_files_timeout != 0) {
1310 double age = timespec_elapsed(
1311 &smb_fname_base->st.st_ex_mtime);
1313 if (age < (double)hide_new_files_timeout) {
1322 TALLOC_FREE(smb_fname_base);
1327 static int smb_Dir_destructor(struct smb_Dir *dir_hnd)
1329 files_struct *fsp = dir_hnd->fsp;
1331 SMB_VFS_CLOSEDIR(dir_hnd->conn, dir_hnd->dir);
1333 * The SMB_VFS_CLOSEDIR above
1334 * closes the underlying fd inside
1335 * dirp->fsp, unless fallback_opendir
1336 * was set in which case the fd
1337 * in dir_hnd->fsp->fh->fd isn't
1338 * the one being closed. Close
1341 if (dir_hnd->fallback_opendir) {
1345 SMB_ASSERT(fsp->dptr->dir_hnd == dir_hnd);
1346 fsp->dptr->dir_hnd = NULL;
1347 dir_hnd->fsp = NULL;
1351 /*******************************************************************
1353 ********************************************************************/
1355 static struct smb_Dir *OpenDir_internal(TALLOC_CTX *mem_ctx,
1356 connection_struct *conn,
1357 const struct smb_filename *smb_dname,
1361 struct smb_Dir *dir_hnd = talloc_zero(mem_ctx, struct smb_Dir);
1367 dir_hnd->dir = SMB_VFS_OPENDIR(conn, smb_dname, mask, attr);
1369 if (!dir_hnd->dir) {
1370 DEBUG(5,("OpenDir: Can't open %s. %s\n",
1371 smb_dname->base_name,
1376 dir_hnd->conn = conn;
1378 if (!conn->sconn->using_smb2) {
1380 * The dircache is only needed for SMB1 because SMB1 uses a name
1381 * for the resume wheras SMB2 always continues from the next
1382 * position (unless it's told to restart or close-and-reopen the
1385 dir_hnd->name_cache_size =
1386 lp_directory_name_cache_size(SNUM(conn));
1392 TALLOC_FREE(dir_hnd);
1397 * @brief Open a directory handle by pathname, ensuring it's under the share path.
1399 * First stores the $cwd, then changes directory to the passed in pathname
1400 * uses check_name() to ensure this is under the connection struct share path,
1401 * then operates on a pathname of "." to ensure we're in the same place.
1403 * The returned struct smb_Dir * should have a talloc destrctor added to
1404 * ensure that when the struct is freed the internal POSIX DIR * pointer
1409 * static int sample_smb_Dir_destructor(struct smb_Dir *dirp)
1411 * SMB_VFS_CLOSEDIR(dirp->conn,dirp->dir);
1414 * struct smb_Dir *dir_hnd = open_dir_safely(mem_ctx,
1419 * if (dir_hnd == NULL) {
1422 * talloc_set_destructor(dir_hnd, smb_Dir_destructor);
1427 static struct smb_Dir *open_dir_safely(TALLOC_CTX *ctx,
1428 connection_struct *conn,
1429 const struct smb_filename *smb_dname,
1433 struct smb_Dir *dir_hnd = NULL;
1434 struct smb_filename *smb_fname_cwd = NULL;
1435 struct smb_filename *saved_dir_fname = vfs_GetWd(ctx, conn);
1438 if (saved_dir_fname == NULL) {
1442 if (vfs_ChDir(conn, smb_dname) == -1) {
1446 smb_fname_cwd = synthetic_smb_fname(talloc_tos(),
1451 if (smb_fname_cwd == NULL) {
1456 * Now the directory is pinned, use
1457 * REALPATH to ensure we can access it.
1459 status = check_name(conn, smb_fname_cwd);
1460 if (!NT_STATUS_IS_OK(status)) {
1464 dir_hnd = OpenDir_internal(ctx,
1470 if (dir_hnd == NULL) {
1475 * OpenDir_internal only gets "." as the dir name.
1476 * Store the real dir name here.
1479 dir_hnd->dir_smb_fname = cp_smb_filename(dir_hnd, smb_dname);
1480 if (!dir_hnd->dir_smb_fname) {
1481 TALLOC_FREE(dir_hnd);
1482 SMB_VFS_CLOSEDIR(conn, dir_hnd->dir);
1488 vfs_ChDir(conn, saved_dir_fname);
1489 TALLOC_FREE(saved_dir_fname);
1494 * Simple destructor for OpenDir() use. Don't need to
1495 * care about fsp back pointer as we know we have never
1496 * set it in the OpenDir() code path.
1499 static int smb_Dir_OpenDir_destructor(struct smb_Dir *dir_hnd)
1501 SMB_VFS_CLOSEDIR(dir_hnd->conn, dir_hnd->dir);
1505 struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn,
1506 const struct smb_filename *smb_dname,
1510 struct smb_Dir *dir_hnd = open_dir_safely(mem_ctx,
1515 if (dir_hnd == NULL) {
1518 talloc_set_destructor(dir_hnd, smb_Dir_OpenDir_destructor);
1522 /*******************************************************************
1523 Open a directory from an fsp.
1524 ********************************************************************/
1526 static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn,
1531 struct smb_Dir *dir_hnd = talloc_zero(mem_ctx, struct smb_Dir);
1537 if (!fsp->is_directory) {
1542 if (fsp->fh->fd == -1) {
1547 dir_hnd->conn = conn;
1549 if (!conn->sconn->using_smb2) {
1551 * The dircache is only needed for SMB1 because SMB1 uses a name
1552 * for the resume wheras SMB2 always continues from the next
1553 * position (unless it's told to restart or close-and-reopen the
1556 dir_hnd->name_cache_size =
1557 lp_directory_name_cache_size(SNUM(conn));
1560 dir_hnd->dir_smb_fname = cp_smb_filename(dir_hnd, fsp->fsp_name);
1561 if (!dir_hnd->dir_smb_fname) {
1566 dir_hnd->dir = SMB_VFS_FDOPENDIR(fsp, mask, attr);
1567 if (dir_hnd->dir != NULL) {
1570 DEBUG(10,("OpenDir_fsp: SMB_VFS_FDOPENDIR on %s returned "
1572 dir_hnd->dir_smb_fname->base_name,
1574 if (errno != ENOSYS) {
1579 if (dir_hnd->dir == NULL) {
1580 /* FDOPENDIR is not supported. Use OPENDIR instead. */
1581 TALLOC_FREE(dir_hnd);
1582 dir_hnd = open_dir_safely(mem_ctx,
1587 if (dir_hnd == NULL) {
1592 * Remember if we used the fallback.
1593 * We need to change the destructor
1594 * to also close the fsp file descriptor
1595 * in this case as it isn't the same
1596 * one the directory handle uses.
1599 dir_hnd->fallback_opendir = true;
1602 talloc_set_destructor(dir_hnd, smb_Dir_destructor);
1607 TALLOC_FREE(dir_hnd);
1612 /*******************************************************************
1613 Read from a directory.
1614 Return directory entry, current offset, and optional stat information.
1615 Don't check for veto or invisible files.
1616 ********************************************************************/
1618 const char *ReadDirName(struct smb_Dir *dir_hnd, long *poffset,
1619 SMB_STRUCT_STAT *sbuf, char **ptalloced)
1622 char *talloced = NULL;
1623 connection_struct *conn = dir_hnd->conn;
1625 /* Cheat to allow . and .. to be the first entries returned. */
1626 if (((*poffset == START_OF_DIRECTORY_OFFSET) ||
1627 (*poffset == DOT_DOT_DIRECTORY_OFFSET)) && (dir_hnd->file_number < 2))
1629 if (dir_hnd->file_number == 0) {
1631 *poffset = dir_hnd->offset = START_OF_DIRECTORY_OFFSET;
1634 *poffset = dir_hnd->offset = DOT_DOT_DIRECTORY_OFFSET;
1636 dir_hnd->file_number++;
1641 if (*poffset == END_OF_DIRECTORY_OFFSET) {
1642 *poffset = dir_hnd->offset = END_OF_DIRECTORY_OFFSET;
1646 /* A real offset, seek to it. */
1647 SeekDir(dir_hnd, *poffset);
1649 while ((n = vfs_readdirname(conn, dir_hnd->dir, sbuf, &talloced))) {
1650 /* Ignore . and .. - we've already returned them. */
1652 if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) {
1653 TALLOC_FREE(talloced);
1657 *poffset = dir_hnd->offset = SMB_VFS_TELLDIR(conn, dir_hnd->dir);
1658 *ptalloced = talloced;
1659 dir_hnd->file_number++;
1662 *poffset = dir_hnd->offset = END_OF_DIRECTORY_OFFSET;
1667 /*******************************************************************
1668 Rewind to the start.
1669 ********************************************************************/
1671 void RewindDir(struct smb_Dir *dir_hnd, long *poffset)
1673 SMB_VFS_REWINDDIR(dir_hnd->conn, dir_hnd->dir);
1674 dir_hnd->file_number = 0;
1675 dir_hnd->offset = START_OF_DIRECTORY_OFFSET;
1676 *poffset = START_OF_DIRECTORY_OFFSET;
1679 /*******************************************************************
1681 ********************************************************************/
1683 void SeekDir(struct smb_Dir *dirp, long offset)
1685 if (offset != dirp->offset) {
1686 if (offset == START_OF_DIRECTORY_OFFSET) {
1687 RewindDir(dirp, &offset);
1689 * Ok we should really set the file number here
1690 * to 1 to enable ".." to be returned next. Trouble
1691 * is I'm worried about callers using SeekDir(dirp,0)
1692 * as equivalent to RewindDir(). So leave this alone
1695 } else if (offset == DOT_DOT_DIRECTORY_OFFSET) {
1696 RewindDir(dirp, &offset);
1698 * Set the file number to 2 - we want to get the first
1699 * real file entry (the one we return after "..")
1700 * on the next ReadDir.
1702 dirp->file_number = 2;
1703 } else if (offset == END_OF_DIRECTORY_OFFSET) {
1704 ; /* Don't seek in this case. */
1706 SMB_VFS_SEEKDIR(dirp->conn, dirp->dir, offset);
1708 dirp->offset = offset;
1712 /*******************************************************************
1713 Tell a dir position.
1714 ********************************************************************/
1716 long TellDir(struct smb_Dir *dir_hnd)
1718 return(dir_hnd->offset);
1721 /*******************************************************************
1722 Add an entry into the dcache.
1723 ********************************************************************/
1725 static void DirCacheAdd(struct smb_Dir *dir_hnd, const char *name, long offset)
1727 struct name_cache_entry *e;
1729 if (dir_hnd->name_cache_size == 0) {
1733 if (dir_hnd->name_cache == NULL) {
1734 dir_hnd->name_cache = talloc_zero_array(dir_hnd,
1735 struct name_cache_entry,
1736 dir_hnd->name_cache_size);
1738 if (dir_hnd->name_cache == NULL) {
1743 dir_hnd->name_cache_index = (dir_hnd->name_cache_index+1) %
1744 dir_hnd->name_cache_size;
1745 e = &dir_hnd->name_cache[dir_hnd->name_cache_index];
1746 TALLOC_FREE(e->name);
1747 e->name = talloc_strdup(dir_hnd, name);
1751 /*******************************************************************
1752 Find an entry by name. Leave us at the offset after it.
1753 Don't check for veto or invisible files.
1754 ********************************************************************/
1756 bool SearchDir(struct smb_Dir *dir_hnd, const char *name, long *poffset)
1759 const char *entry = NULL;
1760 char *talloced = NULL;
1761 connection_struct *conn = dir_hnd->conn;
1763 /* Search back in the name cache. */
1764 if (dir_hnd->name_cache_size && dir_hnd->name_cache) {
1765 for (i = dir_hnd->name_cache_index; i >= 0; i--) {
1766 struct name_cache_entry *e = &dir_hnd->name_cache[i];
1767 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1768 *poffset = e->offset;
1769 SeekDir(dir_hnd, e->offset);
1773 for (i = dir_hnd->name_cache_size - 1;
1774 i > dir_hnd->name_cache_index; i--) {
1775 struct name_cache_entry *e = &dir_hnd->name_cache[i];
1776 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1777 *poffset = e->offset;
1778 SeekDir(dir_hnd, e->offset);
1784 /* Not found in the name cache. Rewind directory and start from scratch. */
1785 SMB_VFS_REWINDDIR(conn, dir_hnd->dir);
1786 dir_hnd->file_number = 0;
1787 *poffset = START_OF_DIRECTORY_OFFSET;
1788 while ((entry = ReadDirName(dir_hnd, poffset, NULL, &talloced))) {
1789 if (conn->case_sensitive ? (strcmp(entry, name) == 0) : strequal(entry, name)) {
1790 TALLOC_FREE(talloced);
1793 TALLOC_FREE(talloced);
1798 struct files_below_forall_state {
1801 int (*fn)(struct file_id fid, const struct share_mode_data *data,
1802 void *private_data);
1806 static int files_below_forall_fn(struct file_id fid,
1807 const struct share_mode_data *data,
1810 struct files_below_forall_state *state = private_data;
1811 char tmpbuf[PATH_MAX];
1812 char *fullpath, *to_free;
1815 len = full_path_tos(data->servicepath, data->base_name,
1816 tmpbuf, sizeof(tmpbuf),
1817 &fullpath, &to_free);
1821 if (state->dirpath_len >= len) {
1823 * Filter files above dirpath
1827 if (fullpath[state->dirpath_len] != '/') {
1829 * Filter file that don't have a path separator at the end of
1835 if (memcmp(state->dirpath, fullpath, state->dirpath_len) != 0) {
1842 TALLOC_FREE(to_free);
1843 return state->fn(fid, data, state->private_data);
1846 TALLOC_FREE(to_free);
1850 static int files_below_forall(connection_struct *conn,
1851 const struct smb_filename *dir_name,
1852 int (*fn)(struct file_id fid,
1853 const struct share_mode_data *data,
1854 void *private_data),
1857 struct files_below_forall_state state = {
1859 .private_data = private_data,
1862 char tmpbuf[PATH_MAX];
1865 state.dirpath_len = full_path_tos(conn->connectpath,
1866 dir_name->base_name,
1867 tmpbuf, sizeof(tmpbuf),
1868 &state.dirpath, &to_free);
1869 if (state.dirpath_len == -1) {
1873 ret = share_mode_forall(files_below_forall_fn, &state);
1874 TALLOC_FREE(to_free);
1878 struct have_file_open_below_state {
1882 static int have_file_open_below_fn(struct file_id fid,
1883 const struct share_mode_data *data,
1886 struct have_file_open_below_state *state = private_data;
1887 state->found_one = true;
1891 bool have_file_open_below(connection_struct *conn,
1892 const struct smb_filename *name)
1894 struct have_file_open_below_state state = {
1899 if (!VALID_STAT(name->st)) {
1902 if (!S_ISDIR(name->st.st_ex_mode)) {
1906 ret = files_below_forall(conn, name, have_file_open_below_fn, &state);
1911 return state.found_one;
1914 /*****************************************************************
1915 Is this directory empty ?
1916 *****************************************************************/
1918 NTSTATUS can_delete_directory_fsp(files_struct *fsp)
1920 NTSTATUS status = NT_STATUS_OK;
1922 const char *dname = NULL;
1923 const char *dirname = fsp->fsp_name->base_name;
1924 char *talloced = NULL;
1926 struct connection_struct *conn = fsp->conn;
1927 struct smb_Dir *dir_hnd = OpenDir(talloc_tos(),
1934 return map_nt_error_from_unix(errno);
1937 while ((dname = ReadDirName(dir_hnd, &dirpos, &st, &talloced))) {
1938 /* Quick check for "." and ".." */
1939 if (dname[0] == '.') {
1940 if (!dname[1] || (dname[1] == '.' && !dname[2])) {
1941 TALLOC_FREE(talloced);
1946 if (!is_visible_file(conn, dirname, dname, &st, True)) {
1947 TALLOC_FREE(talloced);
1951 DEBUG(10,("got name %s - can't delete\n",
1953 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
1956 TALLOC_FREE(talloced);
1957 TALLOC_FREE(dir_hnd);
1959 if (!NT_STATUS_IS_OK(status)) {
1963 if (!(fsp->posix_flags & FSP_POSIX_FLAGS_RENAME) &&
1964 lp_strict_rename(SNUM(conn)) &&
1965 have_file_open_below(fsp->conn, fsp->fsp_name))
1967 return NT_STATUS_ACCESS_DENIED;
1970 return NT_STATUS_OK;