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(). */
65 struct dptr_struct *next, *prev;
68 struct connection_struct *conn;
69 struct smb_Dir *dir_hnd;
73 struct smb_filename *smb_dname;
74 bool has_wild; /* Set to true if the wcard entry has MS wildcard characters in it. */
75 bool did_stat; /* Optimisation for non-wcard searches. */
76 bool priv; /* Directory handle opened with privilege. */
78 struct memcache *dptr_cache;
81 static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn,
86 static void DirCacheAdd(struct smb_Dir *dirp, const char *name, long offset);
88 #define INVALID_DPTR_KEY (-3)
90 /****************************************************************************
91 Initialise the dir bitmap.
92 ****************************************************************************/
94 bool init_dptrs(struct smbd_server_connection *sconn)
96 if (sconn->searches.dptr_bmap) {
100 sconn->searches.dptr_bmap = bitmap_talloc(
101 sconn, MAX_DIRECTORY_HANDLES);
103 if (sconn->searches.dptr_bmap == NULL) {
110 /****************************************************************************
111 Idle a dptr - the directory is closed but the control info is kept.
112 ****************************************************************************/
114 static void dptr_idle(struct dptr_struct *dptr)
117 DEBUG(4,("Idling dptr dnum %d\n",dptr->dnum));
118 TALLOC_FREE(dptr->dir_hnd);
119 TALLOC_FREE(dptr->dptr_cache);
124 /****************************************************************************
125 Idle the oldest dptr.
126 ****************************************************************************/
128 static void dptr_idleoldest(struct smbd_server_connection *sconn)
130 struct dptr_struct *dptr;
133 * Go to the end of the list.
135 dptr = DLIST_TAIL(sconn->searches.dirptrs);
138 DEBUG(0,("No dptrs available to idle ?\n"));
143 * Idle the oldest pointer.
146 for(; dptr; dptr = DLIST_PREV(dptr)) {
154 /****************************************************************************
155 Get the struct dptr_struct for a dir index.
156 ****************************************************************************/
158 static struct dptr_struct *dptr_get(struct smbd_server_connection *sconn,
159 int key, bool forclose)
161 struct dptr_struct *dptr;
163 for(dptr = sconn->searches.dirptrs; dptr; dptr = dptr->next) {
164 if(dptr->dnum == key) {
165 if (!forclose && !dptr->dir_hnd) {
166 if (sconn->searches.dirhandles_open >= MAX_OPEN_DIRECTORIES)
167 dptr_idleoldest(sconn);
168 DEBUG(4,("dptr_get: Reopening dptr key %d\n",key));
170 if (!(dptr->dir_hnd = OpenDir(NULL,
175 DEBUG(4,("dptr_get: Failed to "
177 dptr->smb_dname->base_name,
182 DLIST_PROMOTE(sconn->searches.dirptrs,dptr);
189 /****************************************************************************
190 Get the dir path for a dir index.
191 ****************************************************************************/
193 const char *dptr_path(struct smbd_server_connection *sconn, int key)
195 struct dptr_struct *dptr = dptr_get(sconn, key, false);
197 return(dptr->smb_dname->base_name);
201 /****************************************************************************
202 Get the dir wcard for a dir index.
203 ****************************************************************************/
205 const char *dptr_wcard(struct smbd_server_connection *sconn, int key)
207 struct dptr_struct *dptr = dptr_get(sconn, key, false);
213 /****************************************************************************
214 Get the dir attrib for a dir index.
215 ****************************************************************************/
217 uint16_t dptr_attr(struct smbd_server_connection *sconn, int key)
219 struct dptr_struct *dptr = dptr_get(sconn, key, false);
225 /****************************************************************************
226 Close a dptr (internal func).
227 ****************************************************************************/
229 static void dptr_close_internal(struct dptr_struct *dptr)
231 struct smbd_server_connection *sconn = dptr->conn->sconn;
233 DEBUG(4,("closing dptr key %d\n",dptr->dnum));
239 if (sconn->using_smb2) {
243 DLIST_REMOVE(sconn->searches.dirptrs, dptr);
246 * Free the dnum in the bitmap. Remember the dnum value is always
247 * biased by one with respect to the bitmap.
250 if (!bitmap_query(sconn->searches.dptr_bmap, dptr->dnum - 1)) {
251 DEBUG(0,("dptr_close_internal : Error - closing dnum = %d and bitmap not set !\n",
255 bitmap_clear(sconn->searches.dptr_bmap, dptr->dnum - 1);
258 TALLOC_FREE(dptr->dir_hnd);
262 /****************************************************************************
263 Close a dptr given a key.
264 ****************************************************************************/
266 void dptr_close(struct smbd_server_connection *sconn, int *key)
268 struct dptr_struct *dptr;
270 if(*key == INVALID_DPTR_KEY)
273 /* OS/2 seems to use -1 to indicate "close all directories" */
275 struct dptr_struct *next;
276 for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
278 dptr_close_internal(dptr);
280 *key = INVALID_DPTR_KEY;
284 dptr = dptr_get(sconn, *key, true);
287 DEBUG(0,("Invalid key %d given to dptr_close\n", *key));
291 dptr_close_internal(dptr);
293 *key = INVALID_DPTR_KEY;
296 /****************************************************************************
297 Close all dptrs for a cnum.
298 ****************************************************************************/
300 void dptr_closecnum(connection_struct *conn)
302 struct dptr_struct *dptr, *next;
303 struct smbd_server_connection *sconn = conn->sconn;
309 for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
311 if (dptr->conn == conn) {
312 dptr_close_internal(dptr);
317 /****************************************************************************
318 Idle all dptrs for a cnum.
319 ****************************************************************************/
321 void dptr_idlecnum(connection_struct *conn)
323 struct dptr_struct *dptr;
324 struct smbd_server_connection *sconn = conn->sconn;
330 for(dptr = sconn->searches.dirptrs; dptr; dptr = dptr->next) {
331 if (dptr->conn == conn && dptr->dir_hnd) {
337 /****************************************************************************
338 Close a dptr that matches a given path, only if it matches the spid also.
339 ****************************************************************************/
341 void dptr_closepath(struct smbd_server_connection *sconn,
342 char *path,uint16_t spid)
344 struct dptr_struct *dptr, *next;
345 for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
347 if (spid == dptr->spid &&
348 strequal(dptr->smb_dname->base_name,path)) {
349 dptr_close_internal(dptr);
354 /****************************************************************************
355 Try and close the oldest handle not marked for
356 expect close in the hope that the client has
357 finished with that one.
358 ****************************************************************************/
360 static void dptr_close_oldest(struct smbd_server_connection *sconn,
363 struct dptr_struct *dptr;
366 * Go to the end of the list.
368 for(dptr = sconn->searches.dirptrs; dptr && dptr->next; dptr = dptr->next)
372 DEBUG(0,("No old dptrs available to close oldest ?\n"));
377 * If 'old' is true, close the oldest oldhandle dnum (ie. 1 < dnum < 256) that
378 * does not have expect_close set. If 'old' is false, close
379 * one of the new dnum handles.
382 for(; dptr; dptr = DLIST_PREV(dptr)) {
383 if ((old && (dptr->dnum < 256) && !dptr->expect_close) ||
384 (!old && (dptr->dnum > 255))) {
385 dptr_close_internal(dptr);
391 /****************************************************************************
392 Safely do an OpenDir as root, ensuring we're in the right place.
393 ****************************************************************************/
395 static struct smb_Dir *open_dir_with_privilege(connection_struct *conn,
396 struct smb_request *req,
397 const struct smb_filename *smb_dname,
401 struct smb_Dir *dir_hnd = NULL;
402 struct smb_filename *smb_fname_cwd = NULL;
403 struct smb_filename *saved_dir_fname = vfs_GetWd(talloc_tos(), conn);
404 struct privilege_paths *priv_paths = req->priv_paths;
407 if (saved_dir_fname == NULL) {
411 if (vfs_ChDir(conn, smb_dname) == -1) {
415 /* Now check the stat value is the same. */
416 smb_fname_cwd = synthetic_smb_fname(talloc_tos(),
421 if (smb_fname_cwd == NULL) {
424 ret = SMB_VFS_STAT(conn, smb_fname_cwd);
429 if (!check_same_stat(&smb_fname_cwd->st, &priv_paths->parent_name.st)) {
430 DEBUG(0,("open_dir_with_privilege: stat mismatch between %s "
432 smb_dname->base_name,
433 smb_fname_str_dbg(&priv_paths->parent_name)));
437 dir_hnd = OpenDir(NULL, conn, smb_fname_cwd, wcard, attr);
441 vfs_ChDir(conn, saved_dir_fname);
442 TALLOC_FREE(saved_dir_fname);
446 /****************************************************************************
447 Create a new dir ptr. If the flag old_handle is true then we must allocate
448 from the bitmap range 0 - 255 as old SMBsearch directory handles are only
449 one byte long. If old_handle is false we allocate from the range
450 256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
451 a directory handle is never zero.
452 wcard must not be zero.
453 ****************************************************************************/
455 NTSTATUS dptr_create(connection_struct *conn,
456 struct smb_request *req,
458 const struct smb_filename *smb_dname,
465 struct dptr_struct **dptr_ret)
467 struct smbd_server_connection *sconn = conn->sconn;
468 struct dptr_struct *dptr = NULL;
469 struct smb_Dir *dir_hnd;
471 if (fsp && fsp->is_directory && fsp->fh->fd != -1) {
472 smb_dname = fsp->fsp_name;
475 DEBUG(5,("dptr_create dir=%s\n", smb_dname->base_name));
478 DEBUG(0,("dptr_create: called with fake connection_struct\n"));
479 return NT_STATUS_INTERNAL_ERROR;
483 return NT_STATUS_INVALID_PARAMETER;
487 if (!(fsp->access_mask & SEC_DIR_LIST)) {
488 DEBUG(5,("dptr_create: directory %s "
489 "not open for LIST access\n",
490 smb_dname->base_name));
491 return NT_STATUS_ACCESS_DENIED;
493 dir_hnd = OpenDir_fsp(NULL, conn, fsp, wcard, attr);
496 bool backup_intent = (req && req->priv_paths);
498 struct smb_filename *smb_dname_cp =
499 cp_smb_filename(talloc_tos(), smb_dname);
501 if (smb_dname_cp == NULL) {
502 return NT_STATUS_NO_MEMORY;
505 if (req != NULL && req->posix_pathnames) {
506 ret = SMB_VFS_LSTAT(conn, smb_dname_cp);
508 ret = SMB_VFS_STAT(conn, smb_dname_cp);
511 status = map_nt_error_from_unix(errno);
512 TALLOC_FREE(smb_dname_cp);
515 if (!S_ISDIR(smb_dname_cp->st.st_ex_mode)) {
516 TALLOC_FREE(smb_dname_cp);
517 return NT_STATUS_NOT_A_DIRECTORY;
519 status = smbd_check_access_rights(conn,
523 if (!NT_STATUS_IS_OK(status)) {
524 TALLOC_FREE(smb_dname_cp);
528 dir_hnd = open_dir_with_privilege(conn,
534 dir_hnd = OpenDir(NULL,
540 TALLOC_FREE(smb_dname_cp);
544 return map_nt_error_from_unix(errno);
547 if (sconn->searches.dirhandles_open >= MAX_OPEN_DIRECTORIES) {
548 dptr_idleoldest(sconn);
551 dptr = talloc_zero(NULL, struct dptr_struct);
553 DEBUG(0,("talloc fail in dptr_create.\n"));
554 TALLOC_FREE(dir_hnd);
555 return NT_STATUS_NO_MEMORY;
558 dptr->smb_dname = cp_smb_filename(dptr, smb_dname);
559 if (!dptr->smb_dname) {
561 TALLOC_FREE(dir_hnd);
562 return NT_STATUS_NO_MEMORY;
565 dptr->dir_hnd = dir_hnd;
567 dptr->expect_close = expect_close;
568 dptr->wcard = talloc_strdup(dptr, wcard);
571 TALLOC_FREE(dir_hnd);
572 return NT_STATUS_NO_MEMORY;
574 if ((req != NULL && req->posix_pathnames) ||
575 (wcard[0] == '.' && wcard[1] == 0)) {
576 dptr->has_wild = True;
578 dptr->has_wild = wcard_has_wild;
583 if (sconn->using_smb2) {
590 * This is an old-style SMBsearch request. Ensure the
591 * value we return will fit in the range 1-255.
594 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 0);
596 if(dptr->dnum == -1 || dptr->dnum > 254) {
599 * Try and close the oldest handle not marked for
600 * expect close in the hope that the client has
601 * finished with that one.
604 dptr_close_oldest(sconn, true);
606 /* Now try again... */
607 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 0);
608 if(dptr->dnum == -1 || dptr->dnum > 254) {
609 DEBUG(0,("dptr_create: returned %d: Error - all old dirptrs in use ?\n", dptr->dnum));
611 TALLOC_FREE(dir_hnd);
612 return NT_STATUS_TOO_MANY_OPENED_FILES;
618 * This is a new-style trans2 request. Allocate from
619 * a range that will return 256 - MAX_DIRECTORY_HANDLES.
622 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 255);
624 if(dptr->dnum == -1 || dptr->dnum < 255) {
627 * Try and close the oldest handle close in the hope that
628 * the client has finished with that one. This will only
629 * happen in the case of the Win98 client bug where it leaks
633 dptr_close_oldest(sconn, false);
635 /* Now try again... */
636 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 255);
638 if(dptr->dnum == -1 || dptr->dnum < 255) {
639 DEBUG(0,("dptr_create: returned %d: Error - all new dirptrs in use ?\n", dptr->dnum));
641 TALLOC_FREE(dir_hnd);
642 return NT_STATUS_TOO_MANY_OPENED_FILES;
647 bitmap_set(sconn->searches.dptr_bmap, dptr->dnum);
649 dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
651 DLIST_ADD(sconn->searches.dirptrs, dptr);
654 DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
656 dptr->smb_dname->base_name,
665 /****************************************************************************
666 Wrapper functions to access the lower level directory handles.
667 ****************************************************************************/
669 void dptr_CloseDir(files_struct *fsp)
673 * The destructor for the struct smb_Dir
674 * (fsp->dptr->dir_hnd) now handles
675 * all resource deallocation.
677 dptr_close_internal(fsp->dptr);
682 void dptr_SeekDir(struct dptr_struct *dptr, long offset)
684 SeekDir(dptr->dir_hnd, offset);
687 long dptr_TellDir(struct dptr_struct *dptr)
689 return TellDir(dptr->dir_hnd);
692 bool dptr_has_wild(struct dptr_struct *dptr)
694 return dptr->has_wild;
697 int dptr_dnum(struct dptr_struct *dptr)
702 bool dptr_get_priv(struct dptr_struct *dptr)
707 void dptr_set_priv(struct dptr_struct *dptr)
712 /****************************************************************************
713 Return the next visible file name, skipping veto'd and invisible files.
714 ****************************************************************************/
716 static const char *dptr_normal_ReadDirName(struct dptr_struct *dptr,
717 long *poffset, SMB_STRUCT_STAT *pst,
720 /* Normal search for the next file. */
722 char *talloced = NULL;
724 while ((name = ReadDirName(dptr->dir_hnd, poffset, pst, &talloced))
726 if (is_visible_file(dptr->conn,
727 dptr->smb_dname->base_name,
731 *ptalloced = talloced;
734 TALLOC_FREE(talloced);
739 /****************************************************************************
740 Return the next visible file name, skipping veto'd and invisible files.
741 ****************************************************************************/
743 static char *dptr_ReadDirName(TALLOC_CTX *ctx,
744 struct dptr_struct *dptr,
746 SMB_STRUCT_STAT *pst)
748 struct smb_filename smb_fname_base;
750 const char *name_temp = NULL;
751 char *talloced = NULL;
752 char *pathreal = NULL;
753 char *found_name = NULL;
756 SET_STAT_INVALID(*pst);
758 if (dptr->has_wild || dptr->did_stat) {
759 name_temp = dptr_normal_ReadDirName(dptr, poffset, pst,
761 if (name_temp == NULL) {
764 if (talloced != NULL) {
765 return talloc_move(ctx, &talloced);
767 return talloc_strdup(ctx, name_temp);
770 /* If poffset is -1 then we know we returned this name before and we
771 * have no wildcards. We're at the end of the directory. */
772 if (*poffset == END_OF_DIRECTORY_OFFSET) {
776 /* We know the stored wcard contains no wildcard characters.
777 * See if we can match with a stat call. If we can't, then set
778 * did_stat to true to ensure we only do this once and keep
781 dptr->did_stat = true;
783 /* First check if it should be visible. */
784 if (!is_visible_file(dptr->conn,
785 dptr->smb_dname->base_name,
789 /* This only returns false if the file was found, but
790 is explicitly not visible. Set us to end of
791 directory, but return NULL as we know we can't ever
796 if (VALID_STAT(*pst)) {
797 name = talloc_strdup(ctx, dptr->wcard);
801 pathreal = talloc_asprintf(ctx,
803 dptr->smb_dname->base_name,
808 /* Create an smb_filename with stream_name == NULL. */
809 smb_fname_base = (struct smb_filename) { .base_name = pathreal };
811 if (SMB_VFS_STAT(dptr->conn, &smb_fname_base) == 0) {
812 *pst = smb_fname_base.st;
813 name = talloc_strdup(ctx, dptr->wcard);
816 /* If we get any other error than ENOENT or ENOTDIR
817 then the file exists we just can't stat it. */
818 if (errno != ENOENT && errno != ENOTDIR) {
819 name = talloc_strdup(ctx, dptr->wcard);
824 /* Stat failed. We know this is authoratiative if we are
825 * providing case sensitive semantics or the underlying
826 * filesystem is case sensitive.
828 if (dptr->conn->case_sensitive ||
829 !(dptr->conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH))
835 * Try case-insensitive stat if the fs has the ability. This avoids
836 * scanning the whole directory.
838 ret = SMB_VFS_GET_REAL_FILENAME(dptr->conn,
839 dptr->smb_dname->base_name,
846 } else if (errno == ENOENT) {
847 /* The case-insensitive lookup was authoritative. */
851 TALLOC_FREE(pathreal);
853 name_temp = dptr_normal_ReadDirName(dptr, poffset, pst, &talloced);
854 if (name_temp == NULL) {
857 if (talloced != NULL) {
858 return talloc_move(ctx, &talloced);
860 return talloc_strdup(ctx, name_temp);
863 TALLOC_FREE(pathreal);
865 /* We need to set the underlying dir_hnd offset to -1
866 * also as this function is usually called with the
867 * output from TellDir. */
868 dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
872 /****************************************************************************
873 Search for a file by name, skipping veto'ed and not visible files.
874 ****************************************************************************/
876 bool dptr_SearchDir(struct dptr_struct *dptr, const char *name, long *poffset, SMB_STRUCT_STAT *pst)
878 SET_STAT_INVALID(*pst);
880 if (!dptr->has_wild && (dptr->dir_hnd->offset == END_OF_DIRECTORY_OFFSET)) {
881 /* This is a singleton directory and we're already at the end. */
882 *poffset = END_OF_DIRECTORY_OFFSET;
886 return SearchDir(dptr->dir_hnd, name, poffset);
889 /****************************************************************************
890 Initialize variables & state data at the beginning of all search SMB requests.
891 ****************************************************************************/
892 void dptr_init_search_op(struct dptr_struct *dptr)
894 SMB_VFS_INIT_SEARCH_OP(dptr->conn, dptr->dir_hnd->dir);
897 /****************************************************************************
898 Map a native directory offset to a 32-bit cookie.
899 ****************************************************************************/
901 static uint32_t map_dir_offset_to_wire(struct dptr_struct *dptr, long offset)
906 if (offset == END_OF_DIRECTORY_OFFSET) {
907 return WIRE_END_OF_DIRECTORY_OFFSET;
908 } else if(offset == START_OF_DIRECTORY_OFFSET) {
909 return WIRE_START_OF_DIRECTORY_OFFSET;
910 } else if (offset == DOT_DOT_DIRECTORY_OFFSET) {
911 return WIRE_DOT_DOT_DIRECTORY_OFFSET;
913 if (sizeof(long) == 4) {
914 /* 32-bit machine. We can cheat... */
915 return (uint32_t)offset;
917 if (dptr->dptr_cache == NULL) {
918 /* Lazy initialize cache. */
919 dptr->dptr_cache = memcache_init(dptr, 0);
920 if (dptr->dptr_cache == NULL) {
921 return WIRE_END_OF_DIRECTORY_OFFSET;
924 /* Have we seen this offset before ? */
925 key.data = (void *)&offset;
926 key.length = sizeof(offset);
927 if (memcache_lookup(dptr->dptr_cache,
928 SMB1_SEARCH_OFFSET_MAP,
931 uint32_t wire_offset;
932 SMB_ASSERT(val.length == sizeof(wire_offset));
933 memcpy(&wire_offset, val.data, sizeof(wire_offset));
934 DEBUG(10,("found wire %u <-> offset %ld\n",
935 (unsigned int)wire_offset,
940 /* Allocate a new wire cookie. */
943 } while (dptr->counter == WIRE_START_OF_DIRECTORY_OFFSET ||
944 dptr->counter == WIRE_END_OF_DIRECTORY_OFFSET ||
945 dptr->counter == WIRE_DOT_DOT_DIRECTORY_OFFSET);
946 /* Store it in the cache. */
947 key.data = (void *)&offset;
948 key.length = sizeof(offset);
949 val.data = (void *)&dptr->counter;
950 val.length = sizeof(dptr->counter); /* MUST BE uint32_t ! */
951 memcache_add(dptr->dptr_cache,
952 SMB1_SEARCH_OFFSET_MAP,
955 /* And the reverse mapping for lookup from
956 map_wire_to_dir_offset(). */
957 memcache_add(dptr->dptr_cache,
958 SMB1_SEARCH_OFFSET_MAP,
961 DEBUG(10,("stored wire %u <-> offset %ld\n",
962 (unsigned int)dptr->counter,
964 return dptr->counter;
967 /****************************************************************************
968 Fill the 5 byte server reserved dptr field.
969 ****************************************************************************/
971 bool dptr_fill(struct smbd_server_connection *sconn,
972 char *buf1,unsigned int key)
974 unsigned char *buf = (unsigned char *)buf1;
975 struct dptr_struct *dptr = dptr_get(sconn, key, false);
976 uint32_t wire_offset;
978 DEBUG(1,("filling null dirptr %d\n",key));
981 wire_offset = map_dir_offset_to_wire(dptr,TellDir(dptr->dir_hnd));
982 DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key,
983 (long)dptr->dir_hnd,(int)wire_offset));
985 SIVAL(buf,1,wire_offset);
989 /****************************************************************************
990 Map a 32-bit wire cookie to a native directory offset.
991 ****************************************************************************/
993 static long map_wire_to_dir_offset(struct dptr_struct *dptr, uint32_t wire_offset)
998 if (wire_offset == WIRE_END_OF_DIRECTORY_OFFSET) {
999 return END_OF_DIRECTORY_OFFSET;
1000 } else if(wire_offset == WIRE_START_OF_DIRECTORY_OFFSET) {
1001 return START_OF_DIRECTORY_OFFSET;
1002 } else if (wire_offset == WIRE_DOT_DOT_DIRECTORY_OFFSET) {
1003 return DOT_DOT_DIRECTORY_OFFSET;
1005 if (sizeof(long) == 4) {
1006 /* 32-bit machine. We can cheat... */
1007 return (long)wire_offset;
1009 if (dptr->dptr_cache == NULL) {
1010 /* Logic error, cache should be initialized. */
1011 return END_OF_DIRECTORY_OFFSET;
1013 key.data = (void *)&wire_offset;
1014 key.length = sizeof(wire_offset);
1015 if (memcache_lookup(dptr->dptr_cache,
1016 SMB1_SEARCH_OFFSET_MAP,
1019 /* Found mapping. */
1021 SMB_ASSERT(val.length == sizeof(offset));
1022 memcpy(&offset, val.data, sizeof(offset));
1023 DEBUG(10,("lookup wire %u <-> offset %ld\n",
1024 (unsigned int)wire_offset,
1028 return END_OF_DIRECTORY_OFFSET;
1031 /****************************************************************************
1032 Fetch the dir ptr and seek it given the 5 byte server field.
1033 ****************************************************************************/
1035 struct dptr_struct *dptr_fetch(struct smbd_server_connection *sconn,
1036 char *buf, int *num)
1038 unsigned int key = *(unsigned char *)buf;
1039 struct dptr_struct *dptr = dptr_get(sconn, key, false);
1040 uint32_t wire_offset;
1044 DEBUG(3,("fetched null dirptr %d\n",key));
1048 wire_offset = IVAL(buf,1);
1049 seekoff = map_wire_to_dir_offset(dptr, wire_offset);
1050 SeekDir(dptr->dir_hnd,seekoff);
1051 DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
1052 key, dptr->smb_dname->base_name, (int)seekoff));
1056 /****************************************************************************
1058 ****************************************************************************/
1060 struct dptr_struct *dptr_fetch_lanman2(struct smbd_server_connection *sconn,
1063 struct dptr_struct *dptr = dptr_get(sconn, dptr_num, false);
1066 DEBUG(3,("fetched null dirptr %d\n",dptr_num));
1069 DEBUG(3,("fetching dirptr %d for path %s\n",
1071 dptr->smb_dname->base_name));
1075 static bool mangle_mask_match(connection_struct *conn,
1076 const char *filename,
1081 if (!name_to_8_3(filename,mname,False,conn->params)) {
1084 return mask_match_search(mname,mask,False);
1087 bool smbd_dirptr_get_entry(TALLOC_CTX *ctx,
1088 struct dptr_struct *dirptr,
1093 bool (*match_fn)(TALLOC_CTX *ctx,
1098 bool (*mode_fn)(TALLOC_CTX *ctx,
1100 struct smb_filename *smb_fname,
1104 struct smb_filename **_smb_fname,
1108 connection_struct *conn = dirptr->conn;
1111 const char *dpath = dirptr->smb_dname->base_name;
1112 bool dirptr_path_is_dot = ISDOT(dpath);
1117 pathlen = strlen(dpath);
1118 slashlen = ( dpath[pathlen-1] != '/') ? 1 : 0;
1123 SMB_STRUCT_STAT sbuf = { 0 };
1127 char *pathreal = NULL;
1128 struct smb_filename smb_fname;
1132 cur_offset = dptr_TellDir(dirptr);
1133 prev_offset = cur_offset;
1134 dname = dptr_ReadDirName(ctx, dirptr, &cur_offset, &sbuf);
1136 DEBUG(6,("smbd_dirptr_get_entry: dirptr 0x%lx now at offset %ld\n",
1137 (long)dirptr, cur_offset));
1139 if (dname == NULL) {
1143 isdots = (ISDOT(dname) || ISDOTDOT(dname));
1144 if (dont_descend && !isdots) {
1150 * fname may get mangled, dname is never mangled.
1151 * Whenever we're accessing the filesystem we use
1152 * pathreal which is composed from dname.
1155 ok = match_fn(ctx, private_data, dname, mask, &fname);
1163 * pathreal = talloc_asprintf(ctx, "%s%s%s", dirptr->path,
1164 * needslash?"/":"", dname);
1165 * but this was measurably slower than doing the memcpy.
1168 pathreal = talloc_array(
1170 pathlen + slashlen + talloc_get_size(dname));
1178 * We don't want to pass ./xxx to modules below us so don't
1179 * add the path if it is just . by itself.
1181 if (dirptr_path_is_dot) {
1182 memcpy(pathreal, dname, talloc_get_size(dname));
1184 memcpy(pathreal, dpath, pathlen);
1185 pathreal[pathlen] = '/';
1186 memcpy(pathreal + slashlen + pathlen, dname,
1187 talloc_get_size(dname));
1190 /* Create smb_fname with NULL stream_name. */
1191 smb_fname = (struct smb_filename) {
1192 .base_name = pathreal, .st = sbuf
1195 ok = mode_fn(ctx, private_data, &smb_fname, &mode);
1199 TALLOC_FREE(pathreal);
1203 if (!dir_check_ftype(mode, dirtype)) {
1204 DEBUG(5,("[%s] attribs 0x%x didn't match 0x%x\n",
1205 fname, (unsigned int)mode, (unsigned int)dirtype));
1208 TALLOC_FREE(pathreal);
1212 if (ask_sharemode) {
1213 struct timespec write_time_ts;
1214 struct file_id fileid;
1216 fileid = vfs_file_id_from_sbuf(conn,
1218 get_file_infos(fileid, 0, NULL, &write_time_ts);
1219 if (!null_timespec(write_time_ts)) {
1220 update_stat_ex_mtime(&smb_fname.st,
1225 DEBUG(3,("smbd_dirptr_get_entry mask=[%s] found %s "
1227 mask, smb_fname_str_dbg(&smb_fname),
1230 DirCacheAdd(dirptr->dir_hnd, dname, cur_offset);
1234 *_smb_fname = cp_smb_filename(ctx, &smb_fname);
1235 TALLOC_FREE(pathreal);
1236 if (*_smb_fname == NULL) {
1241 *_prev_offset = prev_offset;
1249 /****************************************************************************
1250 Get an 8.3 directory entry.
1251 ****************************************************************************/
1253 static bool smbd_dirptr_8_3_match_fn(TALLOC_CTX *ctx,
1259 connection_struct *conn = (connection_struct *)private_data;
1261 if ((strcmp(mask,"*.*") == 0) ||
1262 mask_match_search(dname, mask, false) ||
1263 mangle_mask_match(conn, dname, mask)) {
1267 * Ensure we can push the original name as UCS2. If
1268 * not, then just don't return this name.
1272 size_t len = (strlen(dname) + 2) * 4; /* Allow enough space. */
1273 uint8_t *tmp = talloc_array(talloc_tos(),
1277 status = srvstr_push(NULL,
1278 FLAGS2_UNICODE_STRINGS,
1287 if (!NT_STATUS_IS_OK(status)) {
1291 if (!mangle_is_8_3(dname, false, conn->params)) {
1292 bool ok = name_to_8_3(dname, mname, false,
1302 *_fname = talloc_strdup(ctx, fname);
1303 if (*_fname == NULL) {
1313 static bool smbd_dirptr_8_3_mode_fn(TALLOC_CTX *ctx,
1315 struct smb_filename *smb_fname,
1318 connection_struct *conn = (connection_struct *)private_data;
1320 if (!VALID_STAT(smb_fname->st)) {
1321 if ((SMB_VFS_STAT(conn, smb_fname)) != 0) {
1322 DEBUG(5,("smbd_dirptr_8_3_mode_fn: "
1323 "Couldn't stat [%s]. Error "
1325 smb_fname_str_dbg(smb_fname),
1331 *_mode = dos_mode(conn, smb_fname);
1335 bool get_dir_entry(TALLOC_CTX *ctx,
1336 struct dptr_struct *dirptr,
1342 struct timespec *_date,
1346 connection_struct *conn = dirptr->conn;
1348 struct smb_filename *smb_fname = NULL;
1353 ok = smbd_dirptr_get_entry(ctx,
1359 smbd_dirptr_8_3_match_fn,
1360 smbd_dirptr_8_3_mode_fn,
1370 *_fname = talloc_move(ctx, &fname);
1371 *_size = smb_fname->st.st_ex_size;
1373 *_date = smb_fname->st.st_ex_mtime;
1374 TALLOC_FREE(smb_fname);
1378 /*******************************************************************
1379 Check to see if a user can read a file. This is only approximate,
1380 it is used as part of the "hide unreadable" option. Don't
1381 use it for anything security sensitive.
1382 ********************************************************************/
1384 static bool user_can_read_file(connection_struct *conn,
1385 struct smb_filename *smb_fname)
1388 uint32_t rejected_share_access = 0;
1389 uint32_t rejected_mask = 0;
1390 struct security_descriptor *sd = NULL;
1391 uint32_t access_mask = FILE_READ_DATA|
1393 FILE_READ_ATTRIBUTES|
1394 SEC_STD_READ_CONTROL;
1397 * Never hide files from the root user.
1398 * We use (uid_t)0 here not sec_initial_uid()
1399 * as make test uses a single user context.
1402 if (get_current_uid(conn) == (uid_t)0) {
1407 * We can't directly use smbd_check_access_rights()
1408 * here, as this implicitly grants FILE_READ_ATTRIBUTES
1409 * which the Windows access-based-enumeration code
1410 * explicitly checks for on the file security descriptor.
1413 * https://bugzilla.samba.org/show_bug.cgi?id=10252
1415 * and the smb2.acl2.ACCESSBASED test for details.
1418 rejected_share_access = access_mask & ~(conn->share_access);
1419 if (rejected_share_access) {
1420 DEBUG(10, ("rejected share access 0x%x "
1422 (unsigned int)access_mask,
1423 smb_fname_str_dbg(smb_fname),
1424 (unsigned int)rejected_share_access ));
1428 status = SMB_VFS_GET_NT_ACL(conn,
1436 if (!NT_STATUS_IS_OK(status)) {
1437 DEBUG(10, ("Could not get acl "
1439 smb_fname_str_dbg(smb_fname),
1440 nt_errstr(status)));
1444 status = se_file_access_check(sd,
1445 get_current_nttok(conn),
1452 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1453 DEBUG(10,("rejected bits 0x%x read access for %s\n",
1454 (unsigned int)rejected_mask,
1455 smb_fname_str_dbg(smb_fname) ));
1461 /*******************************************************************
1462 Check to see if a user can write a file (and only files, we do not
1463 check dirs on this one). This is only approximate,
1464 it is used as part of the "hide unwriteable" option. Don't
1465 use it for anything security sensitive.
1466 ********************************************************************/
1468 static bool user_can_write_file(connection_struct *conn,
1469 const struct smb_filename *smb_fname)
1472 * Never hide files from the root user.
1473 * We use (uid_t)0 here not sec_initial_uid()
1474 * as make test uses a single user context.
1477 if (get_current_uid(conn) == (uid_t)0) {
1481 SMB_ASSERT(VALID_STAT(smb_fname->st));
1483 /* Pseudo-open the file */
1485 if(S_ISDIR(smb_fname->st.st_ex_mode)) {
1489 return can_write_to_file(conn, smb_fname);
1492 /*******************************************************************
1493 Is a file a "special" type ?
1494 ********************************************************************/
1496 static bool file_is_special(connection_struct *conn,
1497 const struct smb_filename *smb_fname)
1500 * Never hide files from the root user.
1501 * We use (uid_t)0 here not sec_initial_uid()
1502 * as make test uses a single user context.
1505 if (get_current_uid(conn) == (uid_t)0) {
1509 SMB_ASSERT(VALID_STAT(smb_fname->st));
1511 if (S_ISREG(smb_fname->st.st_ex_mode) ||
1512 S_ISDIR(smb_fname->st.st_ex_mode) ||
1513 S_ISLNK(smb_fname->st.st_ex_mode))
1519 /*******************************************************************
1520 Should the file be seen by the client?
1521 NOTE: A successful return is no guarantee of the file's existence.
1522 ********************************************************************/
1524 bool is_visible_file(connection_struct *conn, const char *dir_path,
1525 const char *name, SMB_STRUCT_STAT *pst, bool use_veto)
1527 bool hide_unreadable = lp_hide_unreadable(SNUM(conn));
1528 bool hide_unwriteable = lp_hide_unwriteable_files(SNUM(conn));
1529 bool hide_special = lp_hide_special_files(SNUM(conn));
1531 struct smb_filename *smb_fname_base = NULL;
1534 if ((strcmp(".",name) == 0) || (strcmp("..",name) == 0)) {
1535 return True; /* . and .. are always visible. */
1538 /* If it's a vetoed file, pretend it doesn't even exist */
1539 if (use_veto && IS_VETO_PATH(conn, name)) {
1540 DEBUG(10,("is_visible_file: file %s is vetoed.\n", name ));
1544 if (hide_unreadable || hide_unwriteable || hide_special) {
1545 entry = talloc_asprintf(talloc_tos(), "%s/%s", dir_path, name);
1551 /* Create an smb_filename with stream_name == NULL. */
1552 smb_fname_base = synthetic_smb_fname(talloc_tos(),
1557 if (smb_fname_base == NULL) {
1562 /* If the file name does not exist, there's no point checking
1563 * the configuration options. We succeed, on the basis that the
1564 * checks *might* have passed if the file was present.
1566 if (!VALID_STAT(*pst)) {
1567 if (SMB_VFS_STAT(conn, smb_fname_base) != 0) {
1571 *pst = smb_fname_base->st;
1574 /* Honour _hide unreadable_ option */
1575 if (hide_unreadable &&
1576 !user_can_read_file(conn, smb_fname_base)) {
1577 DEBUG(10,("is_visible_file: file %s is unreadable.\n",
1582 /* Honour _hide unwriteable_ option */
1583 if (hide_unwriteable && !user_can_write_file(conn,
1585 DEBUG(10,("is_visible_file: file %s is unwritable.\n",
1590 /* Honour _hide_special_ option */
1591 if (hide_special && file_is_special(conn, smb_fname_base)) {
1592 DEBUG(10,("is_visible_file: file %s is special.\n",
1601 TALLOC_FREE(smb_fname_base);
1606 static int smb_Dir_destructor(struct smb_Dir *dirp)
1608 if (dirp->dir != NULL) {
1609 SMB_VFS_CLOSEDIR(dirp->conn,dirp->dir);
1610 if (dirp->fsp != NULL) {
1612 * The SMB_VFS_CLOSEDIR above
1613 * closes the underlying fd inside
1616 dirp->fsp->fh->fd = -1;
1617 if (dirp->fsp->dptr != NULL) {
1618 SMB_ASSERT(dirp->fsp->dptr->dir_hnd == dirp);
1619 dirp->fsp->dptr->dir_hnd = NULL;
1624 if (dirp->conn->sconn && !dirp->conn->sconn->using_smb2) {
1625 dirp->conn->sconn->searches.dirhandles_open--;
1630 /*******************************************************************
1632 ********************************************************************/
1634 static struct smb_Dir *OpenDir_internal(TALLOC_CTX *mem_ctx,
1635 connection_struct *conn,
1636 const struct smb_filename *smb_dname,
1640 struct smb_Dir *dirp = talloc_zero(mem_ctx, struct smb_Dir);
1641 struct smbd_server_connection *sconn = conn->sconn;
1647 dirp->dir = SMB_VFS_OPENDIR(conn, smb_dname, mask, attr);
1650 DEBUG(5,("OpenDir: Can't open %s. %s\n",
1651 smb_dname->base_name,
1657 dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
1659 if (sconn && !sconn->using_smb2) {
1660 sconn->searches.dirhandles_open++;
1662 talloc_set_destructor(dirp, smb_Dir_destructor);
1671 /****************************************************************************
1672 Open a directory handle by pathname, ensuring it's under the share path.
1673 ****************************************************************************/
1675 static struct smb_Dir *open_dir_safely(TALLOC_CTX *ctx,
1676 connection_struct *conn,
1677 const struct smb_filename *smb_dname,
1681 struct smb_Dir *dir_hnd = NULL;
1682 struct smb_filename *smb_fname_cwd = NULL;
1683 struct smb_filename *saved_dir_fname = vfs_GetWd(ctx, conn);
1686 if (saved_dir_fname == NULL) {
1690 if (vfs_ChDir(conn, smb_dname) == -1) {
1694 smb_fname_cwd = synthetic_smb_fname(talloc_tos(),
1699 if (smb_fname_cwd == NULL) {
1704 * Now the directory is pinned, use
1705 * REALPATH to ensure we can access it.
1707 status = check_name(conn, smb_fname_cwd);
1708 if (!NT_STATUS_IS_OK(status)) {
1712 dir_hnd = OpenDir_internal(ctx,
1718 if (dir_hnd == NULL) {
1723 * OpenDir_internal only gets "." as the dir name.
1724 * Store the real dir name here.
1727 dir_hnd->dir_smb_fname = cp_smb_filename(dir_hnd, smb_dname);
1728 if (!dir_hnd->dir_smb_fname) {
1729 TALLOC_FREE(dir_hnd);
1735 vfs_ChDir(conn, saved_dir_fname);
1736 TALLOC_FREE(saved_dir_fname);
1740 struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn,
1741 const struct smb_filename *smb_dname,
1745 return open_dir_safely(mem_ctx,
1752 /*******************************************************************
1753 Open a directory from an fsp.
1754 ********************************************************************/
1756 static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn,
1761 struct smb_Dir *dirp = talloc_zero(mem_ctx, struct smb_Dir);
1762 struct smbd_server_connection *sconn = conn->sconn;
1768 if (!fsp->is_directory) {
1773 if (fsp->fh->fd == -1) {
1779 dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
1781 dirp->dir_smb_fname = cp_smb_filename(dirp, fsp->fsp_name);
1782 if (!dirp->dir_smb_fname) {
1787 dirp->dir = SMB_VFS_FDOPENDIR(fsp, mask, attr);
1788 if (dirp->dir != NULL) {
1791 DEBUG(10,("OpenDir_fsp: SMB_VFS_FDOPENDIR on %s returned "
1793 dirp->dir_smb_fname->base_name,
1795 if (errno != ENOSYS) {
1800 if (dirp->dir == NULL) {
1801 /* FDOPENDIR is not supported. Use OPENDIR instead. */
1803 return open_dir_safely(mem_ctx,
1810 if (sconn && !sconn->using_smb2) {
1811 sconn->searches.dirhandles_open++;
1813 talloc_set_destructor(dirp, smb_Dir_destructor);
1823 /*******************************************************************
1824 Read from a directory.
1825 Return directory entry, current offset, and optional stat information.
1826 Don't check for veto or invisible files.
1827 ********************************************************************/
1829 const char *ReadDirName(struct smb_Dir *dirp, long *poffset,
1830 SMB_STRUCT_STAT *sbuf, char **ptalloced)
1833 char *talloced = NULL;
1834 connection_struct *conn = dirp->conn;
1836 /* Cheat to allow . and .. to be the first entries returned. */
1837 if (((*poffset == START_OF_DIRECTORY_OFFSET) ||
1838 (*poffset == DOT_DOT_DIRECTORY_OFFSET)) && (dirp->file_number < 2))
1840 if (dirp->file_number == 0) {
1842 *poffset = dirp->offset = START_OF_DIRECTORY_OFFSET;
1845 *poffset = dirp->offset = DOT_DOT_DIRECTORY_OFFSET;
1847 dirp->file_number++;
1852 if (*poffset == END_OF_DIRECTORY_OFFSET) {
1853 *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1857 /* A real offset, seek to it. */
1858 SeekDir(dirp, *poffset);
1860 while ((n = vfs_readdirname(conn, dirp->dir, sbuf, &talloced))) {
1861 /* Ignore . and .. - we've already returned them. */
1863 if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) {
1864 TALLOC_FREE(talloced);
1868 *poffset = dirp->offset = SMB_VFS_TELLDIR(conn, dirp->dir);
1869 *ptalloced = talloced;
1870 dirp->file_number++;
1873 *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1878 /*******************************************************************
1879 Rewind to the start.
1880 ********************************************************************/
1882 void RewindDir(struct smb_Dir *dirp, long *poffset)
1884 SMB_VFS_REWINDDIR(dirp->conn, dirp->dir);
1885 dirp->file_number = 0;
1886 dirp->offset = START_OF_DIRECTORY_OFFSET;
1887 *poffset = START_OF_DIRECTORY_OFFSET;
1890 /*******************************************************************
1892 ********************************************************************/
1894 void SeekDir(struct smb_Dir *dirp, long offset)
1896 if (offset != dirp->offset) {
1897 if (offset == START_OF_DIRECTORY_OFFSET) {
1898 RewindDir(dirp, &offset);
1900 * Ok we should really set the file number here
1901 * to 1 to enable ".." to be returned next. Trouble
1902 * is I'm worried about callers using SeekDir(dirp,0)
1903 * as equivalent to RewindDir(). So leave this alone
1906 } else if (offset == DOT_DOT_DIRECTORY_OFFSET) {
1907 RewindDir(dirp, &offset);
1909 * Set the file number to 2 - we want to get the first
1910 * real file entry (the one we return after "..")
1911 * on the next ReadDir.
1913 dirp->file_number = 2;
1914 } else if (offset == END_OF_DIRECTORY_OFFSET) {
1915 ; /* Don't seek in this case. */
1917 SMB_VFS_SEEKDIR(dirp->conn, dirp->dir, offset);
1919 dirp->offset = offset;
1923 /*******************************************************************
1924 Tell a dir position.
1925 ********************************************************************/
1927 long TellDir(struct smb_Dir *dirp)
1929 return(dirp->offset);
1932 /*******************************************************************
1933 Add an entry into the dcache.
1934 ********************************************************************/
1936 static void DirCacheAdd(struct smb_Dir *dirp, const char *name, long offset)
1938 struct name_cache_entry *e;
1940 if (dirp->name_cache_size == 0) {
1944 if (dirp->name_cache == NULL) {
1945 dirp->name_cache = talloc_zero_array(
1946 dirp, struct name_cache_entry, dirp->name_cache_size);
1948 if (dirp->name_cache == NULL) {
1953 dirp->name_cache_index = (dirp->name_cache_index+1) %
1954 dirp->name_cache_size;
1955 e = &dirp->name_cache[dirp->name_cache_index];
1956 TALLOC_FREE(e->name);
1957 e->name = talloc_strdup(dirp, name);
1961 /*******************************************************************
1962 Find an entry by name. Leave us at the offset after it.
1963 Don't check for veto or invisible files.
1964 ********************************************************************/
1966 bool SearchDir(struct smb_Dir *dirp, const char *name, long *poffset)
1969 const char *entry = NULL;
1970 char *talloced = NULL;
1971 connection_struct *conn = dirp->conn;
1973 /* Search back in the name cache. */
1974 if (dirp->name_cache_size && dirp->name_cache) {
1975 for (i = dirp->name_cache_index; i >= 0; i--) {
1976 struct name_cache_entry *e = &dirp->name_cache[i];
1977 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1978 *poffset = e->offset;
1979 SeekDir(dirp, e->offset);
1983 for (i = dirp->name_cache_size - 1; i > dirp->name_cache_index; i--) {
1984 struct name_cache_entry *e = &dirp->name_cache[i];
1985 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1986 *poffset = e->offset;
1987 SeekDir(dirp, e->offset);
1993 /* Not found in the name cache. Rewind directory and start from scratch. */
1994 SMB_VFS_REWINDDIR(conn, dirp->dir);
1995 dirp->file_number = 0;
1996 *poffset = START_OF_DIRECTORY_OFFSET;
1997 while ((entry = ReadDirName(dirp, poffset, NULL, &talloced))) {
1998 if (conn->case_sensitive ? (strcmp(entry, name) == 0) : strequal(entry, name)) {
1999 TALLOC_FREE(talloced);
2002 TALLOC_FREE(talloced);
2007 struct files_below_forall_state {
2010 int (*fn)(struct file_id fid, const struct share_mode_data *data,
2011 void *private_data);
2015 static int files_below_forall_fn(struct file_id fid,
2016 const struct share_mode_data *data,
2019 struct files_below_forall_state *state = private_data;
2020 char tmpbuf[PATH_MAX];
2021 char *fullpath, *to_free;
2024 len = full_path_tos(data->servicepath, data->base_name,
2025 tmpbuf, sizeof(tmpbuf),
2026 &fullpath, &to_free);
2030 if (state->dirpath_len >= len) {
2032 * Filter files above dirpath
2036 if (fullpath[state->dirpath_len] != '/') {
2038 * Filter file that don't have a path separator at the end of
2044 if (memcmp(state->dirpath, fullpath, state->dirpath_len) != 0) {
2051 return state->fn(fid, data, state->private_data);
2054 static int files_below_forall(connection_struct *conn,
2055 const struct smb_filename *dir_name,
2056 int (*fn)(struct file_id fid,
2057 const struct share_mode_data *data,
2058 void *private_data),
2061 struct files_below_forall_state state = {
2063 .private_data = private_data,
2066 char tmpbuf[PATH_MAX];
2069 state.dirpath_len = full_path_tos(conn->connectpath,
2070 dir_name->base_name,
2071 tmpbuf, sizeof(tmpbuf),
2072 &state.dirpath, &to_free);
2073 if (state.dirpath_len == -1) {
2077 ret = share_mode_forall(files_below_forall_fn, &state);
2078 TALLOC_FREE(to_free);
2082 struct have_file_open_below_state {
2086 static int have_file_open_below_fn(struct file_id fid,
2087 const struct share_mode_data *data,
2090 struct have_file_open_below_state *state = private_data;
2091 state->found_one = true;
2095 bool have_file_open_below(connection_struct *conn,
2096 const struct smb_filename *name)
2098 struct have_file_open_below_state state = {
2103 if (!VALID_STAT(name->st)) {
2106 if (!S_ISDIR(name->st.st_ex_mode)) {
2110 ret = files_below_forall(conn, name, have_file_open_below_fn, &state);
2115 return state.found_one;
2118 /*****************************************************************
2119 Is this directory empty ?
2120 *****************************************************************/
2122 NTSTATUS can_delete_directory_fsp(files_struct *fsp)
2124 NTSTATUS status = NT_STATUS_OK;
2126 const char *dname = NULL;
2127 const char *dirname = fsp->fsp_name->base_name;
2128 char *talloced = NULL;
2130 struct connection_struct *conn = fsp->conn;
2131 struct smb_Dir *dir_hnd = OpenDir_fsp(talloc_tos(),
2138 return map_nt_error_from_unix(errno);
2141 while ((dname = ReadDirName(dir_hnd, &dirpos, &st, &talloced))) {
2142 /* Quick check for "." and ".." */
2143 if (dname[0] == '.') {
2144 if (!dname[1] || (dname[1] == '.' && !dname[2])) {
2145 TALLOC_FREE(talloced);
2150 if (!is_visible_file(conn, dirname, dname, &st, True)) {
2151 TALLOC_FREE(talloced);
2155 DEBUG(10,("got name %s - can't delete\n",
2157 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
2160 TALLOC_FREE(talloced);
2161 TALLOC_FREE(dir_hnd);
2163 if (!NT_STATUS_IS_OK(status)) {
2167 if (!(fsp->posix_flags & FSP_POSIX_FLAGS_RENAME) &&
2168 lp_strict_rename(SNUM(conn)) &&
2169 have_file_open_below(fsp->conn, fsp->fsp_name))
2171 return NT_STATUS_ACCESS_DENIED;
2174 return NT_STATUS_OK;