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
;
162 const int dirhandles_open
= sconn
->searches
.dirhandles_open
;
164 for (dptr
= sconn
->searches
.dirptrs
; dptr
!= NULL
; dptr
= dptr
->next
) {
165 if(dptr
->dnum
!= key
) {
169 if (!forclose
&& (dptr
->dir_hnd
== NULL
)) {
170 if (dirhandles_open
>= MAX_OPEN_DIRECTORIES
) {
171 dptr_idleoldest(sconn
);
173 DBG_INFO("Reopening dptr key %d\n",key
);
175 dptr
->dir_hnd
= OpenDir(NULL
,
181 if (dptr
->dir_hnd
== NULL
) {
182 DBG_INFO("Failed to open %s (%s)\n",
183 dptr
->smb_dname
->base_name
,
188 DLIST_PROMOTE(sconn
->searches
.dirptrs
, dptr
);
194 /****************************************************************************
195 Get the dir path for a dir index.
196 ****************************************************************************/
198 const char *dptr_path(struct smbd_server_connection
*sconn
, int key
)
200 struct dptr_struct
*dptr
= dptr_get(sconn
, key
, false);
202 return(dptr
->smb_dname
->base_name
);
206 /****************************************************************************
207 Get the dir wcard for a dir index.
208 ****************************************************************************/
210 const char *dptr_wcard(struct smbd_server_connection
*sconn
, int key
)
212 struct dptr_struct
*dptr
= dptr_get(sconn
, key
, false);
218 /****************************************************************************
219 Get the dir attrib for a dir index.
220 ****************************************************************************/
222 uint16_t dptr_attr(struct smbd_server_connection
*sconn
, int key
)
224 struct dptr_struct
*dptr
= dptr_get(sconn
, key
, false);
230 /****************************************************************************
231 Close a dptr (internal func).
232 ****************************************************************************/
234 static void dptr_close_internal(struct dptr_struct
*dptr
)
236 struct smbd_server_connection
*sconn
= dptr
->conn
->sconn
;
238 DEBUG(4,("closing dptr key %d\n",dptr
->dnum
));
244 if (sconn
->using_smb2
) {
248 DLIST_REMOVE(sconn
->searches
.dirptrs
, dptr
);
251 * Free the dnum in the bitmap. Remember the dnum value is always
252 * biased by one with respect to the bitmap.
255 if (!bitmap_query(sconn
->searches
.dptr_bmap
, dptr
->dnum
- 1)) {
256 DEBUG(0,("dptr_close_internal : Error - closing dnum = %d and bitmap not set !\n",
260 bitmap_clear(sconn
->searches
.dptr_bmap
, dptr
->dnum
- 1);
263 TALLOC_FREE(dptr
->dir_hnd
);
267 /****************************************************************************
268 Close a dptr given a key.
269 ****************************************************************************/
271 void dptr_close(struct smbd_server_connection
*sconn
, int *key
)
273 struct dptr_struct
*dptr
;
275 if(*key
== INVALID_DPTR_KEY
)
278 /* OS/2 seems to use -1 to indicate "close all directories" */
280 struct dptr_struct
*next
;
281 for(dptr
= sconn
->searches
.dirptrs
; dptr
; dptr
= next
) {
283 dptr_close_internal(dptr
);
285 *key
= INVALID_DPTR_KEY
;
289 dptr
= dptr_get(sconn
, *key
, true);
292 DEBUG(0,("Invalid key %d given to dptr_close\n", *key
));
296 dptr_close_internal(dptr
);
298 *key
= INVALID_DPTR_KEY
;
301 /****************************************************************************
302 Close all dptrs for a cnum.
303 ****************************************************************************/
305 void dptr_closecnum(connection_struct
*conn
)
307 struct dptr_struct
*dptr
, *next
;
308 struct smbd_server_connection
*sconn
= conn
->sconn
;
314 for(dptr
= sconn
->searches
.dirptrs
; dptr
; dptr
= next
) {
316 if (dptr
->conn
== conn
) {
317 dptr_close_internal(dptr
);
322 /****************************************************************************
323 Idle all dptrs for a cnum.
324 ****************************************************************************/
326 void dptr_idlecnum(connection_struct
*conn
)
328 struct dptr_struct
*dptr
;
329 struct smbd_server_connection
*sconn
= conn
->sconn
;
335 for(dptr
= sconn
->searches
.dirptrs
; dptr
; dptr
= dptr
->next
) {
336 if (dptr
->conn
== conn
&& dptr
->dir_hnd
) {
342 /****************************************************************************
343 Close a dptr that matches a given path, only if it matches the spid also.
344 ****************************************************************************/
346 void dptr_closepath(struct smbd_server_connection
*sconn
,
347 char *path
,uint16_t spid
)
349 struct dptr_struct
*dptr
, *next
;
350 for(dptr
= sconn
->searches
.dirptrs
; dptr
; dptr
= next
) {
352 if (spid
== dptr
->spid
&&
353 strequal(dptr
->smb_dname
->base_name
,path
)) {
354 dptr_close_internal(dptr
);
359 /****************************************************************************
360 Try and close the oldest handle not marked for
361 expect close in the hope that the client has
362 finished with that one.
363 ****************************************************************************/
365 static void dptr_close_oldest(struct smbd_server_connection
*sconn
,
368 struct dptr_struct
*dptr
;
371 * Go to the end of the list.
373 for(dptr
= sconn
->searches
.dirptrs
; dptr
&& dptr
->next
; dptr
= dptr
->next
)
377 DEBUG(0,("No old dptrs available to close oldest ?\n"));
382 * If 'old' is true, close the oldest oldhandle dnum (ie. 1 < dnum < 256) that
383 * does not have expect_close set. If 'old' is false, close
384 * one of the new dnum handles.
387 for(; dptr
; dptr
= DLIST_PREV(dptr
)) {
388 if ((old
&& (dptr
->dnum
< 256) && !dptr
->expect_close
) ||
389 (!old
&& (dptr
->dnum
> 255))) {
390 dptr_close_internal(dptr
);
396 /****************************************************************************
397 Safely do an OpenDir as root, ensuring we're in the right place.
398 ****************************************************************************/
400 static struct smb_Dir
*open_dir_with_privilege(connection_struct
*conn
,
401 struct smb_request
*req
,
402 const struct smb_filename
*smb_dname
,
406 struct smb_Dir
*dir_hnd
= NULL
;
407 struct smb_filename
*smb_fname_cwd
= NULL
;
408 struct smb_filename
*saved_dir_fname
= vfs_GetWd(talloc_tos(), conn
);
409 struct privilege_paths
*priv_paths
= req
->priv_paths
;
412 if (saved_dir_fname
== NULL
) {
416 if (vfs_ChDir(conn
, smb_dname
) == -1) {
420 /* Now check the stat value is the same. */
421 smb_fname_cwd
= synthetic_smb_fname(talloc_tos(),
426 if (smb_fname_cwd
== NULL
) {
429 ret
= SMB_VFS_STAT(conn
, smb_fname_cwd
);
434 if (!check_same_stat(&smb_fname_cwd
->st
, &priv_paths
->parent_name
.st
)) {
435 DEBUG(0,("open_dir_with_privilege: stat mismatch between %s "
437 smb_dname
->base_name
,
438 smb_fname_str_dbg(&priv_paths
->parent_name
)));
442 dir_hnd
= OpenDir(NULL
, conn
, smb_fname_cwd
, wcard
, attr
);
446 vfs_ChDir(conn
, saved_dir_fname
);
447 TALLOC_FREE(saved_dir_fname
);
451 /****************************************************************************
452 Create a new dir ptr. If the flag old_handle is true then we must allocate
453 from the bitmap range 0 - 255 as old SMBsearch directory handles are only
454 one byte long. If old_handle is false we allocate from the range
455 256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
456 a directory handle is never zero.
457 wcard must not be zero.
458 ****************************************************************************/
460 NTSTATUS
dptr_create(connection_struct
*conn
,
461 struct smb_request
*req
,
463 const struct smb_filename
*smb_dname
,
470 struct dptr_struct
**dptr_ret
)
472 struct smbd_server_connection
*sconn
= conn
->sconn
;
473 struct dptr_struct
*dptr
= NULL
;
474 struct smb_Dir
*dir_hnd
;
476 if (fsp
&& fsp
->is_directory
&& fsp
->fh
->fd
!= -1) {
477 smb_dname
= fsp
->fsp_name
;
480 DEBUG(5,("dptr_create dir=%s\n", smb_dname
->base_name
));
483 DEBUG(0,("dptr_create: called with fake connection_struct\n"));
484 return NT_STATUS_INTERNAL_ERROR
;
488 return NT_STATUS_INVALID_PARAMETER
;
492 if (!(fsp
->access_mask
& SEC_DIR_LIST
)) {
493 DEBUG(5,("dptr_create: directory %s "
494 "not open for LIST access\n",
495 smb_dname
->base_name
));
496 return NT_STATUS_ACCESS_DENIED
;
498 dir_hnd
= OpenDir_fsp(NULL
, conn
, fsp
, wcard
, attr
);
501 bool backup_intent
= (req
&& req
->priv_paths
);
503 struct smb_filename
*smb_dname_cp
=
504 cp_smb_filename(talloc_tos(), smb_dname
);
506 if (smb_dname_cp
== NULL
) {
507 return NT_STATUS_NO_MEMORY
;
510 if (req
!= NULL
&& req
->posix_pathnames
) {
511 ret
= SMB_VFS_LSTAT(conn
, smb_dname_cp
);
513 ret
= SMB_VFS_STAT(conn
, smb_dname_cp
);
516 status
= map_nt_error_from_unix(errno
);
517 TALLOC_FREE(smb_dname_cp
);
520 if (!S_ISDIR(smb_dname_cp
->st
.st_ex_mode
)) {
521 TALLOC_FREE(smb_dname_cp
);
522 return NT_STATUS_NOT_A_DIRECTORY
;
524 status
= smbd_check_access_rights(conn
,
528 if (!NT_STATUS_IS_OK(status
)) {
529 TALLOC_FREE(smb_dname_cp
);
533 dir_hnd
= open_dir_with_privilege(conn
,
539 dir_hnd
= OpenDir(NULL
,
545 TALLOC_FREE(smb_dname_cp
);
549 return map_nt_error_from_unix(errno
);
552 if (sconn
->searches
.dirhandles_open
>= MAX_OPEN_DIRECTORIES
) {
553 dptr_idleoldest(sconn
);
556 dptr
= talloc_zero(NULL
, struct dptr_struct
);
558 DEBUG(0,("talloc fail in dptr_create.\n"));
559 TALLOC_FREE(dir_hnd
);
560 return NT_STATUS_NO_MEMORY
;
563 dptr
->smb_dname
= cp_smb_filename(dptr
, smb_dname
);
564 if (!dptr
->smb_dname
) {
566 TALLOC_FREE(dir_hnd
);
567 return NT_STATUS_NO_MEMORY
;
570 dptr
->dir_hnd
= dir_hnd
;
572 dptr
->expect_close
= expect_close
;
573 dptr
->wcard
= talloc_strdup(dptr
, wcard
);
576 TALLOC_FREE(dir_hnd
);
577 return NT_STATUS_NO_MEMORY
;
579 if ((req
!= NULL
&& req
->posix_pathnames
) ||
580 (wcard
[0] == '.' && wcard
[1] == 0)) {
581 dptr
->has_wild
= True
;
583 dptr
->has_wild
= wcard_has_wild
;
588 if (sconn
->using_smb2
) {
595 * This is an old-style SMBsearch request. Ensure the
596 * value we return will fit in the range 1-255.
599 dptr
->dnum
= bitmap_find(sconn
->searches
.dptr_bmap
, 0);
601 if(dptr
->dnum
== -1 || dptr
->dnum
> 254) {
604 * Try and close the oldest handle not marked for
605 * expect close in the hope that the client has
606 * finished with that one.
609 dptr_close_oldest(sconn
, true);
611 /* Now try again... */
612 dptr
->dnum
= bitmap_find(sconn
->searches
.dptr_bmap
, 0);
613 if(dptr
->dnum
== -1 || dptr
->dnum
> 254) {
614 DEBUG(0,("dptr_create: returned %d: Error - all old dirptrs in use ?\n", dptr
->dnum
));
616 TALLOC_FREE(dir_hnd
);
617 return NT_STATUS_TOO_MANY_OPENED_FILES
;
623 * This is a new-style trans2 request. Allocate from
624 * a range that will return 256 - MAX_DIRECTORY_HANDLES.
627 dptr
->dnum
= bitmap_find(sconn
->searches
.dptr_bmap
, 255);
629 if(dptr
->dnum
== -1 || dptr
->dnum
< 255) {
632 * Try and close the oldest handle close in the hope that
633 * the client has finished with that one. This will only
634 * happen in the case of the Win98 client bug where it leaks
638 dptr_close_oldest(sconn
, false);
640 /* Now try again... */
641 dptr
->dnum
= bitmap_find(sconn
->searches
.dptr_bmap
, 255);
643 if(dptr
->dnum
== -1 || dptr
->dnum
< 255) {
644 DEBUG(0,("dptr_create: returned %d: Error - all new dirptrs in use ?\n", dptr
->dnum
));
646 TALLOC_FREE(dir_hnd
);
647 return NT_STATUS_TOO_MANY_OPENED_FILES
;
652 bitmap_set(sconn
->searches
.dptr_bmap
, dptr
->dnum
);
654 dptr
->dnum
+= 1; /* Always bias the dnum by one - no zero dnums allowed. */
656 DLIST_ADD(sconn
->searches
.dirptrs
, dptr
);
659 DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
661 dptr
->smb_dname
->base_name
,
670 /****************************************************************************
671 Wrapper functions to access the lower level directory handles.
672 ****************************************************************************/
674 void dptr_CloseDir(files_struct
*fsp
)
678 * The destructor for the struct smb_Dir
679 * (fsp->dptr->dir_hnd) now handles
680 * all resource deallocation.
682 dptr_close_internal(fsp
->dptr
);
687 void dptr_SeekDir(struct dptr_struct
*dptr
, long offset
)
689 SeekDir(dptr
->dir_hnd
, offset
);
692 long dptr_TellDir(struct dptr_struct
*dptr
)
694 return TellDir(dptr
->dir_hnd
);
697 bool dptr_has_wild(struct dptr_struct
*dptr
)
699 return dptr
->has_wild
;
702 int dptr_dnum(struct dptr_struct
*dptr
)
707 bool dptr_get_priv(struct dptr_struct
*dptr
)
712 void dptr_set_priv(struct dptr_struct
*dptr
)
717 /****************************************************************************
718 Return the next visible file name, skipping veto'd and invisible files.
719 ****************************************************************************/
721 static const char *dptr_normal_ReadDirName(struct dptr_struct
*dptr
,
722 long *poffset
, SMB_STRUCT_STAT
*pst
,
725 /* Normal search for the next file. */
727 char *talloced
= NULL
;
729 while ((name
= ReadDirName(dptr
->dir_hnd
, poffset
, pst
, &talloced
))
731 if (is_visible_file(dptr
->conn
,
732 dptr
->smb_dname
->base_name
,
736 *ptalloced
= talloced
;
739 TALLOC_FREE(talloced
);
744 /****************************************************************************
745 Return the next visible file name, skipping veto'd and invisible files.
746 ****************************************************************************/
748 static char *dptr_ReadDirName(TALLOC_CTX
*ctx
,
749 struct dptr_struct
*dptr
,
751 SMB_STRUCT_STAT
*pst
)
753 struct smb_filename smb_fname_base
;
755 const char *name_temp
= NULL
;
756 char *talloced
= NULL
;
757 char *pathreal
= NULL
;
758 char *found_name
= NULL
;
761 SET_STAT_INVALID(*pst
);
763 if (dptr
->has_wild
|| dptr
->did_stat
) {
764 name_temp
= dptr_normal_ReadDirName(dptr
, poffset
, pst
,
766 if (name_temp
== NULL
) {
769 if (talloced
!= NULL
) {
770 return talloc_move(ctx
, &talloced
);
772 return talloc_strdup(ctx
, name_temp
);
775 /* If poffset is -1 then we know we returned this name before and we
776 * have no wildcards. We're at the end of the directory. */
777 if (*poffset
== END_OF_DIRECTORY_OFFSET
) {
781 /* We know the stored wcard contains no wildcard characters.
782 * See if we can match with a stat call. If we can't, then set
783 * did_stat to true to ensure we only do this once and keep
786 dptr
->did_stat
= true;
788 /* First check if it should be visible. */
789 if (!is_visible_file(dptr
->conn
,
790 dptr
->smb_dname
->base_name
,
794 /* This only returns false if the file was found, but
795 is explicitly not visible. Set us to end of
796 directory, but return NULL as we know we can't ever
801 if (VALID_STAT(*pst
)) {
802 name
= talloc_strdup(ctx
, dptr
->wcard
);
806 pathreal
= talloc_asprintf(ctx
,
808 dptr
->smb_dname
->base_name
,
813 /* Create an smb_filename with stream_name == NULL. */
814 smb_fname_base
= (struct smb_filename
) { .base_name
= pathreal
};
816 if (SMB_VFS_STAT(dptr
->conn
, &smb_fname_base
) == 0) {
817 *pst
= smb_fname_base
.st
;
818 name
= talloc_strdup(ctx
, dptr
->wcard
);
821 /* If we get any other error than ENOENT or ENOTDIR
822 then the file exists we just can't stat it. */
823 if (errno
!= ENOENT
&& errno
!= ENOTDIR
) {
824 name
= talloc_strdup(ctx
, dptr
->wcard
);
829 /* Stat failed. We know this is authoratiative if we are
830 * providing case sensitive semantics or the underlying
831 * filesystem is case sensitive.
833 if (dptr
->conn
->case_sensitive
||
834 !(dptr
->conn
->fs_capabilities
& FILE_CASE_SENSITIVE_SEARCH
))
840 * Try case-insensitive stat if the fs has the ability. This avoids
841 * scanning the whole directory.
843 ret
= SMB_VFS_GET_REAL_FILENAME(dptr
->conn
,
844 dptr
->smb_dname
->base_name
,
851 } else if (errno
== ENOENT
) {
852 /* The case-insensitive lookup was authoritative. */
856 TALLOC_FREE(pathreal
);
858 name_temp
= dptr_normal_ReadDirName(dptr
, poffset
, pst
, &talloced
);
859 if (name_temp
== NULL
) {
862 if (talloced
!= NULL
) {
863 return talloc_move(ctx
, &talloced
);
865 return talloc_strdup(ctx
, name_temp
);
868 TALLOC_FREE(pathreal
);
870 /* We need to set the underlying dir_hnd offset to -1
871 * also as this function is usually called with the
872 * output from TellDir. */
873 dptr
->dir_hnd
->offset
= *poffset
= END_OF_DIRECTORY_OFFSET
;
877 /****************************************************************************
878 Search for a file by name, skipping veto'ed and not visible files.
879 ****************************************************************************/
881 bool dptr_SearchDir(struct dptr_struct
*dptr
, const char *name
, long *poffset
, SMB_STRUCT_STAT
*pst
)
883 SET_STAT_INVALID(*pst
);
885 if (!dptr
->has_wild
&& (dptr
->dir_hnd
->offset
== END_OF_DIRECTORY_OFFSET
)) {
886 /* This is a singleton directory and we're already at the end. */
887 *poffset
= END_OF_DIRECTORY_OFFSET
;
891 return SearchDir(dptr
->dir_hnd
, name
, poffset
);
894 /****************************************************************************
895 Map a native directory offset to a 32-bit cookie.
896 ****************************************************************************/
898 static uint32_t map_dir_offset_to_wire(struct dptr_struct
*dptr
, long offset
)
903 if (offset
== END_OF_DIRECTORY_OFFSET
) {
904 return WIRE_END_OF_DIRECTORY_OFFSET
;
905 } else if(offset
== START_OF_DIRECTORY_OFFSET
) {
906 return WIRE_START_OF_DIRECTORY_OFFSET
;
907 } else if (offset
== DOT_DOT_DIRECTORY_OFFSET
) {
908 return WIRE_DOT_DOT_DIRECTORY_OFFSET
;
910 if (sizeof(long) == 4) {
911 /* 32-bit machine. We can cheat... */
912 return (uint32_t)offset
;
914 if (dptr
->dptr_cache
== NULL
) {
915 /* Lazy initialize cache. */
916 dptr
->dptr_cache
= memcache_init(dptr
, 0);
917 if (dptr
->dptr_cache
== NULL
) {
918 return WIRE_END_OF_DIRECTORY_OFFSET
;
921 /* Have we seen this offset before ? */
922 key
.data
= (void *)&offset
;
923 key
.length
= sizeof(offset
);
924 if (memcache_lookup(dptr
->dptr_cache
,
925 SMB1_SEARCH_OFFSET_MAP
,
928 uint32_t wire_offset
;
929 SMB_ASSERT(val
.length
== sizeof(wire_offset
));
930 memcpy(&wire_offset
, val
.data
, sizeof(wire_offset
));
931 DEBUG(10,("found wire %u <-> offset %ld\n",
932 (unsigned int)wire_offset
,
937 /* Allocate a new wire cookie. */
940 } while (dptr
->counter
== WIRE_START_OF_DIRECTORY_OFFSET
||
941 dptr
->counter
== WIRE_END_OF_DIRECTORY_OFFSET
||
942 dptr
->counter
== WIRE_DOT_DOT_DIRECTORY_OFFSET
);
943 /* Store it in the cache. */
944 key
.data
= (void *)&offset
;
945 key
.length
= sizeof(offset
);
946 val
.data
= (void *)&dptr
->counter
;
947 val
.length
= sizeof(dptr
->counter
); /* MUST BE uint32_t ! */
948 memcache_add(dptr
->dptr_cache
,
949 SMB1_SEARCH_OFFSET_MAP
,
952 /* And the reverse mapping for lookup from
953 map_wire_to_dir_offset(). */
954 memcache_add(dptr
->dptr_cache
,
955 SMB1_SEARCH_OFFSET_MAP
,
958 DEBUG(10,("stored wire %u <-> offset %ld\n",
959 (unsigned int)dptr
->counter
,
961 return dptr
->counter
;
964 /****************************************************************************
965 Fill the 5 byte server reserved dptr field.
966 ****************************************************************************/
968 bool dptr_fill(struct smbd_server_connection
*sconn
,
969 char *buf1
,unsigned int key
)
971 unsigned char *buf
= (unsigned char *)buf1
;
972 struct dptr_struct
*dptr
= dptr_get(sconn
, key
, false);
973 uint32_t wire_offset
;
975 DEBUG(1,("filling null dirptr %d\n",key
));
978 wire_offset
= map_dir_offset_to_wire(dptr
,TellDir(dptr
->dir_hnd
));
979 DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key
,
980 (long)dptr
->dir_hnd
,(int)wire_offset
));
982 SIVAL(buf
,1,wire_offset
);
986 /****************************************************************************
987 Map a 32-bit wire cookie to a native directory offset.
988 ****************************************************************************/
990 static long map_wire_to_dir_offset(struct dptr_struct
*dptr
, uint32_t wire_offset
)
995 if (wire_offset
== WIRE_END_OF_DIRECTORY_OFFSET
) {
996 return END_OF_DIRECTORY_OFFSET
;
997 } else if(wire_offset
== WIRE_START_OF_DIRECTORY_OFFSET
) {
998 return START_OF_DIRECTORY_OFFSET
;
999 } else if (wire_offset
== WIRE_DOT_DOT_DIRECTORY_OFFSET
) {
1000 return DOT_DOT_DIRECTORY_OFFSET
;
1002 if (sizeof(long) == 4) {
1003 /* 32-bit machine. We can cheat... */
1004 return (long)wire_offset
;
1006 if (dptr
->dptr_cache
== NULL
) {
1007 /* Logic error, cache should be initialized. */
1008 return END_OF_DIRECTORY_OFFSET
;
1010 key
.data
= (void *)&wire_offset
;
1011 key
.length
= sizeof(wire_offset
);
1012 if (memcache_lookup(dptr
->dptr_cache
,
1013 SMB1_SEARCH_OFFSET_MAP
,
1016 /* Found mapping. */
1018 SMB_ASSERT(val
.length
== sizeof(offset
));
1019 memcpy(&offset
, val
.data
, sizeof(offset
));
1020 DEBUG(10,("lookup wire %u <-> offset %ld\n",
1021 (unsigned int)wire_offset
,
1025 return END_OF_DIRECTORY_OFFSET
;
1028 /****************************************************************************
1029 Fetch the dir ptr and seek it given the 5 byte server field.
1030 ****************************************************************************/
1032 struct dptr_struct
*dptr_fetch(struct smbd_server_connection
*sconn
,
1033 char *buf
, int *num
)
1035 unsigned int key
= *(unsigned char *)buf
;
1036 struct dptr_struct
*dptr
= dptr_get(sconn
, key
, false);
1037 uint32_t wire_offset
;
1041 DEBUG(3,("fetched null dirptr %d\n",key
));
1045 wire_offset
= IVAL(buf
,1);
1046 seekoff
= map_wire_to_dir_offset(dptr
, wire_offset
);
1047 SeekDir(dptr
->dir_hnd
,seekoff
);
1048 DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
1049 key
, dptr
->smb_dname
->base_name
, (int)seekoff
));
1053 /****************************************************************************
1055 ****************************************************************************/
1057 struct dptr_struct
*dptr_fetch_lanman2(struct smbd_server_connection
*sconn
,
1060 struct dptr_struct
*dptr
= dptr_get(sconn
, dptr_num
, false);
1063 DEBUG(3,("fetched null dirptr %d\n",dptr_num
));
1066 DEBUG(3,("fetching dirptr %d for path %s\n",
1068 dptr
->smb_dname
->base_name
));
1072 static bool mangle_mask_match(connection_struct
*conn
,
1073 const char *filename
,
1078 if (!name_to_8_3(filename
,mname
,False
,conn
->params
)) {
1081 return mask_match_search(mname
,mask
,False
);
1084 bool smbd_dirptr_get_entry(TALLOC_CTX
*ctx
,
1085 struct dptr_struct
*dirptr
,
1091 bool (*match_fn
)(TALLOC_CTX
*ctx
,
1096 bool (*mode_fn
)(TALLOC_CTX
*ctx
,
1098 struct smb_filename
*smb_fname
,
1103 struct smb_filename
**_smb_fname
,
1107 connection_struct
*conn
= dirptr
->conn
;
1110 const char *dpath
= dirptr
->smb_dname
->base_name
;
1111 bool dirptr_path_is_dot
= ISDOT(dpath
);
1116 pathlen
= strlen(dpath
);
1117 slashlen
= ( dpath
[pathlen
-1] != '/') ? 1 : 0;
1122 SMB_STRUCT_STAT sbuf
= { 0 };
1126 char *pathreal
= NULL
;
1127 struct smb_filename smb_fname
;
1131 cur_offset
= dptr_TellDir(dirptr
);
1132 prev_offset
= cur_offset
;
1133 dname
= dptr_ReadDirName(ctx
, dirptr
, &cur_offset
, &sbuf
);
1135 DEBUG(6,("smbd_dirptr_get_entry: dirptr 0x%lx now at offset %ld\n",
1136 (long)dirptr
, cur_offset
));
1138 if (dname
== NULL
) {
1142 isdots
= (ISDOT(dname
) || ISDOTDOT(dname
));
1143 if (dont_descend
&& !isdots
) {
1149 * fname may get mangled, dname is never mangled.
1150 * Whenever we're accessing the filesystem we use
1151 * pathreal which is composed from dname.
1154 ok
= match_fn(ctx
, private_data
, dname
, mask
, &fname
);
1162 * pathreal = talloc_asprintf(ctx, "%s%s%s", dirptr->path,
1163 * needslash?"/":"", dname);
1164 * but this was measurably slower than doing the memcpy.
1167 pathreal
= talloc_array(
1169 pathlen
+ slashlen
+ talloc_get_size(dname
));
1177 * We don't want to pass ./xxx to modules below us so don't
1178 * add the path if it is just . by itself.
1180 if (dirptr_path_is_dot
) {
1181 memcpy(pathreal
, dname
, talloc_get_size(dname
));
1183 memcpy(pathreal
, dpath
, pathlen
);
1184 pathreal
[pathlen
] = '/';
1185 memcpy(pathreal
+ slashlen
+ pathlen
, dname
,
1186 talloc_get_size(dname
));
1189 /* Create smb_fname with NULL stream_name. */
1190 smb_fname
= (struct smb_filename
) {
1191 .base_name
= pathreal
, .st
= sbuf
1194 ok
= mode_fn(ctx
, private_data
, &smb_fname
, get_dosmode
, &mode
);
1198 TALLOC_FREE(pathreal
);
1202 if (!dir_check_ftype(mode
, dirtype
)) {
1203 DEBUG(5,("[%s] attribs 0x%x didn't match 0x%x\n",
1204 fname
, (unsigned int)mode
, (unsigned int)dirtype
));
1207 TALLOC_FREE(pathreal
);
1211 if (ask_sharemode
) {
1212 struct timespec write_time_ts
;
1213 struct file_id fileid
;
1215 fileid
= vfs_file_id_from_sbuf(conn
,
1217 get_file_infos(fileid
, 0, NULL
, &write_time_ts
);
1218 if (!null_timespec(write_time_ts
)) {
1219 update_stat_ex_mtime(&smb_fname
.st
,
1224 DEBUG(3,("smbd_dirptr_get_entry mask=[%s] found %s "
1226 mask
, smb_fname_str_dbg(&smb_fname
),
1229 if (!conn
->sconn
->using_smb2
) {
1231 * The dircache is only needed for SMB1 because SMB1
1232 * uses a name for the resume wheras SMB2 always
1233 * continues from the next position (unless it's told to
1234 * restart or close-and-reopen the listing).
1236 DirCacheAdd(dirptr
->dir_hnd
, dname
, cur_offset
);
1241 *_smb_fname
= cp_smb_filename(ctx
, &smb_fname
);
1242 TALLOC_FREE(pathreal
);
1243 if (*_smb_fname
== NULL
) {
1248 *_prev_offset
= prev_offset
;
1256 /****************************************************************************
1257 Get an 8.3 directory entry.
1258 ****************************************************************************/
1260 static bool smbd_dirptr_8_3_match_fn(TALLOC_CTX
*ctx
,
1266 connection_struct
*conn
= (connection_struct
*)private_data
;
1268 if ((strcmp(mask
,"*.*") == 0) ||
1269 mask_match_search(dname
, mask
, false) ||
1270 mangle_mask_match(conn
, dname
, mask
)) {
1274 * Ensure we can push the original name as UCS2. If
1275 * not, then just don't return this name.
1279 size_t len
= (strlen(dname
) + 2) * 4; /* Allow enough space. */
1280 uint8_t *tmp
= talloc_array(talloc_tos(),
1284 status
= srvstr_push(NULL
,
1285 FLAGS2_UNICODE_STRINGS
,
1294 if (!NT_STATUS_IS_OK(status
)) {
1298 if (!mangle_is_8_3(dname
, false, conn
->params
)) {
1299 bool ok
= name_to_8_3(dname
, mname
, false,
1309 *_fname
= talloc_strdup(ctx
, fname
);
1310 if (*_fname
== NULL
) {
1320 static bool smbd_dirptr_8_3_mode_fn(TALLOC_CTX
*ctx
,
1322 struct smb_filename
*smb_fname
,
1326 connection_struct
*conn
= (connection_struct
*)private_data
;
1328 if (!VALID_STAT(smb_fname
->st
)) {
1329 if ((SMB_VFS_STAT(conn
, smb_fname
)) != 0) {
1330 DEBUG(5,("smbd_dirptr_8_3_mode_fn: "
1331 "Couldn't stat [%s]. Error "
1333 smb_fname_str_dbg(smb_fname
),
1339 *_mode
= dos_mode(conn
, smb_fname
);
1343 bool get_dir_entry(TALLOC_CTX
*ctx
,
1344 struct dptr_struct
*dirptr
,
1350 struct timespec
*_date
,
1354 connection_struct
*conn
= dirptr
->conn
;
1356 struct smb_filename
*smb_fname
= NULL
;
1361 ok
= smbd_dirptr_get_entry(ctx
,
1368 smbd_dirptr_8_3_match_fn
,
1369 smbd_dirptr_8_3_mode_fn
,
1379 *_fname
= talloc_move(ctx
, &fname
);
1380 *_size
= smb_fname
->st
.st_ex_size
;
1382 *_date
= smb_fname
->st
.st_ex_mtime
;
1383 TALLOC_FREE(smb_fname
);
1387 /*******************************************************************
1388 Check to see if a user can read a file. This is only approximate,
1389 it is used as part of the "hide unreadable" option. Don't
1390 use it for anything security sensitive.
1391 ********************************************************************/
1393 static bool user_can_read_file(connection_struct
*conn
,
1394 struct smb_filename
*smb_fname
)
1397 uint32_t rejected_share_access
= 0;
1398 uint32_t rejected_mask
= 0;
1399 struct security_descriptor
*sd
= NULL
;
1400 uint32_t access_mask
= FILE_READ_DATA
|
1402 FILE_READ_ATTRIBUTES
|
1403 SEC_STD_READ_CONTROL
;
1406 * Never hide files from the root user.
1407 * We use (uid_t)0 here not sec_initial_uid()
1408 * as make test uses a single user context.
1411 if (get_current_uid(conn
) == (uid_t
)0) {
1416 * We can't directly use smbd_check_access_rights()
1417 * here, as this implicitly grants FILE_READ_ATTRIBUTES
1418 * which the Windows access-based-enumeration code
1419 * explicitly checks for on the file security descriptor.
1422 * https://bugzilla.samba.org/show_bug.cgi?id=10252
1424 * and the smb2.acl2.ACCESSBASED test for details.
1427 rejected_share_access
= access_mask
& ~(conn
->share_access
);
1428 if (rejected_share_access
) {
1429 DEBUG(10, ("rejected share access 0x%x "
1431 (unsigned int)access_mask
,
1432 smb_fname_str_dbg(smb_fname
),
1433 (unsigned int)rejected_share_access
));
1437 status
= SMB_VFS_GET_NT_ACL(conn
,
1445 if (!NT_STATUS_IS_OK(status
)) {
1446 DEBUG(10, ("Could not get acl "
1448 smb_fname_str_dbg(smb_fname
),
1449 nt_errstr(status
)));
1453 status
= se_file_access_check(sd
,
1454 get_current_nttok(conn
),
1461 if (NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)) {
1462 DEBUG(10,("rejected bits 0x%x read access for %s\n",
1463 (unsigned int)rejected_mask
,
1464 smb_fname_str_dbg(smb_fname
) ));
1470 /*******************************************************************
1471 Check to see if a user can write a file (and only files, we do not
1472 check dirs on this one). This is only approximate,
1473 it is used as part of the "hide unwriteable" option. Don't
1474 use it for anything security sensitive.
1475 ********************************************************************/
1477 static bool user_can_write_file(connection_struct
*conn
,
1478 const struct smb_filename
*smb_fname
)
1481 * Never hide files from the root user.
1482 * We use (uid_t)0 here not sec_initial_uid()
1483 * as make test uses a single user context.
1486 if (get_current_uid(conn
) == (uid_t
)0) {
1490 SMB_ASSERT(VALID_STAT(smb_fname
->st
));
1492 /* Pseudo-open the file */
1494 if(S_ISDIR(smb_fname
->st
.st_ex_mode
)) {
1498 return can_write_to_file(conn
, smb_fname
);
1501 /*******************************************************************
1502 Is a file a "special" type ?
1503 ********************************************************************/
1505 static bool file_is_special(connection_struct
*conn
,
1506 const struct smb_filename
*smb_fname
)
1509 * Never hide files from the root user.
1510 * We use (uid_t)0 here not sec_initial_uid()
1511 * as make test uses a single user context.
1514 if (get_current_uid(conn
) == (uid_t
)0) {
1518 SMB_ASSERT(VALID_STAT(smb_fname
->st
));
1520 if (S_ISREG(smb_fname
->st
.st_ex_mode
) ||
1521 S_ISDIR(smb_fname
->st
.st_ex_mode
) ||
1522 S_ISLNK(smb_fname
->st
.st_ex_mode
))
1528 /*******************************************************************
1529 Should the file be seen by the client?
1530 NOTE: A successful return is no guarantee of the file's existence.
1531 ********************************************************************/
1533 bool is_visible_file(connection_struct
*conn
, const char *dir_path
,
1534 const char *name
, SMB_STRUCT_STAT
*pst
, bool use_veto
)
1536 bool hide_unreadable
= lp_hide_unreadable(SNUM(conn
));
1537 bool hide_unwriteable
= lp_hide_unwriteable_files(SNUM(conn
));
1538 bool hide_special
= lp_hide_special_files(SNUM(conn
));
1539 int hide_new_files_timeout
= lp_hide_new_files_timeout(SNUM(conn
));
1541 struct smb_filename
*smb_fname_base
= NULL
;
1544 if ((strcmp(".",name
) == 0) || (strcmp("..",name
) == 0)) {
1545 return True
; /* . and .. are always visible. */
1548 /* If it's a vetoed file, pretend it doesn't even exist */
1549 if (use_veto
&& IS_VETO_PATH(conn
, name
)) {
1550 DEBUG(10,("is_visible_file: file %s is vetoed.\n", name
));
1554 if (hide_unreadable
||
1557 (hide_new_files_timeout
!= 0))
1559 entry
= talloc_asprintf(talloc_tos(), "%s/%s", dir_path
, name
);
1565 /* Create an smb_filename with stream_name == NULL. */
1566 smb_fname_base
= synthetic_smb_fname(talloc_tos(),
1571 if (smb_fname_base
== NULL
) {
1576 /* If the file name does not exist, there's no point checking
1577 * the configuration options. We succeed, on the basis that the
1578 * checks *might* have passed if the file was present.
1580 if (!VALID_STAT(*pst
)) {
1581 if (SMB_VFS_STAT(conn
, smb_fname_base
) != 0) {
1585 *pst
= smb_fname_base
->st
;
1588 /* Honour _hide unreadable_ option */
1589 if (hide_unreadable
&&
1590 !user_can_read_file(conn
, smb_fname_base
)) {
1591 DEBUG(10,("is_visible_file: file %s is unreadable.\n",
1596 /* Honour _hide unwriteable_ option */
1597 if (hide_unwriteable
&& !user_can_write_file(conn
,
1599 DEBUG(10,("is_visible_file: file %s is unwritable.\n",
1604 /* Honour _hide_special_ option */
1605 if (hide_special
&& file_is_special(conn
, smb_fname_base
)) {
1606 DEBUG(10,("is_visible_file: file %s is special.\n",
1612 if (hide_new_files_timeout
!= 0) {
1614 double age
= timespec_elapsed(
1615 &smb_fname_base
->st
.st_ex_mtime
);
1617 if (age
< (double)hide_new_files_timeout
) {
1626 TALLOC_FREE(smb_fname_base
);
1631 static int smb_Dir_destructor(struct smb_Dir
*dirp
)
1633 if (dirp
->dir
!= NULL
) {
1634 SMB_VFS_CLOSEDIR(dirp
->conn
,dirp
->dir
);
1635 if (dirp
->fsp
!= NULL
) {
1637 * The SMB_VFS_CLOSEDIR above
1638 * closes the underlying fd inside
1641 dirp
->fsp
->fh
->fd
= -1;
1642 if (dirp
->fsp
->dptr
!= NULL
) {
1643 SMB_ASSERT(dirp
->fsp
->dptr
->dir_hnd
== dirp
);
1644 dirp
->fsp
->dptr
->dir_hnd
= NULL
;
1649 if (dirp
->conn
->sconn
&& !dirp
->conn
->sconn
->using_smb2
) {
1650 dirp
->conn
->sconn
->searches
.dirhandles_open
--;
1655 /*******************************************************************
1657 ********************************************************************/
1659 static struct smb_Dir
*OpenDir_internal(TALLOC_CTX
*mem_ctx
,
1660 connection_struct
*conn
,
1661 const struct smb_filename
*smb_dname
,
1665 struct smb_Dir
*dirp
= talloc_zero(mem_ctx
, struct smb_Dir
);
1666 struct smbd_server_connection
*sconn
= conn
->sconn
;
1672 dirp
->dir
= SMB_VFS_OPENDIR(conn
, smb_dname
, mask
, attr
);
1675 DEBUG(5,("OpenDir: Can't open %s. %s\n",
1676 smb_dname
->base_name
,
1683 if (!conn
->sconn
->using_smb2
) {
1685 * The dircache is only needed for SMB1 because SMB1 uses a name
1686 * for the resume wheras SMB2 always continues from the next
1687 * position (unless it's told to restart or close-and-reopen the
1690 dirp
->name_cache_size
= lp_directory_name_cache_size(SNUM(conn
));
1693 if (sconn
&& !sconn
->using_smb2
) {
1694 sconn
->searches
.dirhandles_open
++;
1696 talloc_set_destructor(dirp
, smb_Dir_destructor
);
1705 /****************************************************************************
1706 Open a directory handle by pathname, ensuring it's under the share path.
1707 ****************************************************************************/
1709 static struct smb_Dir
*open_dir_safely(TALLOC_CTX
*ctx
,
1710 connection_struct
*conn
,
1711 const struct smb_filename
*smb_dname
,
1715 struct smb_Dir
*dir_hnd
= NULL
;
1716 struct smb_filename
*smb_fname_cwd
= NULL
;
1717 struct smb_filename
*saved_dir_fname
= vfs_GetWd(ctx
, conn
);
1720 if (saved_dir_fname
== NULL
) {
1724 if (vfs_ChDir(conn
, smb_dname
) == -1) {
1728 smb_fname_cwd
= synthetic_smb_fname(talloc_tos(),
1733 if (smb_fname_cwd
== NULL
) {
1738 * Now the directory is pinned, use
1739 * REALPATH to ensure we can access it.
1741 status
= check_name(conn
, smb_fname_cwd
);
1742 if (!NT_STATUS_IS_OK(status
)) {
1746 dir_hnd
= OpenDir_internal(ctx
,
1752 if (dir_hnd
== NULL
) {
1757 * OpenDir_internal only gets "." as the dir name.
1758 * Store the real dir name here.
1761 dir_hnd
->dir_smb_fname
= cp_smb_filename(dir_hnd
, smb_dname
);
1762 if (!dir_hnd
->dir_smb_fname
) {
1763 TALLOC_FREE(dir_hnd
);
1769 vfs_ChDir(conn
, saved_dir_fname
);
1770 TALLOC_FREE(saved_dir_fname
);
1774 struct smb_Dir
*OpenDir(TALLOC_CTX
*mem_ctx
, connection_struct
*conn
,
1775 const struct smb_filename
*smb_dname
,
1779 return open_dir_safely(mem_ctx
,
1786 /*******************************************************************
1787 Open a directory from an fsp.
1788 ********************************************************************/
1790 static struct smb_Dir
*OpenDir_fsp(TALLOC_CTX
*mem_ctx
, connection_struct
*conn
,
1795 struct smb_Dir
*dirp
= talloc_zero(mem_ctx
, struct smb_Dir
);
1796 struct smbd_server_connection
*sconn
= conn
->sconn
;
1802 if (!fsp
->is_directory
) {
1807 if (fsp
->fh
->fd
== -1) {
1814 if (!conn
->sconn
->using_smb2
) {
1816 * The dircache is only needed for SMB1 because SMB1 uses a name
1817 * for the resume wheras SMB2 always continues from the next
1818 * position (unless it's told to restart or close-and-reopen the
1821 dirp
->name_cache_size
= lp_directory_name_cache_size(SNUM(conn
));
1824 dirp
->dir_smb_fname
= cp_smb_filename(dirp
, fsp
->fsp_name
);
1825 if (!dirp
->dir_smb_fname
) {
1830 dirp
->dir
= SMB_VFS_FDOPENDIR(fsp
, mask
, attr
);
1831 if (dirp
->dir
!= NULL
) {
1834 DEBUG(10,("OpenDir_fsp: SMB_VFS_FDOPENDIR on %s returned "
1836 dirp
->dir_smb_fname
->base_name
,
1838 if (errno
!= ENOSYS
) {
1843 if (dirp
->dir
== NULL
) {
1844 /* FDOPENDIR is not supported. Use OPENDIR instead. */
1846 return open_dir_safely(mem_ctx
,
1853 if (sconn
&& !sconn
->using_smb2
) {
1854 sconn
->searches
.dirhandles_open
++;
1856 talloc_set_destructor(dirp
, smb_Dir_destructor
);
1866 /*******************************************************************
1867 Read from a directory.
1868 Return directory entry, current offset, and optional stat information.
1869 Don't check for veto or invisible files.
1870 ********************************************************************/
1872 const char *ReadDirName(struct smb_Dir
*dirp
, long *poffset
,
1873 SMB_STRUCT_STAT
*sbuf
, char **ptalloced
)
1876 char *talloced
= NULL
;
1877 connection_struct
*conn
= dirp
->conn
;
1879 /* Cheat to allow . and .. to be the first entries returned. */
1880 if (((*poffset
== START_OF_DIRECTORY_OFFSET
) ||
1881 (*poffset
== DOT_DOT_DIRECTORY_OFFSET
)) && (dirp
->file_number
< 2))
1883 if (dirp
->file_number
== 0) {
1885 *poffset
= dirp
->offset
= START_OF_DIRECTORY_OFFSET
;
1888 *poffset
= dirp
->offset
= DOT_DOT_DIRECTORY_OFFSET
;
1890 dirp
->file_number
++;
1895 if (*poffset
== END_OF_DIRECTORY_OFFSET
) {
1896 *poffset
= dirp
->offset
= END_OF_DIRECTORY_OFFSET
;
1900 /* A real offset, seek to it. */
1901 SeekDir(dirp
, *poffset
);
1903 while ((n
= vfs_readdirname(conn
, dirp
->dir
, sbuf
, &talloced
))) {
1904 /* Ignore . and .. - we've already returned them. */
1906 if ((n
[1] == '\0') || (n
[1] == '.' && n
[2] == '\0')) {
1907 TALLOC_FREE(talloced
);
1911 *poffset
= dirp
->offset
= SMB_VFS_TELLDIR(conn
, dirp
->dir
);
1912 *ptalloced
= talloced
;
1913 dirp
->file_number
++;
1916 *poffset
= dirp
->offset
= END_OF_DIRECTORY_OFFSET
;
1921 /*******************************************************************
1922 Rewind to the start.
1923 ********************************************************************/
1925 void RewindDir(struct smb_Dir
*dirp
, long *poffset
)
1927 SMB_VFS_REWINDDIR(dirp
->conn
, dirp
->dir
);
1928 dirp
->file_number
= 0;
1929 dirp
->offset
= START_OF_DIRECTORY_OFFSET
;
1930 *poffset
= START_OF_DIRECTORY_OFFSET
;
1933 /*******************************************************************
1935 ********************************************************************/
1937 void SeekDir(struct smb_Dir
*dirp
, long offset
)
1939 if (offset
!= dirp
->offset
) {
1940 if (offset
== START_OF_DIRECTORY_OFFSET
) {
1941 RewindDir(dirp
, &offset
);
1943 * Ok we should really set the file number here
1944 * to 1 to enable ".." to be returned next. Trouble
1945 * is I'm worried about callers using SeekDir(dirp,0)
1946 * as equivalent to RewindDir(). So leave this alone
1949 } else if (offset
== DOT_DOT_DIRECTORY_OFFSET
) {
1950 RewindDir(dirp
, &offset
);
1952 * Set the file number to 2 - we want to get the first
1953 * real file entry (the one we return after "..")
1954 * on the next ReadDir.
1956 dirp
->file_number
= 2;
1957 } else if (offset
== END_OF_DIRECTORY_OFFSET
) {
1958 ; /* Don't seek in this case. */
1960 SMB_VFS_SEEKDIR(dirp
->conn
, dirp
->dir
, offset
);
1962 dirp
->offset
= offset
;
1966 /*******************************************************************
1967 Tell a dir position.
1968 ********************************************************************/
1970 long TellDir(struct smb_Dir
*dirp
)
1972 return(dirp
->offset
);
1975 /*******************************************************************
1976 Add an entry into the dcache.
1977 ********************************************************************/
1979 static void DirCacheAdd(struct smb_Dir
*dirp
, const char *name
, long offset
)
1981 struct name_cache_entry
*e
;
1983 if (dirp
->name_cache_size
== 0) {
1987 if (dirp
->name_cache
== NULL
) {
1988 dirp
->name_cache
= talloc_zero_array(
1989 dirp
, struct name_cache_entry
, dirp
->name_cache_size
);
1991 if (dirp
->name_cache
== NULL
) {
1996 dirp
->name_cache_index
= (dirp
->name_cache_index
+1) %
1997 dirp
->name_cache_size
;
1998 e
= &dirp
->name_cache
[dirp
->name_cache_index
];
1999 TALLOC_FREE(e
->name
);
2000 e
->name
= talloc_strdup(dirp
, name
);
2004 /*******************************************************************
2005 Find an entry by name. Leave us at the offset after it.
2006 Don't check for veto or invisible files.
2007 ********************************************************************/
2009 bool SearchDir(struct smb_Dir
*dirp
, const char *name
, long *poffset
)
2012 const char *entry
= NULL
;
2013 char *talloced
= NULL
;
2014 connection_struct
*conn
= dirp
->conn
;
2016 /* Search back in the name cache. */
2017 if (dirp
->name_cache_size
&& dirp
->name_cache
) {
2018 for (i
= dirp
->name_cache_index
; i
>= 0; i
--) {
2019 struct name_cache_entry
*e
= &dirp
->name_cache
[i
];
2020 if (e
->name
&& (conn
->case_sensitive
? (strcmp(e
->name
, name
) == 0) : strequal(e
->name
, name
))) {
2021 *poffset
= e
->offset
;
2022 SeekDir(dirp
, e
->offset
);
2026 for (i
= dirp
->name_cache_size
- 1; i
> dirp
->name_cache_index
; i
--) {
2027 struct name_cache_entry
*e
= &dirp
->name_cache
[i
];
2028 if (e
->name
&& (conn
->case_sensitive
? (strcmp(e
->name
, name
) == 0) : strequal(e
->name
, name
))) {
2029 *poffset
= e
->offset
;
2030 SeekDir(dirp
, e
->offset
);
2036 /* Not found in the name cache. Rewind directory and start from scratch. */
2037 SMB_VFS_REWINDDIR(conn
, dirp
->dir
);
2038 dirp
->file_number
= 0;
2039 *poffset
= START_OF_DIRECTORY_OFFSET
;
2040 while ((entry
= ReadDirName(dirp
, poffset
, NULL
, &talloced
))) {
2041 if (conn
->case_sensitive
? (strcmp(entry
, name
) == 0) : strequal(entry
, name
)) {
2042 TALLOC_FREE(talloced
);
2045 TALLOC_FREE(talloced
);
2050 struct files_below_forall_state
{
2053 int (*fn
)(struct file_id fid
, const struct share_mode_data
*data
,
2054 void *private_data
);
2058 static int files_below_forall_fn(struct file_id fid
,
2059 const struct share_mode_data
*data
,
2062 struct files_below_forall_state
*state
= private_data
;
2063 char tmpbuf
[PATH_MAX
];
2064 char *fullpath
, *to_free
;
2067 len
= full_path_tos(data
->servicepath
, data
->base_name
,
2068 tmpbuf
, sizeof(tmpbuf
),
2069 &fullpath
, &to_free
);
2073 if (state
->dirpath_len
>= len
) {
2075 * Filter files above dirpath
2079 if (fullpath
[state
->dirpath_len
] != '/') {
2081 * Filter file that don't have a path separator at the end of
2087 if (memcmp(state
->dirpath
, fullpath
, state
->dirpath_len
) != 0) {
2094 TALLOC_FREE(to_free
);
2095 return state
->fn(fid
, data
, state
->private_data
);
2098 TALLOC_FREE(to_free
);
2102 static int files_below_forall(connection_struct
*conn
,
2103 const struct smb_filename
*dir_name
,
2104 int (*fn
)(struct file_id fid
,
2105 const struct share_mode_data
*data
,
2106 void *private_data
),
2109 struct files_below_forall_state state
= {
2111 .private_data
= private_data
,
2114 char tmpbuf
[PATH_MAX
];
2117 state
.dirpath_len
= full_path_tos(conn
->connectpath
,
2118 dir_name
->base_name
,
2119 tmpbuf
, sizeof(tmpbuf
),
2120 &state
.dirpath
, &to_free
);
2121 if (state
.dirpath_len
== -1) {
2125 ret
= share_mode_forall(files_below_forall_fn
, &state
);
2126 TALLOC_FREE(to_free
);
2130 struct have_file_open_below_state
{
2134 static int have_file_open_below_fn(struct file_id fid
,
2135 const struct share_mode_data
*data
,
2138 struct have_file_open_below_state
*state
= private_data
;
2139 state
->found_one
= true;
2143 bool have_file_open_below(connection_struct
*conn
,
2144 const struct smb_filename
*name
)
2146 struct have_file_open_below_state state
= {
2151 if (!VALID_STAT(name
->st
)) {
2154 if (!S_ISDIR(name
->st
.st_ex_mode
)) {
2158 ret
= files_below_forall(conn
, name
, have_file_open_below_fn
, &state
);
2163 return state
.found_one
;
2166 /*****************************************************************
2167 Is this directory empty ?
2168 *****************************************************************/
2170 NTSTATUS
can_delete_directory_fsp(files_struct
*fsp
)
2172 NTSTATUS status
= NT_STATUS_OK
;
2174 const char *dname
= NULL
;
2175 const char *dirname
= fsp
->fsp_name
->base_name
;
2176 char *talloced
= NULL
;
2178 struct connection_struct
*conn
= fsp
->conn
;
2179 struct smb_Dir
*dir_hnd
= OpenDir(talloc_tos(),
2186 return map_nt_error_from_unix(errno
);
2189 while ((dname
= ReadDirName(dir_hnd
, &dirpos
, &st
, &talloced
))) {
2190 /* Quick check for "." and ".." */
2191 if (dname
[0] == '.') {
2192 if (!dname
[1] || (dname
[1] == '.' && !dname
[2])) {
2193 TALLOC_FREE(talloced
);
2198 if (!is_visible_file(conn
, dirname
, dname
, &st
, True
)) {
2199 TALLOC_FREE(talloced
);
2203 DEBUG(10,("got name %s - can't delete\n",
2205 status
= NT_STATUS_DIRECTORY_NOT_EMPTY
;
2208 TALLOC_FREE(talloced
);
2209 TALLOC_FREE(dir_hnd
);
2211 if (!NT_STATUS_IS_OK(status
)) {
2215 if (!(fsp
->posix_flags
& FSP_POSIX_FLAGS_RENAME
) &&
2216 lp_strict_rename(SNUM(conn
)) &&
2217 have_file_open_below(fsp
->conn
, fsp
->fsp_name
))
2219 return NT_STATUS_ACCESS_DENIED
;
2222 return NT_STATUS_OK
;