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 Get the struct dptr_struct for a dir index.
112 ****************************************************************************/
114 static struct dptr_struct *dptr_get(struct smbd_server_connection *sconn,
117 struct dptr_struct *dptr;
119 for (dptr = sconn->searches.dirptrs; dptr != NULL; dptr = dptr->next) {
120 if(dptr->dnum != key) {
123 DLIST_PROMOTE(sconn->searches.dirptrs, dptr);
129 /****************************************************************************
130 Get the dir path for a dir index.
131 ****************************************************************************/
133 const char *dptr_path(struct smbd_server_connection *sconn, int key)
135 struct dptr_struct *dptr = dptr_get(sconn, key);
137 return(dptr->smb_dname->base_name);
141 /****************************************************************************
142 Get the dir wcard for a dir index.
143 ****************************************************************************/
145 const char *dptr_wcard(struct smbd_server_connection *sconn, int key)
147 struct dptr_struct *dptr = dptr_get(sconn, key);
153 /****************************************************************************
154 Get the dir attrib for a dir index.
155 ****************************************************************************/
157 uint16_t dptr_attr(struct smbd_server_connection *sconn, int key)
159 struct dptr_struct *dptr = dptr_get(sconn, key);
165 /****************************************************************************
166 Close a dptr (internal func).
167 ****************************************************************************/
169 static void dptr_close_internal(struct dptr_struct *dptr)
171 struct smbd_server_connection *sconn = dptr->conn->sconn;
173 DEBUG(4,("closing dptr key %d\n",dptr->dnum));
179 if (sconn->using_smb2) {
183 DLIST_REMOVE(sconn->searches.dirptrs, dptr);
186 * Free the dnum in the bitmap. Remember the dnum value is always
187 * biased by one with respect to the bitmap.
190 if (!bitmap_query(sconn->searches.dptr_bmap, dptr->dnum - 1)) {
191 DEBUG(0,("dptr_close_internal : Error - closing dnum = %d and bitmap not set !\n",
195 bitmap_clear(sconn->searches.dptr_bmap, dptr->dnum - 1);
198 TALLOC_FREE(dptr->dir_hnd);
202 /****************************************************************************
203 Close a dptr given a key.
204 ****************************************************************************/
206 void dptr_close(struct smbd_server_connection *sconn, int *key)
208 struct dptr_struct *dptr;
210 if(*key == INVALID_DPTR_KEY)
213 /* OS/2 seems to use -1 to indicate "close all directories" */
215 struct dptr_struct *next;
216 for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
218 dptr_close_internal(dptr);
220 *key = INVALID_DPTR_KEY;
224 dptr = dptr_get(sconn, *key);
227 DEBUG(0,("Invalid key %d given to dptr_close\n", *key));
231 dptr_close_internal(dptr);
233 *key = INVALID_DPTR_KEY;
236 /****************************************************************************
237 Close all dptrs for a cnum.
238 ****************************************************************************/
240 void dptr_closecnum(connection_struct *conn)
242 struct dptr_struct *dptr, *next;
243 struct smbd_server_connection *sconn = conn->sconn;
249 for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
251 if (dptr->conn == conn) {
252 dptr_close_internal(dptr);
257 /****************************************************************************
258 Are there any SMB1 searches active on this connection struct ?
259 ****************************************************************************/
261 bool dptr_activecnum(const struct smbd_server_connection *sconn,
262 const struct connection_struct *conn)
264 const struct dptr_struct *dptr;
266 for(dptr = sconn->searches.dirptrs; dptr; dptr = dptr->next) {
267 if (dptr->conn == conn) {
274 /****************************************************************************
275 Close a dptr that matches a given path, only if it matches the spid also.
276 ****************************************************************************/
278 void dptr_closepath(struct smbd_server_connection *sconn,
279 char *path,uint16_t spid)
281 struct dptr_struct *dptr, *next;
282 for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
284 if (spid == dptr->spid &&
285 strequal(dptr->smb_dname->base_name,path)) {
286 dptr_close_internal(dptr);
291 /****************************************************************************
292 Try and close the oldest handle not marked for
293 expect close in the hope that the client has
294 finished with that one.
295 ****************************************************************************/
297 static void dptr_close_oldest(struct smbd_server_connection *sconn,
300 struct dptr_struct *dptr;
303 * Go to the end of the list.
305 for(dptr = sconn->searches.dirptrs; dptr && dptr->next; dptr = dptr->next)
309 DEBUG(0,("No old dptrs available to close oldest ?\n"));
314 * If 'old' is true, close the oldest oldhandle dnum (ie. 1 < dnum < 256) that
315 * does not have expect_close set. If 'old' is false, close
316 * one of the new dnum handles.
319 for(; dptr; dptr = DLIST_PREV(dptr)) {
320 if ((old && (dptr->dnum < 256) && !dptr->expect_close) ||
321 (!old && (dptr->dnum > 255))) {
322 dptr_close_internal(dptr);
328 /****************************************************************************
329 Safely do an OpenDir as root, ensuring we're in the right place.
330 ****************************************************************************/
332 static struct smb_Dir *open_dir_with_privilege(connection_struct *conn,
333 struct smb_request *req,
334 const struct smb_filename *smb_dname,
338 struct smb_Dir *dir_hnd = NULL;
339 struct smb_filename *smb_fname_cwd = NULL;
340 struct smb_filename *saved_dir_fname = vfs_GetWd(talloc_tos(), conn);
341 struct privilege_paths *priv_paths = req->priv_paths;
344 if (saved_dir_fname == NULL) {
348 if (vfs_ChDir(conn, smb_dname) == -1) {
352 /* Now check the stat value is the same. */
353 smb_fname_cwd = synthetic_smb_fname(talloc_tos(),
358 if (smb_fname_cwd == NULL) {
361 ret = SMB_VFS_STAT(conn, smb_fname_cwd);
366 if (!check_same_stat(&smb_fname_cwd->st, &priv_paths->parent_name.st)) {
367 DEBUG(0,("open_dir_with_privilege: stat mismatch between %s "
369 smb_dname->base_name,
370 smb_fname_str_dbg(&priv_paths->parent_name)));
374 dir_hnd = OpenDir(NULL, conn, smb_fname_cwd, wcard, attr);
378 vfs_ChDir(conn, saved_dir_fname);
379 TALLOC_FREE(saved_dir_fname);
383 /****************************************************************************
384 Create a new dir ptr. If the flag old_handle is true then we must allocate
385 from the bitmap range 0 - 255 as old SMBsearch directory handles are only
386 one byte long. If old_handle is false we allocate from the range
387 256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
388 a directory handle is never zero.
389 wcard must not be zero.
390 ****************************************************************************/
392 NTSTATUS dptr_create(connection_struct *conn,
393 struct smb_request *req,
395 const struct smb_filename *smb_dname,
402 struct dptr_struct **dptr_ret)
404 struct smbd_server_connection *sconn = conn->sconn;
405 struct dptr_struct *dptr = NULL;
406 struct smb_Dir *dir_hnd;
408 if (fsp && fsp->is_directory && fsp->fh->fd != -1) {
409 smb_dname = fsp->fsp_name;
412 DEBUG(5,("dptr_create dir=%s\n", smb_dname->base_name));
415 DEBUG(0,("dptr_create: called with fake connection_struct\n"));
416 return NT_STATUS_INTERNAL_ERROR;
420 return NT_STATUS_INVALID_PARAMETER;
424 if (!(fsp->access_mask & SEC_DIR_LIST)) {
425 DEBUG(5,("dptr_create: directory %s "
426 "not open for LIST access\n",
427 smb_dname->base_name));
428 return NT_STATUS_ACCESS_DENIED;
430 dir_hnd = OpenDir_fsp(NULL, conn, fsp, wcard, attr);
433 bool backup_intent = (req && req->priv_paths);
435 struct smb_filename *smb_dname_cp =
436 cp_smb_filename(talloc_tos(), smb_dname);
438 if (smb_dname_cp == NULL) {
439 return NT_STATUS_NO_MEMORY;
442 if (req != NULL && req->posix_pathnames) {
443 ret = SMB_VFS_LSTAT(conn, smb_dname_cp);
445 ret = SMB_VFS_STAT(conn, smb_dname_cp);
448 status = map_nt_error_from_unix(errno);
449 TALLOC_FREE(smb_dname_cp);
452 if (!S_ISDIR(smb_dname_cp->st.st_ex_mode)) {
453 TALLOC_FREE(smb_dname_cp);
454 return NT_STATUS_NOT_A_DIRECTORY;
456 status = smbd_check_access_rights(conn,
460 if (!NT_STATUS_IS_OK(status)) {
461 TALLOC_FREE(smb_dname_cp);
465 dir_hnd = open_dir_with_privilege(conn,
471 dir_hnd = OpenDir(NULL,
477 TALLOC_FREE(smb_dname_cp);
481 return map_nt_error_from_unix(errno);
484 dptr = talloc_zero(NULL, struct dptr_struct);
486 DEBUG(0,("talloc fail in dptr_create.\n"));
487 TALLOC_FREE(dir_hnd);
488 return NT_STATUS_NO_MEMORY;
491 dptr->smb_dname = cp_smb_filename(dptr, smb_dname);
492 if (!dptr->smb_dname) {
494 TALLOC_FREE(dir_hnd);
495 return NT_STATUS_NO_MEMORY;
498 dptr->dir_hnd = dir_hnd;
500 dptr->expect_close = expect_close;
501 dptr->wcard = talloc_strdup(dptr, wcard);
504 TALLOC_FREE(dir_hnd);
505 return NT_STATUS_NO_MEMORY;
507 if ((req != NULL && req->posix_pathnames) ||
508 (wcard[0] == '.' && wcard[1] == 0)) {
509 dptr->has_wild = True;
511 dptr->has_wild = wcard_has_wild;
516 if (sconn->using_smb2) {
523 * This is an old-style SMBsearch request. Ensure the
524 * value we return will fit in the range 1-255.
527 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 0);
529 if(dptr->dnum == -1 || dptr->dnum > 254) {
532 * Try and close the oldest handle not marked for
533 * expect close in the hope that the client has
534 * finished with that one.
537 dptr_close_oldest(sconn, true);
539 /* Now try again... */
540 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 0);
541 if(dptr->dnum == -1 || dptr->dnum > 254) {
542 DEBUG(0,("dptr_create: returned %d: Error - all old dirptrs in use ?\n", dptr->dnum));
544 TALLOC_FREE(dir_hnd);
545 return NT_STATUS_TOO_MANY_OPENED_FILES;
551 * This is a new-style trans2 request. Allocate from
552 * a range that will return 256 - MAX_DIRECTORY_HANDLES.
555 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 255);
557 if(dptr->dnum == -1 || dptr->dnum < 255) {
560 * Try and close the oldest handle close in the hope that
561 * the client has finished with that one. This will only
562 * happen in the case of the Win98 client bug where it leaks
566 dptr_close_oldest(sconn, false);
568 /* Now try again... */
569 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 255);
571 if(dptr->dnum == -1 || dptr->dnum < 255) {
572 DEBUG(0,("dptr_create: returned %d: Error - all new dirptrs in use ?\n", dptr->dnum));
574 TALLOC_FREE(dir_hnd);
575 return NT_STATUS_TOO_MANY_OPENED_FILES;
580 bitmap_set(sconn->searches.dptr_bmap, dptr->dnum);
582 dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
584 DLIST_ADD(sconn->searches.dirptrs, dptr);
587 DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
589 dptr->smb_dname->base_name,
598 /****************************************************************************
599 Wrapper functions to access the lower level directory handles.
600 ****************************************************************************/
602 void dptr_CloseDir(files_struct *fsp)
606 * The destructor for the struct smb_Dir
607 * (fsp->dptr->dir_hnd) now handles
608 * all resource deallocation.
610 dptr_close_internal(fsp->dptr);
615 void dptr_SeekDir(struct dptr_struct *dptr, long offset)
617 SeekDir(dptr->dir_hnd, offset);
620 long dptr_TellDir(struct dptr_struct *dptr)
622 return TellDir(dptr->dir_hnd);
625 bool dptr_has_wild(struct dptr_struct *dptr)
627 return dptr->has_wild;
630 int dptr_dnum(struct dptr_struct *dptr)
635 bool dptr_get_priv(struct dptr_struct *dptr)
640 void dptr_set_priv(struct dptr_struct *dptr)
645 /****************************************************************************
646 Return the next visible file name, skipping veto'd and invisible files.
647 ****************************************************************************/
649 static const char *dptr_normal_ReadDirName(struct dptr_struct *dptr,
650 long *poffset, SMB_STRUCT_STAT *pst,
653 /* Normal search for the next file. */
655 char *talloced = NULL;
657 while ((name = ReadDirName(dptr->dir_hnd, poffset, pst, &talloced))
659 if (is_visible_file(dptr->conn,
660 dptr->smb_dname->base_name,
664 *ptalloced = talloced;
667 TALLOC_FREE(talloced);
672 /****************************************************************************
673 Return the next visible file name, skipping veto'd and invisible files.
674 ****************************************************************************/
676 static char *dptr_ReadDirName(TALLOC_CTX *ctx,
677 struct dptr_struct *dptr,
679 SMB_STRUCT_STAT *pst)
681 struct smb_filename smb_fname_base;
683 const char *name_temp = NULL;
684 char *talloced = NULL;
685 char *pathreal = NULL;
686 char *found_name = NULL;
689 SET_STAT_INVALID(*pst);
691 if (dptr->has_wild || dptr->did_stat) {
692 name_temp = dptr_normal_ReadDirName(dptr, poffset, pst,
694 if (name_temp == NULL) {
697 if (talloced != NULL) {
698 return talloc_move(ctx, &talloced);
700 return talloc_strdup(ctx, name_temp);
703 /* If poffset is -1 then we know we returned this name before and we
704 * have no wildcards. We're at the end of the directory. */
705 if (*poffset == END_OF_DIRECTORY_OFFSET) {
709 /* We know the stored wcard contains no wildcard characters.
710 * See if we can match with a stat call. If we can't, then set
711 * did_stat to true to ensure we only do this once and keep
714 dptr->did_stat = true;
716 /* First check if it should be visible. */
717 if (!is_visible_file(dptr->conn,
718 dptr->smb_dname->base_name,
722 /* This only returns false if the file was found, but
723 is explicitly not visible. Set us to end of
724 directory, but return NULL as we know we can't ever
729 if (VALID_STAT(*pst)) {
730 name = talloc_strdup(ctx, dptr->wcard);
734 pathreal = talloc_asprintf(ctx,
736 dptr->smb_dname->base_name,
741 /* Create an smb_filename with stream_name == NULL. */
742 smb_fname_base = (struct smb_filename) { .base_name = pathreal };
744 if (SMB_VFS_STAT(dptr->conn, &smb_fname_base) == 0) {
745 *pst = smb_fname_base.st;
746 name = talloc_strdup(ctx, dptr->wcard);
749 /* If we get any other error than ENOENT or ENOTDIR
750 then the file exists we just can't stat it. */
751 if (errno != ENOENT && errno != ENOTDIR) {
752 name = talloc_strdup(ctx, dptr->wcard);
757 /* Stat failed. We know this is authoratiative if we are
758 * providing case sensitive semantics or the underlying
759 * filesystem is case sensitive.
761 if (dptr->conn->case_sensitive ||
762 !(dptr->conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH))
768 * Try case-insensitive stat if the fs has the ability. This avoids
769 * scanning the whole directory.
771 ret = SMB_VFS_GET_REAL_FILENAME(dptr->conn,
772 dptr->smb_dname->base_name,
779 } else if (errno == ENOENT) {
780 /* The case-insensitive lookup was authoritative. */
784 TALLOC_FREE(pathreal);
786 name_temp = dptr_normal_ReadDirName(dptr, poffset, pst, &talloced);
787 if (name_temp == NULL) {
790 if (talloced != NULL) {
791 return talloc_move(ctx, &talloced);
793 return talloc_strdup(ctx, name_temp);
796 TALLOC_FREE(pathreal);
798 /* We need to set the underlying dir_hnd offset to -1
799 * also as this function is usually called with the
800 * output from TellDir. */
801 dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
805 /****************************************************************************
806 Search for a file by name, skipping veto'ed and not visible files.
807 ****************************************************************************/
809 bool dptr_SearchDir(struct dptr_struct *dptr, const char *name, long *poffset, SMB_STRUCT_STAT *pst)
811 SET_STAT_INVALID(*pst);
813 if (!dptr->has_wild && (dptr->dir_hnd->offset == END_OF_DIRECTORY_OFFSET)) {
814 /* This is a singleton directory and we're already at the end. */
815 *poffset = END_OF_DIRECTORY_OFFSET;
819 return SearchDir(dptr->dir_hnd, name, poffset);
822 /****************************************************************************
823 Map a native directory offset to a 32-bit cookie.
824 ****************************************************************************/
826 static uint32_t map_dir_offset_to_wire(struct dptr_struct *dptr, long offset)
831 if (offset == END_OF_DIRECTORY_OFFSET) {
832 return WIRE_END_OF_DIRECTORY_OFFSET;
833 } else if(offset == START_OF_DIRECTORY_OFFSET) {
834 return WIRE_START_OF_DIRECTORY_OFFSET;
835 } else if (offset == DOT_DOT_DIRECTORY_OFFSET) {
836 return WIRE_DOT_DOT_DIRECTORY_OFFSET;
838 if (sizeof(long) == 4) {
839 /* 32-bit machine. We can cheat... */
840 return (uint32_t)offset;
842 if (dptr->dptr_cache == NULL) {
843 /* Lazy initialize cache. */
844 dptr->dptr_cache = memcache_init(dptr, 0);
845 if (dptr->dptr_cache == NULL) {
846 return WIRE_END_OF_DIRECTORY_OFFSET;
849 /* Have we seen this offset before ? */
850 key.data = (void *)&offset;
851 key.length = sizeof(offset);
852 if (memcache_lookup(dptr->dptr_cache,
853 SMB1_SEARCH_OFFSET_MAP,
856 uint32_t wire_offset;
857 SMB_ASSERT(val.length == sizeof(wire_offset));
858 memcpy(&wire_offset, val.data, sizeof(wire_offset));
859 DEBUG(10,("found wire %u <-> offset %ld\n",
860 (unsigned int)wire_offset,
865 /* Allocate a new wire cookie. */
868 } while (dptr->counter == WIRE_START_OF_DIRECTORY_OFFSET ||
869 dptr->counter == WIRE_END_OF_DIRECTORY_OFFSET ||
870 dptr->counter == WIRE_DOT_DOT_DIRECTORY_OFFSET);
871 /* Store it in the cache. */
872 key.data = (void *)&offset;
873 key.length = sizeof(offset);
874 val.data = (void *)&dptr->counter;
875 val.length = sizeof(dptr->counter); /* MUST BE uint32_t ! */
876 memcache_add(dptr->dptr_cache,
877 SMB1_SEARCH_OFFSET_MAP,
880 /* And the reverse mapping for lookup from
881 map_wire_to_dir_offset(). */
882 memcache_add(dptr->dptr_cache,
883 SMB1_SEARCH_OFFSET_MAP,
886 DEBUG(10,("stored wire %u <-> offset %ld\n",
887 (unsigned int)dptr->counter,
889 return dptr->counter;
892 /****************************************************************************
893 Fill the 5 byte server reserved dptr field.
894 ****************************************************************************/
896 bool dptr_fill(struct smbd_server_connection *sconn,
897 char *buf1,unsigned int key)
899 unsigned char *buf = (unsigned char *)buf1;
900 struct dptr_struct *dptr = dptr_get(sconn, key);
901 uint32_t wire_offset;
903 DEBUG(1,("filling null dirptr %d\n",key));
906 wire_offset = map_dir_offset_to_wire(dptr,TellDir(dptr->dir_hnd));
907 DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key,
908 (long)dptr->dir_hnd,(int)wire_offset));
910 SIVAL(buf,1,wire_offset);
914 /****************************************************************************
915 Map a 32-bit wire cookie to a native directory offset.
916 ****************************************************************************/
918 static long map_wire_to_dir_offset(struct dptr_struct *dptr, uint32_t wire_offset)
923 if (wire_offset == WIRE_END_OF_DIRECTORY_OFFSET) {
924 return END_OF_DIRECTORY_OFFSET;
925 } else if(wire_offset == WIRE_START_OF_DIRECTORY_OFFSET) {
926 return START_OF_DIRECTORY_OFFSET;
927 } else if (wire_offset == WIRE_DOT_DOT_DIRECTORY_OFFSET) {
928 return DOT_DOT_DIRECTORY_OFFSET;
930 if (sizeof(long) == 4) {
931 /* 32-bit machine. We can cheat... */
932 return (long)wire_offset;
934 if (dptr->dptr_cache == NULL) {
935 /* Logic error, cache should be initialized. */
936 return END_OF_DIRECTORY_OFFSET;
938 key.data = (void *)&wire_offset;
939 key.length = sizeof(wire_offset);
940 if (memcache_lookup(dptr->dptr_cache,
941 SMB1_SEARCH_OFFSET_MAP,
946 SMB_ASSERT(val.length == sizeof(offset));
947 memcpy(&offset, val.data, sizeof(offset));
948 DEBUG(10,("lookup wire %u <-> offset %ld\n",
949 (unsigned int)wire_offset,
953 return END_OF_DIRECTORY_OFFSET;
956 /****************************************************************************
957 Fetch the dir ptr and seek it given the 5 byte server field.
958 ****************************************************************************/
960 struct dptr_struct *dptr_fetch(struct smbd_server_connection *sconn,
963 unsigned int key = *(unsigned char *)buf;
964 struct dptr_struct *dptr = dptr_get(sconn, key);
965 uint32_t wire_offset;
969 DEBUG(3,("fetched null dirptr %d\n",key));
973 wire_offset = IVAL(buf,1);
974 seekoff = map_wire_to_dir_offset(dptr, wire_offset);
975 SeekDir(dptr->dir_hnd,seekoff);
976 DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
977 key, dptr->smb_dname->base_name, (int)seekoff));
981 /****************************************************************************
983 ****************************************************************************/
985 struct dptr_struct *dptr_fetch_lanman2(struct smbd_server_connection *sconn,
988 struct dptr_struct *dptr = dptr_get(sconn, dptr_num);
991 DEBUG(3,("fetched null dirptr %d\n",dptr_num));
994 DEBUG(3,("fetching dirptr %d for path %s\n",
996 dptr->smb_dname->base_name));
1000 static bool mangle_mask_match(connection_struct *conn,
1001 const char *filename,
1006 if (!name_to_8_3(filename,mname,False,conn->params)) {
1009 return mask_match_search(mname,mask,False);
1012 bool smbd_dirptr_get_entry(TALLOC_CTX *ctx,
1013 struct dptr_struct *dirptr,
1019 bool (*match_fn)(TALLOC_CTX *ctx,
1024 bool (*mode_fn)(TALLOC_CTX *ctx,
1026 struct smb_filename *smb_fname,
1031 struct smb_filename **_smb_fname,
1035 connection_struct *conn = dirptr->conn;
1038 const char *dpath = dirptr->smb_dname->base_name;
1039 bool dirptr_path_is_dot = ISDOT(dpath);
1044 pathlen = strlen(dpath);
1045 slashlen = ( dpath[pathlen-1] != '/') ? 1 : 0;
1050 SMB_STRUCT_STAT sbuf = { 0 };
1054 char *pathreal = NULL;
1055 struct smb_filename smb_fname;
1059 cur_offset = dptr_TellDir(dirptr);
1060 prev_offset = cur_offset;
1061 dname = dptr_ReadDirName(ctx, dirptr, &cur_offset, &sbuf);
1063 DEBUG(6,("smbd_dirptr_get_entry: dirptr 0x%lx now at offset %ld\n",
1064 (long)dirptr, cur_offset));
1066 if (dname == NULL) {
1070 isdots = (ISDOT(dname) || ISDOTDOT(dname));
1071 if (dont_descend && !isdots) {
1077 * fname may get mangled, dname is never mangled.
1078 * Whenever we're accessing the filesystem we use
1079 * pathreal which is composed from dname.
1082 ok = match_fn(ctx, private_data, dname, mask, &fname);
1090 * pathreal = talloc_asprintf(ctx, "%s%s%s", dirptr->path,
1091 * needslash?"/":"", dname);
1092 * but this was measurably slower than doing the memcpy.
1095 pathreal = talloc_array(
1097 pathlen + slashlen + talloc_get_size(dname));
1105 * We don't want to pass ./xxx to modules below us so don't
1106 * add the path if it is just . by itself.
1108 if (dirptr_path_is_dot) {
1109 memcpy(pathreal, dname, talloc_get_size(dname));
1111 memcpy(pathreal, dpath, pathlen);
1112 pathreal[pathlen] = '/';
1113 memcpy(pathreal + slashlen + pathlen, dname,
1114 talloc_get_size(dname));
1117 /* Create smb_fname with NULL stream_name. */
1118 smb_fname = (struct smb_filename) {
1119 .base_name = pathreal, .st = sbuf
1122 ok = mode_fn(ctx, private_data, &smb_fname, get_dosmode, &mode);
1126 TALLOC_FREE(pathreal);
1130 if (!dir_check_ftype(mode, dirtype)) {
1131 DEBUG(5,("[%s] attribs 0x%x didn't match 0x%x\n",
1132 fname, (unsigned int)mode, (unsigned int)dirtype));
1135 TALLOC_FREE(pathreal);
1139 if (ask_sharemode) {
1140 struct timespec write_time_ts;
1141 struct file_id fileid;
1143 fileid = vfs_file_id_from_sbuf(conn,
1145 get_file_infos(fileid, 0, NULL, &write_time_ts);
1146 if (!null_timespec(write_time_ts)) {
1147 update_stat_ex_mtime(&smb_fname.st,
1152 DEBUG(3,("smbd_dirptr_get_entry mask=[%s] found %s "
1154 mask, smb_fname_str_dbg(&smb_fname),
1157 if (!conn->sconn->using_smb2) {
1159 * The dircache is only needed for SMB1 because SMB1
1160 * uses a name for the resume wheras SMB2 always
1161 * continues from the next position (unless it's told to
1162 * restart or close-and-reopen the listing).
1164 DirCacheAdd(dirptr->dir_hnd, dname, cur_offset);
1169 *_smb_fname = cp_smb_filename(ctx, &smb_fname);
1170 TALLOC_FREE(pathreal);
1171 if (*_smb_fname == NULL) {
1176 *_prev_offset = prev_offset;
1184 /****************************************************************************
1185 Get an 8.3 directory entry.
1186 ****************************************************************************/
1188 static bool smbd_dirptr_8_3_match_fn(TALLOC_CTX *ctx,
1194 connection_struct *conn = (connection_struct *)private_data;
1196 if ((strcmp(mask,"*.*") == 0) ||
1197 mask_match_search(dname, mask, false) ||
1198 mangle_mask_match(conn, dname, mask)) {
1202 * Ensure we can push the original name as UCS2. If
1203 * not, then just don't return this name.
1207 size_t len = (strlen(dname) + 2) * 4; /* Allow enough space. */
1208 uint8_t *tmp = talloc_array(talloc_tos(),
1212 status = srvstr_push(NULL,
1213 FLAGS2_UNICODE_STRINGS,
1222 if (!NT_STATUS_IS_OK(status)) {
1226 if (!mangle_is_8_3(dname, false, conn->params)) {
1227 bool ok = name_to_8_3(dname, mname, false,
1237 *_fname = talloc_strdup(ctx, fname);
1238 if (*_fname == NULL) {
1248 static bool smbd_dirptr_8_3_mode_fn(TALLOC_CTX *ctx,
1250 struct smb_filename *smb_fname,
1254 connection_struct *conn = (connection_struct *)private_data;
1256 if (!VALID_STAT(smb_fname->st)) {
1257 if ((SMB_VFS_STAT(conn, smb_fname)) != 0) {
1258 DEBUG(5,("smbd_dirptr_8_3_mode_fn: "
1259 "Couldn't stat [%s]. Error "
1261 smb_fname_str_dbg(smb_fname),
1267 *_mode = dos_mode(conn, smb_fname);
1271 bool get_dir_entry(TALLOC_CTX *ctx,
1272 struct dptr_struct *dirptr,
1278 struct timespec *_date,
1282 connection_struct *conn = dirptr->conn;
1284 struct smb_filename *smb_fname = NULL;
1289 ok = smbd_dirptr_get_entry(ctx,
1296 smbd_dirptr_8_3_match_fn,
1297 smbd_dirptr_8_3_mode_fn,
1307 *_fname = talloc_move(ctx, &fname);
1308 *_size = smb_fname->st.st_ex_size;
1310 *_date = smb_fname->st.st_ex_mtime;
1311 TALLOC_FREE(smb_fname);
1315 /*******************************************************************
1316 Check to see if a user can read a file. This is only approximate,
1317 it is used as part of the "hide unreadable" option. Don't
1318 use it for anything security sensitive.
1319 ********************************************************************/
1321 static bool user_can_read_file(connection_struct *conn,
1322 struct smb_filename *smb_fname)
1325 uint32_t rejected_share_access = 0;
1326 uint32_t rejected_mask = 0;
1327 struct security_descriptor *sd = NULL;
1328 uint32_t access_mask = FILE_READ_DATA|
1330 FILE_READ_ATTRIBUTES|
1331 SEC_STD_READ_CONTROL;
1334 * Never hide files from the root user.
1335 * We use (uid_t)0 here not sec_initial_uid()
1336 * as make test uses a single user context.
1339 if (get_current_uid(conn) == (uid_t)0) {
1344 * We can't directly use smbd_check_access_rights()
1345 * here, as this implicitly grants FILE_READ_ATTRIBUTES
1346 * which the Windows access-based-enumeration code
1347 * explicitly checks for on the file security descriptor.
1350 * https://bugzilla.samba.org/show_bug.cgi?id=10252
1352 * and the smb2.acl2.ACCESSBASED test for details.
1355 rejected_share_access = access_mask & ~(conn->share_access);
1356 if (rejected_share_access) {
1357 DEBUG(10, ("rejected share access 0x%x "
1359 (unsigned int)access_mask,
1360 smb_fname_str_dbg(smb_fname),
1361 (unsigned int)rejected_share_access ));
1365 status = SMB_VFS_GET_NT_ACL(conn,
1373 if (!NT_STATUS_IS_OK(status)) {
1374 DEBUG(10, ("Could not get acl "
1376 smb_fname_str_dbg(smb_fname),
1377 nt_errstr(status)));
1381 status = se_file_access_check(sd,
1382 get_current_nttok(conn),
1389 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1390 DEBUG(10,("rejected bits 0x%x read access for %s\n",
1391 (unsigned int)rejected_mask,
1392 smb_fname_str_dbg(smb_fname) ));
1398 /*******************************************************************
1399 Check to see if a user can write a file (and only files, we do not
1400 check dirs on this one). This is only approximate,
1401 it is used as part of the "hide unwriteable" option. Don't
1402 use it for anything security sensitive.
1403 ********************************************************************/
1405 static bool user_can_write_file(connection_struct *conn,
1406 const struct smb_filename *smb_fname)
1409 * Never hide files from the root user.
1410 * We use (uid_t)0 here not sec_initial_uid()
1411 * as make test uses a single user context.
1414 if (get_current_uid(conn) == (uid_t)0) {
1418 SMB_ASSERT(VALID_STAT(smb_fname->st));
1420 /* Pseudo-open the file */
1422 if(S_ISDIR(smb_fname->st.st_ex_mode)) {
1426 return can_write_to_file(conn, smb_fname);
1429 /*******************************************************************
1430 Is a file a "special" type ?
1431 ********************************************************************/
1433 static bool file_is_special(connection_struct *conn,
1434 const struct smb_filename *smb_fname)
1437 * Never hide files from the root user.
1438 * We use (uid_t)0 here not sec_initial_uid()
1439 * as make test uses a single user context.
1442 if (get_current_uid(conn) == (uid_t)0) {
1446 SMB_ASSERT(VALID_STAT(smb_fname->st));
1448 if (S_ISREG(smb_fname->st.st_ex_mode) ||
1449 S_ISDIR(smb_fname->st.st_ex_mode) ||
1450 S_ISLNK(smb_fname->st.st_ex_mode))
1456 /*******************************************************************
1457 Should the file be seen by the client?
1458 NOTE: A successful return is no guarantee of the file's existence.
1459 ********************************************************************/
1461 bool is_visible_file(connection_struct *conn, const char *dir_path,
1462 const char *name, SMB_STRUCT_STAT *pst, bool use_veto)
1464 bool hide_unreadable = lp_hide_unreadable(SNUM(conn));
1465 bool hide_unwriteable = lp_hide_unwriteable_files(SNUM(conn));
1466 bool hide_special = lp_hide_special_files(SNUM(conn));
1467 int hide_new_files_timeout = lp_hide_new_files_timeout(SNUM(conn));
1469 struct smb_filename *smb_fname_base = NULL;
1472 if ((strcmp(".",name) == 0) || (strcmp("..",name) == 0)) {
1473 return True; /* . and .. are always visible. */
1476 /* If it's a vetoed file, pretend it doesn't even exist */
1477 if (use_veto && IS_VETO_PATH(conn, name)) {
1478 DEBUG(10,("is_visible_file: file %s is vetoed.\n", name ));
1482 if (hide_unreadable ||
1485 (hide_new_files_timeout != 0))
1487 entry = talloc_asprintf(talloc_tos(), "%s/%s", dir_path, name);
1493 /* Create an smb_filename with stream_name == NULL. */
1494 smb_fname_base = synthetic_smb_fname(talloc_tos(),
1499 if (smb_fname_base == NULL) {
1504 /* If the file name does not exist, there's no point checking
1505 * the configuration options. We succeed, on the basis that the
1506 * checks *might* have passed if the file was present.
1508 if (!VALID_STAT(*pst)) {
1509 if (SMB_VFS_STAT(conn, smb_fname_base) != 0) {
1513 *pst = smb_fname_base->st;
1516 /* Honour _hide unreadable_ option */
1517 if (hide_unreadable &&
1518 !user_can_read_file(conn, smb_fname_base)) {
1519 DEBUG(10,("is_visible_file: file %s is unreadable.\n",
1524 /* Honour _hide unwriteable_ option */
1525 if (hide_unwriteable && !user_can_write_file(conn,
1527 DEBUG(10,("is_visible_file: file %s is unwritable.\n",
1532 /* Honour _hide_special_ option */
1533 if (hide_special && file_is_special(conn, smb_fname_base)) {
1534 DEBUG(10,("is_visible_file: file %s is special.\n",
1540 if (hide_new_files_timeout != 0) {
1542 double age = timespec_elapsed(
1543 &smb_fname_base->st.st_ex_mtime);
1545 if (age < (double)hide_new_files_timeout) {
1554 TALLOC_FREE(smb_fname_base);
1559 static int smb_Dir_destructor(struct smb_Dir *dirp)
1561 if (dirp->dir != NULL) {
1562 SMB_VFS_CLOSEDIR(dirp->conn,dirp->dir);
1563 if (dirp->fsp != NULL) {
1565 * The SMB_VFS_CLOSEDIR above
1566 * closes the underlying fd inside
1569 dirp->fsp->fh->fd = -1;
1570 if (dirp->fsp->dptr != NULL) {
1571 SMB_ASSERT(dirp->fsp->dptr->dir_hnd == dirp);
1572 dirp->fsp->dptr->dir_hnd = NULL;
1580 /*******************************************************************
1582 ********************************************************************/
1584 static struct smb_Dir *OpenDir_internal(TALLOC_CTX *mem_ctx,
1585 connection_struct *conn,
1586 const struct smb_filename *smb_dname,
1590 struct smb_Dir *dirp = talloc_zero(mem_ctx, struct smb_Dir);
1596 dirp->dir = SMB_VFS_OPENDIR(conn, smb_dname, mask, attr);
1599 DEBUG(5,("OpenDir: Can't open %s. %s\n",
1600 smb_dname->base_name,
1607 if (!conn->sconn->using_smb2) {
1609 * The dircache is only needed for SMB1 because SMB1 uses a name
1610 * for the resume wheras SMB2 always continues from the next
1611 * position (unless it's told to restart or close-and-reopen the
1614 dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
1617 talloc_set_destructor(dirp, smb_Dir_destructor);
1626 /****************************************************************************
1627 Open a directory handle by pathname, ensuring it's under the share path.
1628 ****************************************************************************/
1630 static struct smb_Dir *open_dir_safely(TALLOC_CTX *ctx,
1631 connection_struct *conn,
1632 const struct smb_filename *smb_dname,
1636 struct smb_Dir *dir_hnd = NULL;
1637 struct smb_filename *smb_fname_cwd = NULL;
1638 struct smb_filename *saved_dir_fname = vfs_GetWd(ctx, conn);
1641 if (saved_dir_fname == NULL) {
1645 if (vfs_ChDir(conn, smb_dname) == -1) {
1649 smb_fname_cwd = synthetic_smb_fname(talloc_tos(),
1654 if (smb_fname_cwd == NULL) {
1659 * Now the directory is pinned, use
1660 * REALPATH to ensure we can access it.
1662 status = check_name(conn, smb_fname_cwd);
1663 if (!NT_STATUS_IS_OK(status)) {
1667 dir_hnd = OpenDir_internal(ctx,
1673 if (dir_hnd == NULL) {
1678 * OpenDir_internal only gets "." as the dir name.
1679 * Store the real dir name here.
1682 dir_hnd->dir_smb_fname = cp_smb_filename(dir_hnd, smb_dname);
1683 if (!dir_hnd->dir_smb_fname) {
1684 TALLOC_FREE(dir_hnd);
1690 vfs_ChDir(conn, saved_dir_fname);
1691 TALLOC_FREE(saved_dir_fname);
1695 struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn,
1696 const struct smb_filename *smb_dname,
1700 return open_dir_safely(mem_ctx,
1707 /*******************************************************************
1708 Open a directory from an fsp.
1709 ********************************************************************/
1711 static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn,
1716 struct smb_Dir *dirp = talloc_zero(mem_ctx, struct smb_Dir);
1722 if (!fsp->is_directory) {
1727 if (fsp->fh->fd == -1) {
1734 if (!conn->sconn->using_smb2) {
1736 * The dircache is only needed for SMB1 because SMB1 uses a name
1737 * for the resume wheras SMB2 always continues from the next
1738 * position (unless it's told to restart or close-and-reopen the
1741 dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
1744 dirp->dir_smb_fname = cp_smb_filename(dirp, fsp->fsp_name);
1745 if (!dirp->dir_smb_fname) {
1750 dirp->dir = SMB_VFS_FDOPENDIR(fsp, mask, attr);
1751 if (dirp->dir != NULL) {
1754 DEBUG(10,("OpenDir_fsp: SMB_VFS_FDOPENDIR on %s returned "
1756 dirp->dir_smb_fname->base_name,
1758 if (errno != ENOSYS) {
1763 if (dirp->dir == NULL) {
1764 /* FDOPENDIR is not supported. Use OPENDIR instead. */
1766 return open_dir_safely(mem_ctx,
1773 talloc_set_destructor(dirp, smb_Dir_destructor);
1783 /*******************************************************************
1784 Read from a directory.
1785 Return directory entry, current offset, and optional stat information.
1786 Don't check for veto or invisible files.
1787 ********************************************************************/
1789 const char *ReadDirName(struct smb_Dir *dirp, long *poffset,
1790 SMB_STRUCT_STAT *sbuf, char **ptalloced)
1793 char *talloced = NULL;
1794 connection_struct *conn = dirp->conn;
1796 /* Cheat to allow . and .. to be the first entries returned. */
1797 if (((*poffset == START_OF_DIRECTORY_OFFSET) ||
1798 (*poffset == DOT_DOT_DIRECTORY_OFFSET)) && (dirp->file_number < 2))
1800 if (dirp->file_number == 0) {
1802 *poffset = dirp->offset = START_OF_DIRECTORY_OFFSET;
1805 *poffset = dirp->offset = DOT_DOT_DIRECTORY_OFFSET;
1807 dirp->file_number++;
1812 if (*poffset == END_OF_DIRECTORY_OFFSET) {
1813 *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1817 /* A real offset, seek to it. */
1818 SeekDir(dirp, *poffset);
1820 while ((n = vfs_readdirname(conn, dirp->dir, sbuf, &talloced))) {
1821 /* Ignore . and .. - we've already returned them. */
1823 if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) {
1824 TALLOC_FREE(talloced);
1828 *poffset = dirp->offset = SMB_VFS_TELLDIR(conn, dirp->dir);
1829 *ptalloced = talloced;
1830 dirp->file_number++;
1833 *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1838 /*******************************************************************
1839 Rewind to the start.
1840 ********************************************************************/
1842 void RewindDir(struct smb_Dir *dirp, long *poffset)
1844 SMB_VFS_REWINDDIR(dirp->conn, dirp->dir);
1845 dirp->file_number = 0;
1846 dirp->offset = START_OF_DIRECTORY_OFFSET;
1847 *poffset = START_OF_DIRECTORY_OFFSET;
1850 /*******************************************************************
1852 ********************************************************************/
1854 void SeekDir(struct smb_Dir *dirp, long offset)
1856 if (offset != dirp->offset) {
1857 if (offset == START_OF_DIRECTORY_OFFSET) {
1858 RewindDir(dirp, &offset);
1860 * Ok we should really set the file number here
1861 * to 1 to enable ".." to be returned next. Trouble
1862 * is I'm worried about callers using SeekDir(dirp,0)
1863 * as equivalent to RewindDir(). So leave this alone
1866 } else if (offset == DOT_DOT_DIRECTORY_OFFSET) {
1867 RewindDir(dirp, &offset);
1869 * Set the file number to 2 - we want to get the first
1870 * real file entry (the one we return after "..")
1871 * on the next ReadDir.
1873 dirp->file_number = 2;
1874 } else if (offset == END_OF_DIRECTORY_OFFSET) {
1875 ; /* Don't seek in this case. */
1877 SMB_VFS_SEEKDIR(dirp->conn, dirp->dir, offset);
1879 dirp->offset = offset;
1883 /*******************************************************************
1884 Tell a dir position.
1885 ********************************************************************/
1887 long TellDir(struct smb_Dir *dirp)
1889 return(dirp->offset);
1892 /*******************************************************************
1893 Add an entry into the dcache.
1894 ********************************************************************/
1896 static void DirCacheAdd(struct smb_Dir *dirp, const char *name, long offset)
1898 struct name_cache_entry *e;
1900 if (dirp->name_cache_size == 0) {
1904 if (dirp->name_cache == NULL) {
1905 dirp->name_cache = talloc_zero_array(
1906 dirp, struct name_cache_entry, dirp->name_cache_size);
1908 if (dirp->name_cache == NULL) {
1913 dirp->name_cache_index = (dirp->name_cache_index+1) %
1914 dirp->name_cache_size;
1915 e = &dirp->name_cache[dirp->name_cache_index];
1916 TALLOC_FREE(e->name);
1917 e->name = talloc_strdup(dirp, name);
1921 /*******************************************************************
1922 Find an entry by name. Leave us at the offset after it.
1923 Don't check for veto or invisible files.
1924 ********************************************************************/
1926 bool SearchDir(struct smb_Dir *dirp, const char *name, long *poffset)
1929 const char *entry = NULL;
1930 char *talloced = NULL;
1931 connection_struct *conn = dirp->conn;
1933 /* Search back in the name cache. */
1934 if (dirp->name_cache_size && dirp->name_cache) {
1935 for (i = dirp->name_cache_index; i >= 0; i--) {
1936 struct name_cache_entry *e = &dirp->name_cache[i];
1937 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1938 *poffset = e->offset;
1939 SeekDir(dirp, e->offset);
1943 for (i = dirp->name_cache_size - 1; i > dirp->name_cache_index; i--) {
1944 struct name_cache_entry *e = &dirp->name_cache[i];
1945 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1946 *poffset = e->offset;
1947 SeekDir(dirp, e->offset);
1953 /* Not found in the name cache. Rewind directory and start from scratch. */
1954 SMB_VFS_REWINDDIR(conn, dirp->dir);
1955 dirp->file_number = 0;
1956 *poffset = START_OF_DIRECTORY_OFFSET;
1957 while ((entry = ReadDirName(dirp, poffset, NULL, &talloced))) {
1958 if (conn->case_sensitive ? (strcmp(entry, name) == 0) : strequal(entry, name)) {
1959 TALLOC_FREE(talloced);
1962 TALLOC_FREE(talloced);
1967 struct files_below_forall_state {
1970 int (*fn)(struct file_id fid, const struct share_mode_data *data,
1971 void *private_data);
1975 static int files_below_forall_fn(struct file_id fid,
1976 const struct share_mode_data *data,
1979 struct files_below_forall_state *state = private_data;
1980 char tmpbuf[PATH_MAX];
1981 char *fullpath, *to_free;
1984 len = full_path_tos(data->servicepath, data->base_name,
1985 tmpbuf, sizeof(tmpbuf),
1986 &fullpath, &to_free);
1990 if (state->dirpath_len >= len) {
1992 * Filter files above dirpath
1996 if (fullpath[state->dirpath_len] != '/') {
1998 * Filter file that don't have a path separator at the end of
2004 if (memcmp(state->dirpath, fullpath, state->dirpath_len) != 0) {
2011 TALLOC_FREE(to_free);
2012 return state->fn(fid, data, state->private_data);
2015 TALLOC_FREE(to_free);
2019 static int files_below_forall(connection_struct *conn,
2020 const struct smb_filename *dir_name,
2021 int (*fn)(struct file_id fid,
2022 const struct share_mode_data *data,
2023 void *private_data),
2026 struct files_below_forall_state state = {
2028 .private_data = private_data,
2031 char tmpbuf[PATH_MAX];
2034 state.dirpath_len = full_path_tos(conn->connectpath,
2035 dir_name->base_name,
2036 tmpbuf, sizeof(tmpbuf),
2037 &state.dirpath, &to_free);
2038 if (state.dirpath_len == -1) {
2042 ret = share_mode_forall(files_below_forall_fn, &state);
2043 TALLOC_FREE(to_free);
2047 struct have_file_open_below_state {
2051 static int have_file_open_below_fn(struct file_id fid,
2052 const struct share_mode_data *data,
2055 struct have_file_open_below_state *state = private_data;
2056 state->found_one = true;
2060 bool have_file_open_below(connection_struct *conn,
2061 const struct smb_filename *name)
2063 struct have_file_open_below_state state = {
2068 if (!VALID_STAT(name->st)) {
2071 if (!S_ISDIR(name->st.st_ex_mode)) {
2075 ret = files_below_forall(conn, name, have_file_open_below_fn, &state);
2080 return state.found_one;
2083 /*****************************************************************
2084 Is this directory empty ?
2085 *****************************************************************/
2087 NTSTATUS can_delete_directory_fsp(files_struct *fsp)
2089 NTSTATUS status = NT_STATUS_OK;
2091 const char *dname = NULL;
2092 const char *dirname = fsp->fsp_name->base_name;
2093 char *talloced = NULL;
2095 struct connection_struct *conn = fsp->conn;
2096 struct smb_Dir *dir_hnd = OpenDir(talloc_tos(),
2103 return map_nt_error_from_unix(errno);
2106 while ((dname = ReadDirName(dir_hnd, &dirpos, &st, &talloced))) {
2107 /* Quick check for "." and ".." */
2108 if (dname[0] == '.') {
2109 if (!dname[1] || (dname[1] == '.' && !dname[2])) {
2110 TALLOC_FREE(talloced);
2115 if (!is_visible_file(conn, dirname, dname, &st, True)) {
2116 TALLOC_FREE(talloced);
2120 DEBUG(10,("got name %s - can't delete\n",
2122 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
2125 TALLOC_FREE(talloced);
2126 TALLOC_FREE(dir_hnd);
2128 if (!NT_STATUS_IS_OK(status)) {
2132 if (!(fsp->posix_flags & FSP_POSIX_FLAGS_RENAME) &&
2133 lp_strict_rename(SNUM(conn)) &&
2134 have_file_open_below(fsp->conn, fsp->fsp_name))
2136 return NT_STATUS_ACCESS_DENIED;
2139 return NT_STATUS_OK;