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 all dptrs for a cnum.
175 ****************************************************************************/
177 void dptr_closecnum(connection_struct *conn)
179 struct dptr_struct *dptr, *next;
180 struct smbd_server_connection *sconn = conn->sconn;
186 for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
188 if (dptr->conn == conn) {
189 files_struct *fsp = dptr->dir_hnd->fsp;
190 close_file(NULL, fsp, NORMAL_CLOSE);
196 /****************************************************************************
197 Create a new dir ptr. If the flag old_handle is true then we must allocate
198 from the bitmap range 0 - 255 as old SMBsearch directory handles are only
199 one byte long. If old_handle is false we allocate from the range
200 256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
201 a directory handle is never zero.
202 wcard must not be zero.
203 ****************************************************************************/
205 NTSTATUS dptr_create(connection_struct *conn,
206 struct smb_request *req,
214 struct dptr_struct **dptr_ret)
216 struct smbd_server_connection *sconn = conn->sconn;
217 struct dptr_struct *dptr = NULL;
218 struct smb_Dir *dir_hnd;
220 DBG_INFO("dir=%s\n", fsp_str_dbg(fsp));
223 DEBUG(0,("dptr_create: called with fake connection_struct\n"));
224 return NT_STATUS_INTERNAL_ERROR;
228 return NT_STATUS_INVALID_PARAMETER;
231 if (!(fsp->access_mask & SEC_DIR_LIST)) {
232 DBG_INFO("dptr_create: directory %s "
233 "not open for LIST access\n",
235 return NT_STATUS_ACCESS_DENIED;
237 dir_hnd = OpenDir_fsp(NULL, conn, fsp, wcard, attr);
239 return map_nt_error_from_unix(errno);
242 dptr = talloc_zero(NULL, struct dptr_struct);
244 DEBUG(0,("talloc fail in dptr_create.\n"));
245 TALLOC_FREE(dir_hnd);
246 return NT_STATUS_NO_MEMORY;
249 dptr->smb_dname = cp_smb_filename(dptr, fsp->fsp_name);
250 if (dptr->smb_dname == NULL) {
252 TALLOC_FREE(dir_hnd);
253 return NT_STATUS_NO_MEMORY;
256 dptr->dir_hnd = dir_hnd;
258 dptr->expect_close = expect_close;
259 dptr->wcard = talloc_strdup(dptr, wcard);
262 TALLOC_FREE(dir_hnd);
263 return NT_STATUS_NO_MEMORY;
265 if ((req != NULL && req->posix_pathnames) ||
266 (wcard[0] == '.' && wcard[1] == 0)) {
267 dptr->has_wild = True;
269 dptr->has_wild = wcard_has_wild;
274 if (sconn->using_smb2) {
281 * This is an old-style SMBsearch request. Ensure the
282 * value we return will fit in the range 1-255.
285 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 0);
287 if(dptr->dnum == -1 || dptr->dnum > 254) {
288 DBG_ERR("returned %d: Error - all old "
289 "dirptrs in use ?\n",
292 TALLOC_FREE(dir_hnd);
293 return NT_STATUS_TOO_MANY_OPENED_FILES;
298 * This is a new-style trans2 request. Allocate from
299 * a range that will return 256 - MAX_DIRECTORY_HANDLES.
302 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 255);
304 if(dptr->dnum == -1 || dptr->dnum < 255) {
305 DBG_ERR("returned %d: Error - all new "
306 "dirptrs in use ?\n",
309 TALLOC_FREE(dir_hnd);
310 return NT_STATUS_TOO_MANY_OPENED_FILES;
314 bitmap_set(sconn->searches.dptr_bmap, dptr->dnum);
316 dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
318 DLIST_ADD(sconn->searches.dirptrs, dptr);
321 DBG_INFO("creating new dirptr [%d] for path [%s], expect_close = %d\n",
322 dptr->dnum, fsp_str_dbg(fsp), expect_close);
330 /****************************************************************************
331 Wrapper functions to access the lower level directory handles.
332 ****************************************************************************/
334 void dptr_CloseDir(files_struct *fsp)
336 struct smbd_server_connection *sconn = NULL;
338 if (fsp->dptr == NULL) {
341 sconn = fsp->dptr->conn->sconn;
344 * The destructor for the struct smb_Dir (fsp->dptr->dir_hnd)
345 * now handles all resource deallocation.
348 DBG_INFO("closing dptr key %d\n", fsp->dptr->dnum);
350 if (sconn != NULL && !sconn->using_smb2) {
351 DLIST_REMOVE(sconn->searches.dirptrs, fsp->dptr);
354 * Free the dnum in the bitmap. Remember the dnum value is
355 * always biased by one with respect to the bitmap.
358 if (!bitmap_query(sconn->searches.dptr_bmap,
359 fsp->dptr->dnum - 1))
361 DBG_ERR("closing dnum = %d and bitmap not set !\n",
365 bitmap_clear(sconn->searches.dptr_bmap, fsp->dptr->dnum - 1);
368 TALLOC_FREE(fsp->dptr->dir_hnd);
369 TALLOC_FREE(fsp->dptr);
372 void dptr_SeekDir(struct dptr_struct *dptr, long offset)
374 SeekDir(dptr->dir_hnd, offset);
377 long dptr_TellDir(struct dptr_struct *dptr)
379 return TellDir(dptr->dir_hnd);
382 bool dptr_has_wild(struct dptr_struct *dptr)
384 return dptr->has_wild;
387 int dptr_dnum(struct dptr_struct *dptr)
392 bool dptr_get_priv(struct dptr_struct *dptr)
397 void dptr_set_priv(struct dptr_struct *dptr)
402 /****************************************************************************
403 Return the next visible file name, skipping veto'd and invisible files.
404 ****************************************************************************/
406 static const char *dptr_normal_ReadDirName(struct dptr_struct *dptr,
407 long *poffset, SMB_STRUCT_STAT *pst,
410 /* Normal search for the next file. */
412 char *talloced = NULL;
414 while ((name = ReadDirName(dptr->dir_hnd, poffset, pst, &talloced))
416 if (is_visible_file(dptr->conn,
417 dptr->smb_dname->base_name,
421 *ptalloced = talloced;
424 TALLOC_FREE(talloced);
429 /****************************************************************************
430 Return the next visible file name, skipping veto'd and invisible files.
431 ****************************************************************************/
433 static char *dptr_ReadDirName(TALLOC_CTX *ctx,
434 struct dptr_struct *dptr,
436 SMB_STRUCT_STAT *pst)
438 struct smb_filename smb_fname_base;
440 const char *name_temp = NULL;
441 char *talloced = NULL;
442 char *pathreal = NULL;
443 char *found_name = NULL;
446 SET_STAT_INVALID(*pst);
448 if (dptr->has_wild || dptr->did_stat) {
449 name_temp = dptr_normal_ReadDirName(dptr, poffset, pst,
451 if (name_temp == NULL) {
454 if (talloced != NULL) {
455 return talloc_move(ctx, &talloced);
457 return talloc_strdup(ctx, name_temp);
460 /* If poffset is -1 then we know we returned this name before and we
461 * have no wildcards. We're at the end of the directory. */
462 if (*poffset == END_OF_DIRECTORY_OFFSET) {
466 /* We know the stored wcard contains no wildcard characters.
467 * See if we can match with a stat call. If we can't, then set
468 * did_stat to true to ensure we only do this once and keep
471 dptr->did_stat = true;
473 /* First check if it should be visible. */
474 if (!is_visible_file(dptr->conn,
475 dptr->smb_dname->base_name,
479 /* This only returns false if the file was found, but
480 is explicitly not visible. Set us to end of
481 directory, but return NULL as we know we can't ever
486 if (VALID_STAT(*pst)) {
487 name = talloc_strdup(ctx, dptr->wcard);
491 pathreal = talloc_asprintf(ctx,
493 dptr->smb_dname->base_name,
498 /* Create an smb_filename with stream_name == NULL. */
499 smb_fname_base = (struct smb_filename) { .base_name = pathreal };
501 if (SMB_VFS_STAT(dptr->conn, &smb_fname_base) == 0) {
502 *pst = smb_fname_base.st;
503 name = talloc_strdup(ctx, dptr->wcard);
506 /* If we get any other error than ENOENT or ENOTDIR
507 then the file exists we just can't stat it. */
508 if (errno != ENOENT && errno != ENOTDIR) {
509 name = talloc_strdup(ctx, dptr->wcard);
514 /* Stat failed. We know this is authoratiative if we are
515 * providing case sensitive semantics or the underlying
516 * filesystem is case sensitive.
518 if (dptr->conn->case_sensitive ||
519 !(dptr->conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH))
525 * Try case-insensitive stat if the fs has the ability. This avoids
526 * scanning the whole directory.
528 ret = SMB_VFS_GET_REAL_FILENAME(dptr->conn,
529 dptr->smb_dname->base_name,
536 } else if (errno == ENOENT) {
537 /* The case-insensitive lookup was authoritative. */
541 TALLOC_FREE(pathreal);
543 name_temp = dptr_normal_ReadDirName(dptr, poffset, pst, &talloced);
544 if (name_temp == NULL) {
547 if (talloced != NULL) {
548 return talloc_move(ctx, &talloced);
550 return talloc_strdup(ctx, name_temp);
553 TALLOC_FREE(pathreal);
555 /* We need to set the underlying dir_hnd offset to -1
556 * also as this function is usually called with the
557 * output from TellDir. */
558 dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
562 /****************************************************************************
563 Search for a file by name, skipping veto'ed and not visible files.
564 ****************************************************************************/
566 bool dptr_SearchDir(struct dptr_struct *dptr, const char *name, long *poffset, SMB_STRUCT_STAT *pst)
568 SET_STAT_INVALID(*pst);
570 if (!dptr->has_wild && (dptr->dir_hnd->offset == END_OF_DIRECTORY_OFFSET)) {
571 /* This is a singleton directory and we're already at the end. */
572 *poffset = END_OF_DIRECTORY_OFFSET;
576 return SearchDir(dptr->dir_hnd, name, poffset);
579 /****************************************************************************
580 Map a native directory offset to a 32-bit cookie.
581 ****************************************************************************/
583 static uint32_t map_dir_offset_to_wire(struct dptr_struct *dptr, long offset)
588 if (offset == END_OF_DIRECTORY_OFFSET) {
589 return WIRE_END_OF_DIRECTORY_OFFSET;
590 } else if(offset == START_OF_DIRECTORY_OFFSET) {
591 return WIRE_START_OF_DIRECTORY_OFFSET;
592 } else if (offset == DOT_DOT_DIRECTORY_OFFSET) {
593 return WIRE_DOT_DOT_DIRECTORY_OFFSET;
595 if (sizeof(long) == 4) {
596 /* 32-bit machine. We can cheat... */
597 return (uint32_t)offset;
599 if (dptr->dptr_cache == NULL) {
600 /* Lazy initialize cache. */
601 dptr->dptr_cache = memcache_init(dptr, 0);
602 if (dptr->dptr_cache == NULL) {
603 return WIRE_END_OF_DIRECTORY_OFFSET;
606 /* Have we seen this offset before ? */
607 key.data = (void *)&offset;
608 key.length = sizeof(offset);
609 if (memcache_lookup(dptr->dptr_cache,
610 SMB1_SEARCH_OFFSET_MAP,
613 uint32_t wire_offset;
614 SMB_ASSERT(val.length == sizeof(wire_offset));
615 memcpy(&wire_offset, val.data, sizeof(wire_offset));
616 DEBUG(10,("found wire %u <-> offset %ld\n",
617 (unsigned int)wire_offset,
622 /* Allocate a new wire cookie. */
625 } while (dptr->counter == WIRE_START_OF_DIRECTORY_OFFSET ||
626 dptr->counter == WIRE_END_OF_DIRECTORY_OFFSET ||
627 dptr->counter == WIRE_DOT_DOT_DIRECTORY_OFFSET);
628 /* Store it in the cache. */
629 key.data = (void *)&offset;
630 key.length = sizeof(offset);
631 val.data = (void *)&dptr->counter;
632 val.length = sizeof(dptr->counter); /* MUST BE uint32_t ! */
633 memcache_add(dptr->dptr_cache,
634 SMB1_SEARCH_OFFSET_MAP,
637 /* And the reverse mapping for lookup from
638 map_wire_to_dir_offset(). */
639 memcache_add(dptr->dptr_cache,
640 SMB1_SEARCH_OFFSET_MAP,
643 DEBUG(10,("stored wire %u <-> offset %ld\n",
644 (unsigned int)dptr->counter,
646 return dptr->counter;
649 /****************************************************************************
650 Fill the 5 byte server reserved dptr field.
651 ****************************************************************************/
653 bool dptr_fill(struct smbd_server_connection *sconn,
654 char *buf1,unsigned int key)
656 unsigned char *buf = (unsigned char *)buf1;
657 struct dptr_struct *dptr = dptr_get(sconn, key);
658 uint32_t wire_offset;
660 DEBUG(1,("filling null dirptr %d\n",key));
663 wire_offset = map_dir_offset_to_wire(dptr,TellDir(dptr->dir_hnd));
664 DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key,
665 (long)dptr->dir_hnd,(int)wire_offset));
667 SIVAL(buf,1,wire_offset);
671 /****************************************************************************
672 Map a 32-bit wire cookie to a native directory offset.
673 ****************************************************************************/
675 static long map_wire_to_dir_offset(struct dptr_struct *dptr, uint32_t wire_offset)
680 if (wire_offset == WIRE_END_OF_DIRECTORY_OFFSET) {
681 return END_OF_DIRECTORY_OFFSET;
682 } else if(wire_offset == WIRE_START_OF_DIRECTORY_OFFSET) {
683 return START_OF_DIRECTORY_OFFSET;
684 } else if (wire_offset == WIRE_DOT_DOT_DIRECTORY_OFFSET) {
685 return DOT_DOT_DIRECTORY_OFFSET;
687 if (sizeof(long) == 4) {
688 /* 32-bit machine. We can cheat... */
689 return (long)wire_offset;
691 if (dptr->dptr_cache == NULL) {
692 /* Logic error, cache should be initialized. */
693 return END_OF_DIRECTORY_OFFSET;
695 key.data = (void *)&wire_offset;
696 key.length = sizeof(wire_offset);
697 if (memcache_lookup(dptr->dptr_cache,
698 SMB1_SEARCH_OFFSET_MAP,
703 SMB_ASSERT(val.length == sizeof(offset));
704 memcpy(&offset, val.data, sizeof(offset));
705 DEBUG(10,("lookup wire %u <-> offset %ld\n",
706 (unsigned int)wire_offset,
710 return END_OF_DIRECTORY_OFFSET;
713 /****************************************************************************
714 Return the associated fsp and seek the dir_hnd on it it given the 5 byte
716 ****************************************************************************/
718 files_struct *dptr_fetch_fsp(struct smbd_server_connection *sconn,
721 unsigned int key = *(unsigned char *)buf;
722 struct dptr_struct *dptr = dptr_get(sconn, key);
723 uint32_t wire_offset;
727 DEBUG(3,("fetched null dirptr %d\n",key));
731 wire_offset = IVAL(buf,1);
732 seekoff = map_wire_to_dir_offset(dptr, wire_offset);
733 SeekDir(dptr->dir_hnd,seekoff);
734 DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
735 key, dptr->smb_dname->base_name, (int)seekoff));
736 return dptr->dir_hnd->fsp;
739 /****************************************************************************
740 Fetch the fsp associated with the dptr_num.
741 ****************************************************************************/
743 files_struct *dptr_fetch_lanman2_fsp(struct smbd_server_connection *sconn,
746 struct dptr_struct *dptr = dptr_get(sconn, dptr_num);
750 DBG_NOTICE("fetching dirptr %d for path %s\n",
752 dptr->smb_dname->base_name);
753 return dptr->dir_hnd->fsp;
756 static bool mangle_mask_match(connection_struct *conn,
757 const char *filename,
762 if (!name_to_8_3(filename,mname,False,conn->params)) {
765 return mask_match_search(mname,mask,False);
768 bool smbd_dirptr_get_entry(TALLOC_CTX *ctx,
769 struct dptr_struct *dirptr,
775 bool (*match_fn)(TALLOC_CTX *ctx,
780 bool (*mode_fn)(TALLOC_CTX *ctx,
782 struct smb_filename *smb_fname,
787 struct smb_filename **_smb_fname,
791 connection_struct *conn = dirptr->conn;
794 const char *dpath = dirptr->smb_dname->base_name;
795 bool dirptr_path_is_dot = ISDOT(dpath);
800 pathlen = strlen(dpath);
801 slashlen = ( dpath[pathlen-1] != '/') ? 1 : 0;
806 SMB_STRUCT_STAT sbuf = { 0 };
810 char *pathreal = NULL;
811 struct smb_filename smb_fname;
815 cur_offset = dptr_TellDir(dirptr);
816 prev_offset = cur_offset;
817 dname = dptr_ReadDirName(ctx, dirptr, &cur_offset, &sbuf);
819 DEBUG(6,("smbd_dirptr_get_entry: dirptr 0x%lx now at offset %ld\n",
820 (long)dirptr, cur_offset));
826 isdots = (ISDOT(dname) || ISDOTDOT(dname));
827 if (dont_descend && !isdots) {
833 * fname may get mangled, dname is never mangled.
834 * Whenever we're accessing the filesystem we use
835 * pathreal which is composed from dname.
838 ok = match_fn(ctx, private_data, dname, mask, &fname);
846 * pathreal = talloc_asprintf(ctx, "%s%s%s", dirptr->path,
847 * needslash?"/":"", dname);
848 * but this was measurably slower than doing the memcpy.
851 pathreal = talloc_array(
853 pathlen + slashlen + talloc_get_size(dname));
861 * We don't want to pass ./xxx to modules below us so don't
862 * add the path if it is just . by itself.
864 if (dirptr_path_is_dot) {
865 memcpy(pathreal, dname, talloc_get_size(dname));
867 memcpy(pathreal, dpath, pathlen);
868 pathreal[pathlen] = '/';
869 memcpy(pathreal + slashlen + pathlen, dname,
870 talloc_get_size(dname));
873 /* Create smb_fname with NULL stream_name. */
874 smb_fname = (struct smb_filename) {
875 .base_name = pathreal, .st = sbuf
878 ok = mode_fn(ctx, private_data, &smb_fname, get_dosmode, &mode);
882 TALLOC_FREE(pathreal);
886 if (!dir_check_ftype(mode, dirtype)) {
887 DEBUG(5,("[%s] attribs 0x%x didn't match 0x%x\n",
888 fname, (unsigned int)mode, (unsigned int)dirtype));
891 TALLOC_FREE(pathreal);
896 struct timespec write_time_ts;
897 struct file_id fileid;
899 fileid = vfs_file_id_from_sbuf(conn,
901 get_file_infos(fileid, 0, NULL, &write_time_ts);
902 if (!null_timespec(write_time_ts)) {
903 update_stat_ex_mtime(&smb_fname.st,
908 DEBUG(3,("smbd_dirptr_get_entry mask=[%s] found %s "
910 mask, smb_fname_str_dbg(&smb_fname),
913 if (!conn->sconn->using_smb2) {
915 * The dircache is only needed for SMB1 because SMB1
916 * uses a name for the resume wheras SMB2 always
917 * continues from the next position (unless it's told to
918 * restart or close-and-reopen the listing).
920 DirCacheAdd(dirptr->dir_hnd, dname, cur_offset);
925 *_smb_fname = cp_smb_filename(ctx, &smb_fname);
926 TALLOC_FREE(pathreal);
927 if (*_smb_fname == NULL) {
932 *_prev_offset = prev_offset;
940 /****************************************************************************
941 Get an 8.3 directory entry.
942 ****************************************************************************/
944 static bool smbd_dirptr_8_3_match_fn(TALLOC_CTX *ctx,
950 connection_struct *conn = (connection_struct *)private_data;
952 if ((strcmp(mask,"*.*") == 0) ||
953 mask_match_search(dname, mask, false) ||
954 mangle_mask_match(conn, dname, mask)) {
958 * Ensure we can push the original name as UCS2. If
959 * not, then just don't return this name.
963 size_t len = (strlen(dname) + 2) * 4; /* Allow enough space. */
964 uint8_t *tmp = talloc_array(talloc_tos(),
968 status = srvstr_push(NULL,
969 FLAGS2_UNICODE_STRINGS,
978 if (!NT_STATUS_IS_OK(status)) {
982 if (!mangle_is_8_3(dname, false, conn->params)) {
983 bool ok = name_to_8_3(dname, mname, false,
993 *_fname = talloc_strdup(ctx, fname);
994 if (*_fname == NULL) {
1004 static bool smbd_dirptr_8_3_mode_fn(TALLOC_CTX *ctx,
1006 struct smb_filename *smb_fname,
1010 connection_struct *conn = (connection_struct *)private_data;
1012 if (!VALID_STAT(smb_fname->st)) {
1013 if ((SMB_VFS_STAT(conn, smb_fname)) != 0) {
1014 DEBUG(5,("smbd_dirptr_8_3_mode_fn: "
1015 "Couldn't stat [%s]. Error "
1017 smb_fname_str_dbg(smb_fname),
1023 *_mode = dos_mode(conn, smb_fname);
1027 bool get_dir_entry(TALLOC_CTX *ctx,
1028 struct dptr_struct *dirptr,
1034 struct timespec *_date,
1038 connection_struct *conn = dirptr->conn;
1040 struct smb_filename *smb_fname = NULL;
1045 ok = smbd_dirptr_get_entry(ctx,
1052 smbd_dirptr_8_3_match_fn,
1053 smbd_dirptr_8_3_mode_fn,
1063 *_fname = talloc_move(ctx, &fname);
1064 *_size = smb_fname->st.st_ex_size;
1066 *_date = smb_fname->st.st_ex_mtime;
1067 TALLOC_FREE(smb_fname);
1071 /*******************************************************************
1072 Check to see if a user can read a file. This is only approximate,
1073 it is used as part of the "hide unreadable" option. Don't
1074 use it for anything security sensitive.
1075 ********************************************************************/
1077 static bool user_can_read_file(connection_struct *conn,
1078 struct smb_filename *smb_fname)
1081 uint32_t rejected_share_access = 0;
1082 uint32_t rejected_mask = 0;
1083 struct security_descriptor *sd = NULL;
1084 uint32_t access_mask = FILE_READ_DATA|
1086 FILE_READ_ATTRIBUTES|
1087 SEC_STD_READ_CONTROL;
1090 * Never hide files from the root user.
1091 * We use (uid_t)0 here not sec_initial_uid()
1092 * as make test uses a single user context.
1095 if (get_current_uid(conn) == (uid_t)0) {
1100 * We can't directly use smbd_check_access_rights()
1101 * here, as this implicitly grants FILE_READ_ATTRIBUTES
1102 * which the Windows access-based-enumeration code
1103 * explicitly checks for on the file security descriptor.
1106 * https://bugzilla.samba.org/show_bug.cgi?id=10252
1108 * and the smb2.acl2.ACCESSBASED test for details.
1111 rejected_share_access = access_mask & ~(conn->share_access);
1112 if (rejected_share_access) {
1113 DEBUG(10, ("rejected share access 0x%x "
1115 (unsigned int)access_mask,
1116 smb_fname_str_dbg(smb_fname),
1117 (unsigned int)rejected_share_access ));
1121 status = SMB_VFS_GET_NT_ACL(conn,
1129 if (!NT_STATUS_IS_OK(status)) {
1130 DEBUG(10, ("Could not get acl "
1132 smb_fname_str_dbg(smb_fname),
1133 nt_errstr(status)));
1137 status = se_file_access_check(sd,
1138 get_current_nttok(conn),
1145 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1146 DEBUG(10,("rejected bits 0x%x read access for %s\n",
1147 (unsigned int)rejected_mask,
1148 smb_fname_str_dbg(smb_fname) ));
1154 /*******************************************************************
1155 Check to see if a user can write a file (and only files, we do not
1156 check dirs on this one). This is only approximate,
1157 it is used as part of the "hide unwriteable" option. Don't
1158 use it for anything security sensitive.
1159 ********************************************************************/
1161 static bool user_can_write_file(connection_struct *conn,
1162 const struct smb_filename *smb_fname)
1165 * Never hide files from the root user.
1166 * We use (uid_t)0 here not sec_initial_uid()
1167 * as make test uses a single user context.
1170 if (get_current_uid(conn) == (uid_t)0) {
1174 SMB_ASSERT(VALID_STAT(smb_fname->st));
1176 /* Pseudo-open the file */
1178 if(S_ISDIR(smb_fname->st.st_ex_mode)) {
1182 return can_write_to_file(conn, smb_fname);
1185 /*******************************************************************
1186 Is a file a "special" type ?
1187 ********************************************************************/
1189 static bool file_is_special(connection_struct *conn,
1190 const struct smb_filename *smb_fname)
1193 * Never hide files from the root user.
1194 * We use (uid_t)0 here not sec_initial_uid()
1195 * as make test uses a single user context.
1198 if (get_current_uid(conn) == (uid_t)0) {
1202 SMB_ASSERT(VALID_STAT(smb_fname->st));
1204 if (S_ISREG(smb_fname->st.st_ex_mode) ||
1205 S_ISDIR(smb_fname->st.st_ex_mode) ||
1206 S_ISLNK(smb_fname->st.st_ex_mode))
1212 /*******************************************************************
1213 Should the file be seen by the client?
1214 NOTE: A successful return is no guarantee of the file's existence.
1215 ********************************************************************/
1217 bool is_visible_file(connection_struct *conn, const char *dir_path,
1218 const char *name, SMB_STRUCT_STAT *pst, bool use_veto)
1220 bool hide_unreadable = lp_hide_unreadable(SNUM(conn));
1221 bool hide_unwriteable = lp_hide_unwriteable_files(SNUM(conn));
1222 bool hide_special = lp_hide_special_files(SNUM(conn));
1223 int hide_new_files_timeout = lp_hide_new_files_timeout(SNUM(conn));
1225 struct smb_filename *smb_fname_base = NULL;
1228 if ((strcmp(".",name) == 0) || (strcmp("..",name) == 0)) {
1229 return True; /* . and .. are always visible. */
1232 /* If it's a vetoed file, pretend it doesn't even exist */
1233 if (use_veto && IS_VETO_PATH(conn, name)) {
1234 DEBUG(10,("is_visible_file: file %s is vetoed.\n", name ));
1238 if (hide_unreadable ||
1241 (hide_new_files_timeout != 0))
1243 entry = talloc_asprintf(talloc_tos(), "%s/%s", dir_path, name);
1249 /* Create an smb_filename with stream_name == NULL. */
1250 smb_fname_base = synthetic_smb_fname(talloc_tos(),
1255 if (smb_fname_base == NULL) {
1260 /* If the file name does not exist, there's no point checking
1261 * the configuration options. We succeed, on the basis that the
1262 * checks *might* have passed if the file was present.
1264 if (!VALID_STAT(*pst)) {
1265 if (SMB_VFS_STAT(conn, smb_fname_base) != 0) {
1269 *pst = smb_fname_base->st;
1272 /* Honour _hide unreadable_ option */
1273 if (hide_unreadable &&
1274 !user_can_read_file(conn, smb_fname_base)) {
1275 DEBUG(10,("is_visible_file: file %s is unreadable.\n",
1280 /* Honour _hide unwriteable_ option */
1281 if (hide_unwriteable && !user_can_write_file(conn,
1283 DEBUG(10,("is_visible_file: file %s is unwritable.\n",
1288 /* Honour _hide_special_ option */
1289 if (hide_special && file_is_special(conn, smb_fname_base)) {
1290 DEBUG(10,("is_visible_file: file %s is special.\n",
1296 if (hide_new_files_timeout != 0) {
1298 double age = timespec_elapsed(
1299 &smb_fname_base->st.st_ex_mtime);
1301 if (age < (double)hide_new_files_timeout) {
1310 TALLOC_FREE(smb_fname_base);
1315 static int smb_Dir_destructor(struct smb_Dir *dir_hnd)
1317 files_struct *fsp = dir_hnd->fsp;
1319 SMB_VFS_CLOSEDIR(dir_hnd->conn, dir_hnd->dir);
1321 * The SMB_VFS_CLOSEDIR above
1322 * closes the underlying fd inside
1323 * dirp->fsp, unless fallback_opendir
1324 * was set in which case the fd
1325 * in dir_hnd->fsp->fh->fd isn't
1326 * the one being closed. Close
1329 if (dir_hnd->fallback_opendir) {
1333 SMB_ASSERT(fsp->dptr->dir_hnd == dir_hnd);
1334 fsp->dptr->dir_hnd = NULL;
1335 dir_hnd->fsp = NULL;
1339 /*******************************************************************
1341 ********************************************************************/
1343 static struct smb_Dir *OpenDir_internal(TALLOC_CTX *mem_ctx,
1344 connection_struct *conn,
1345 const struct smb_filename *smb_dname,
1349 struct smb_Dir *dir_hnd = talloc_zero(mem_ctx, struct smb_Dir);
1355 dir_hnd->dir = SMB_VFS_OPENDIR(conn, smb_dname, mask, attr);
1357 if (!dir_hnd->dir) {
1358 DEBUG(5,("OpenDir: Can't open %s. %s\n",
1359 smb_dname->base_name,
1364 dir_hnd->conn = conn;
1366 if (!conn->sconn->using_smb2) {
1368 * The dircache is only needed for SMB1 because SMB1 uses a name
1369 * for the resume wheras SMB2 always continues from the next
1370 * position (unless it's told to restart or close-and-reopen the
1373 dir_hnd->name_cache_size =
1374 lp_directory_name_cache_size(SNUM(conn));
1380 TALLOC_FREE(dir_hnd);
1385 * @brief Open a directory handle by pathname, ensuring it's under the share path.
1387 * First stores the $cwd, then changes directory to the passed in pathname
1388 * uses check_name() to ensure this is under the connection struct share path,
1389 * then operates on a pathname of "." to ensure we're in the same place.
1391 * The returned struct smb_Dir * should have a talloc destrctor added to
1392 * ensure that when the struct is freed the internal POSIX DIR * pointer
1397 * static int sample_smb_Dir_destructor(struct smb_Dir *dirp)
1399 * SMB_VFS_CLOSEDIR(dirp->conn,dirp->dir);
1402 * struct smb_Dir *dir_hnd = open_dir_safely(mem_ctx,
1407 * if (dir_hnd == NULL) {
1410 * talloc_set_destructor(dir_hnd, smb_Dir_destructor);
1415 static struct smb_Dir *open_dir_safely(TALLOC_CTX *ctx,
1416 connection_struct *conn,
1417 const struct smb_filename *smb_dname,
1421 struct smb_Dir *dir_hnd = NULL;
1422 struct smb_filename *smb_fname_cwd = NULL;
1423 struct smb_filename *saved_dir_fname = vfs_GetWd(ctx, conn);
1426 if (saved_dir_fname == NULL) {
1430 if (vfs_ChDir(conn, smb_dname) == -1) {
1434 smb_fname_cwd = synthetic_smb_fname(talloc_tos(),
1439 if (smb_fname_cwd == NULL) {
1444 * Now the directory is pinned, use
1445 * REALPATH to ensure we can access it.
1447 status = check_name(conn, smb_fname_cwd);
1448 if (!NT_STATUS_IS_OK(status)) {
1452 dir_hnd = OpenDir_internal(ctx,
1458 if (dir_hnd == NULL) {
1463 * OpenDir_internal only gets "." as the dir name.
1464 * Store the real dir name here.
1467 dir_hnd->dir_smb_fname = cp_smb_filename(dir_hnd, smb_dname);
1468 if (!dir_hnd->dir_smb_fname) {
1469 TALLOC_FREE(dir_hnd);
1470 SMB_VFS_CLOSEDIR(conn, dir_hnd->dir);
1476 vfs_ChDir(conn, saved_dir_fname);
1477 TALLOC_FREE(saved_dir_fname);
1482 * Simple destructor for OpenDir() use. Don't need to
1483 * care about fsp back pointer as we know we have never
1484 * set it in the OpenDir() code path.
1487 static int smb_Dir_OpenDir_destructor(struct smb_Dir *dir_hnd)
1489 SMB_VFS_CLOSEDIR(dir_hnd->conn, dir_hnd->dir);
1493 struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn,
1494 const struct smb_filename *smb_dname,
1498 struct smb_Dir *dir_hnd = open_dir_safely(mem_ctx,
1503 if (dir_hnd == NULL) {
1506 talloc_set_destructor(dir_hnd, smb_Dir_OpenDir_destructor);
1510 /*******************************************************************
1511 Open a directory from an fsp.
1512 ********************************************************************/
1514 static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn,
1519 struct smb_Dir *dir_hnd = talloc_zero(mem_ctx, struct smb_Dir);
1525 if (!fsp->is_directory) {
1530 if (fsp->fh->fd == -1) {
1535 dir_hnd->conn = conn;
1537 if (!conn->sconn->using_smb2) {
1539 * The dircache is only needed for SMB1 because SMB1 uses a name
1540 * for the resume wheras SMB2 always continues from the next
1541 * position (unless it's told to restart or close-and-reopen the
1544 dir_hnd->name_cache_size =
1545 lp_directory_name_cache_size(SNUM(conn));
1548 dir_hnd->dir_smb_fname = cp_smb_filename(dir_hnd, fsp->fsp_name);
1549 if (!dir_hnd->dir_smb_fname) {
1554 dir_hnd->dir = SMB_VFS_FDOPENDIR(fsp, mask, attr);
1555 if (dir_hnd->dir != NULL) {
1558 DEBUG(10,("OpenDir_fsp: SMB_VFS_FDOPENDIR on %s returned "
1560 dir_hnd->dir_smb_fname->base_name,
1562 if (errno != ENOSYS) {
1567 if (dir_hnd->dir == NULL) {
1568 /* FDOPENDIR is not supported. Use OPENDIR instead. */
1569 TALLOC_FREE(dir_hnd);
1570 dir_hnd = open_dir_safely(mem_ctx,
1575 if (dir_hnd == NULL) {
1580 * Remember if we used the fallback.
1581 * We need to change the destructor
1582 * to also close the fsp file descriptor
1583 * in this case as it isn't the same
1584 * one the directory handle uses.
1587 dir_hnd->fallback_opendir = true;
1590 talloc_set_destructor(dir_hnd, smb_Dir_destructor);
1595 TALLOC_FREE(dir_hnd);
1600 /*******************************************************************
1601 Read from a directory.
1602 Return directory entry, current offset, and optional stat information.
1603 Don't check for veto or invisible files.
1604 ********************************************************************/
1606 const char *ReadDirName(struct smb_Dir *dir_hnd, long *poffset,
1607 SMB_STRUCT_STAT *sbuf, char **ptalloced)
1610 char *talloced = NULL;
1611 connection_struct *conn = dir_hnd->conn;
1613 /* Cheat to allow . and .. to be the first entries returned. */
1614 if (((*poffset == START_OF_DIRECTORY_OFFSET) ||
1615 (*poffset == DOT_DOT_DIRECTORY_OFFSET)) && (dir_hnd->file_number < 2))
1617 if (dir_hnd->file_number == 0) {
1619 *poffset = dir_hnd->offset = START_OF_DIRECTORY_OFFSET;
1622 *poffset = dir_hnd->offset = DOT_DOT_DIRECTORY_OFFSET;
1624 dir_hnd->file_number++;
1629 if (*poffset == END_OF_DIRECTORY_OFFSET) {
1630 *poffset = dir_hnd->offset = END_OF_DIRECTORY_OFFSET;
1634 /* A real offset, seek to it. */
1635 SeekDir(dir_hnd, *poffset);
1637 while ((n = vfs_readdirname(conn, dir_hnd->dir, sbuf, &talloced))) {
1638 /* Ignore . and .. - we've already returned them. */
1640 if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) {
1641 TALLOC_FREE(talloced);
1645 *poffset = dir_hnd->offset = SMB_VFS_TELLDIR(conn, dir_hnd->dir);
1646 *ptalloced = talloced;
1647 dir_hnd->file_number++;
1650 *poffset = dir_hnd->offset = END_OF_DIRECTORY_OFFSET;
1655 /*******************************************************************
1656 Rewind to the start.
1657 ********************************************************************/
1659 void RewindDir(struct smb_Dir *dir_hnd, long *poffset)
1661 SMB_VFS_REWINDDIR(dir_hnd->conn, dir_hnd->dir);
1662 dir_hnd->file_number = 0;
1663 dir_hnd->offset = START_OF_DIRECTORY_OFFSET;
1664 *poffset = START_OF_DIRECTORY_OFFSET;
1667 /*******************************************************************
1669 ********************************************************************/
1671 void SeekDir(struct smb_Dir *dirp, long offset)
1673 if (offset != dirp->offset) {
1674 if (offset == START_OF_DIRECTORY_OFFSET) {
1675 RewindDir(dirp, &offset);
1677 * Ok we should really set the file number here
1678 * to 1 to enable ".." to be returned next. Trouble
1679 * is I'm worried about callers using SeekDir(dirp,0)
1680 * as equivalent to RewindDir(). So leave this alone
1683 } else if (offset == DOT_DOT_DIRECTORY_OFFSET) {
1684 RewindDir(dirp, &offset);
1686 * Set the file number to 2 - we want to get the first
1687 * real file entry (the one we return after "..")
1688 * on the next ReadDir.
1690 dirp->file_number = 2;
1691 } else if (offset == END_OF_DIRECTORY_OFFSET) {
1692 ; /* Don't seek in this case. */
1694 SMB_VFS_SEEKDIR(dirp->conn, dirp->dir, offset);
1696 dirp->offset = offset;
1700 /*******************************************************************
1701 Tell a dir position.
1702 ********************************************************************/
1704 long TellDir(struct smb_Dir *dir_hnd)
1706 return(dir_hnd->offset);
1709 /*******************************************************************
1710 Add an entry into the dcache.
1711 ********************************************************************/
1713 static void DirCacheAdd(struct smb_Dir *dir_hnd, const char *name, long offset)
1715 struct name_cache_entry *e;
1717 if (dir_hnd->name_cache_size == 0) {
1721 if (dir_hnd->name_cache == NULL) {
1722 dir_hnd->name_cache = talloc_zero_array(dir_hnd,
1723 struct name_cache_entry,
1724 dir_hnd->name_cache_size);
1726 if (dir_hnd->name_cache == NULL) {
1731 dir_hnd->name_cache_index = (dir_hnd->name_cache_index+1) %
1732 dir_hnd->name_cache_size;
1733 e = &dir_hnd->name_cache[dir_hnd->name_cache_index];
1734 TALLOC_FREE(e->name);
1735 e->name = talloc_strdup(dir_hnd, name);
1739 /*******************************************************************
1740 Find an entry by name. Leave us at the offset after it.
1741 Don't check for veto or invisible files.
1742 ********************************************************************/
1744 bool SearchDir(struct smb_Dir *dir_hnd, const char *name, long *poffset)
1747 const char *entry = NULL;
1748 char *talloced = NULL;
1749 connection_struct *conn = dir_hnd->conn;
1751 /* Search back in the name cache. */
1752 if (dir_hnd->name_cache_size && dir_hnd->name_cache) {
1753 for (i = dir_hnd->name_cache_index; i >= 0; i--) {
1754 struct name_cache_entry *e = &dir_hnd->name_cache[i];
1755 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1756 *poffset = e->offset;
1757 SeekDir(dir_hnd, e->offset);
1761 for (i = dir_hnd->name_cache_size - 1;
1762 i > dir_hnd->name_cache_index; i--) {
1763 struct name_cache_entry *e = &dir_hnd->name_cache[i];
1764 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1765 *poffset = e->offset;
1766 SeekDir(dir_hnd, e->offset);
1772 /* Not found in the name cache. Rewind directory and start from scratch. */
1773 SMB_VFS_REWINDDIR(conn, dir_hnd->dir);
1774 dir_hnd->file_number = 0;
1775 *poffset = START_OF_DIRECTORY_OFFSET;
1776 while ((entry = ReadDirName(dir_hnd, poffset, NULL, &talloced))) {
1777 if (conn->case_sensitive ? (strcmp(entry, name) == 0) : strequal(entry, name)) {
1778 TALLOC_FREE(talloced);
1781 TALLOC_FREE(talloced);
1786 struct files_below_forall_state {
1789 int (*fn)(struct file_id fid, const struct share_mode_data *data,
1790 void *private_data);
1794 static int files_below_forall_fn(struct file_id fid,
1795 const struct share_mode_data *data,
1798 struct files_below_forall_state *state = private_data;
1799 char tmpbuf[PATH_MAX];
1800 char *fullpath, *to_free;
1803 len = full_path_tos(data->servicepath, data->base_name,
1804 tmpbuf, sizeof(tmpbuf),
1805 &fullpath, &to_free);
1809 if (state->dirpath_len >= len) {
1811 * Filter files above dirpath
1815 if (fullpath[state->dirpath_len] != '/') {
1817 * Filter file that don't have a path separator at the end of
1823 if (memcmp(state->dirpath, fullpath, state->dirpath_len) != 0) {
1830 TALLOC_FREE(to_free);
1831 return state->fn(fid, data, state->private_data);
1834 TALLOC_FREE(to_free);
1838 static int files_below_forall(connection_struct *conn,
1839 const struct smb_filename *dir_name,
1840 int (*fn)(struct file_id fid,
1841 const struct share_mode_data *data,
1842 void *private_data),
1845 struct files_below_forall_state state = {
1847 .private_data = private_data,
1850 char tmpbuf[PATH_MAX];
1853 state.dirpath_len = full_path_tos(conn->connectpath,
1854 dir_name->base_name,
1855 tmpbuf, sizeof(tmpbuf),
1856 &state.dirpath, &to_free);
1857 if (state.dirpath_len == -1) {
1861 ret = share_mode_forall(files_below_forall_fn, &state);
1862 TALLOC_FREE(to_free);
1866 struct have_file_open_below_state {
1870 static int have_file_open_below_fn(struct file_id fid,
1871 const struct share_mode_data *data,
1874 struct have_file_open_below_state *state = private_data;
1875 state->found_one = true;
1879 bool have_file_open_below(connection_struct *conn,
1880 const struct smb_filename *name)
1882 struct have_file_open_below_state state = {
1887 if (!VALID_STAT(name->st)) {
1890 if (!S_ISDIR(name->st.st_ex_mode)) {
1894 ret = files_below_forall(conn, name, have_file_open_below_fn, &state);
1899 return state.found_one;
1902 /*****************************************************************
1903 Is this directory empty ?
1904 *****************************************************************/
1906 NTSTATUS can_delete_directory_fsp(files_struct *fsp)
1908 NTSTATUS status = NT_STATUS_OK;
1910 const char *dname = NULL;
1911 const char *dirname = fsp->fsp_name->base_name;
1912 char *talloced = NULL;
1914 struct connection_struct *conn = fsp->conn;
1915 struct smb_Dir *dir_hnd = OpenDir(talloc_tos(),
1922 return map_nt_error_from_unix(errno);
1925 while ((dname = ReadDirName(dir_hnd, &dirpos, &st, &talloced))) {
1926 /* Quick check for "." and ".." */
1927 if (dname[0] == '.') {
1928 if (!dname[1] || (dname[1] == '.' && !dname[2])) {
1929 TALLOC_FREE(talloced);
1934 if (!is_visible_file(conn, dirname, dname, &st, True)) {
1935 TALLOC_FREE(talloced);
1939 DEBUG(10,("got name %s - can't delete\n",
1941 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
1944 TALLOC_FREE(talloced);
1945 TALLOC_FREE(dir_hnd);
1947 if (!NT_STATUS_IS_OK(status)) {
1951 if (!(fsp->posix_flags & FSP_POSIX_FLAGS_RENAME) &&
1952 lp_strict_rename(SNUM(conn)) &&
1953 have_file_open_below(fsp->conn, fsp->fsp_name))
1955 return NT_STATUS_ACCESS_DENIED;
1958 return NT_STATUS_OK;