2 Unix SMB/CIFS implementation.
3 Directory handling routines
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Jeremy Allison 2007
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "system/filesys.h"
23 #include "smbd/smbd.h"
24 #include "smbd/globals.h"
25 #include "libcli/security/security.h"
26 #include "lib/util/bitmap.h"
27 #include "../lib/util/memcache.h"
28 #include "../librpc/gen_ndr/open_files.h"
31 This module implements directory related functions for Samba.
34 /* "Special" directory offsets. */
35 #define END_OF_DIRECTORY_OFFSET ((long)-1)
36 #define START_OF_DIRECTORY_OFFSET ((long)0)
37 #define DOT_DOT_DIRECTORY_OFFSET ((long)0x80000000)
39 /* "Special" directory offsets in 32-bit wire format. */
40 #define WIRE_END_OF_DIRECTORY_OFFSET ((uint32_t)0xFFFFFFFF)
41 #define WIRE_START_OF_DIRECTORY_OFFSET ((uint32_t)0)
42 #define WIRE_DOT_DOT_DIRECTORY_OFFSET ((uint32_t)0x80000000)
44 /* Make directory handle internals available. */
46 struct name_cache_entry
{
52 connection_struct
*conn
;
55 struct smb_filename
*dir_smb_fname
;
56 size_t name_cache_size
;
57 struct name_cache_entry
*name_cache
;
58 unsigned int name_cache_index
;
59 unsigned int file_number
;
60 files_struct
*fsp
; /* Back pointer to containing fsp, only
61 set from OpenDir_fsp(). */
65 struct dptr_struct
*next
, *prev
;
68 struct connection_struct
*conn
;
69 struct smb_Dir
*dir_hnd
;
73 struct smb_filename
*smb_dname
;
74 bool has_wild
; /* Set to true if the wcard entry has MS wildcard characters in it. */
75 bool did_stat
; /* Optimisation for non-wcard searches. */
76 bool priv
; /* Directory handle opened with privilege. */
78 struct memcache
*dptr_cache
;
81 static struct smb_Dir
*OpenDir_fsp(TALLOC_CTX
*mem_ctx
, connection_struct
*conn
,
86 static void DirCacheAdd(struct smb_Dir
*dirp
, const char *name
, long offset
);
88 #define INVALID_DPTR_KEY (-3)
90 /****************************************************************************
91 Initialise the dir bitmap.
92 ****************************************************************************/
94 bool init_dptrs(struct smbd_server_connection
*sconn
)
96 if (sconn
->searches
.dptr_bmap
) {
100 sconn
->searches
.dptr_bmap
= bitmap_talloc(
101 sconn
, MAX_DIRECTORY_HANDLES
);
103 if (sconn
->searches
.dptr_bmap
== NULL
) {
110 /****************************************************************************
111 Idle a dptr - the directory is closed but the control info is kept.
112 ****************************************************************************/
114 static void dptr_idle(struct dptr_struct
*dptr
)
117 DEBUG(4,("Idling dptr dnum %d\n",dptr
->dnum
));
118 TALLOC_FREE(dptr
->dir_hnd
);
119 TALLOC_FREE(dptr
->dptr_cache
);
124 /****************************************************************************
125 Idle the oldest dptr.
126 ****************************************************************************/
128 static void dptr_idleoldest(struct smbd_server_connection
*sconn
)
130 struct dptr_struct
*dptr
;
133 * Go to the end of the list.
135 dptr
= DLIST_TAIL(sconn
->searches
.dirptrs
);
138 DEBUG(0,("No dptrs available to idle ?\n"));
143 * Idle the oldest pointer.
146 for(; dptr
; dptr
= DLIST_PREV(dptr
)) {
154 /****************************************************************************
155 Get the struct dptr_struct for a dir index.
156 ****************************************************************************/
158 static struct dptr_struct
*dptr_get(struct smbd_server_connection
*sconn
,
159 int key
, bool forclose
)
161 struct dptr_struct
*dptr
;
163 for(dptr
= sconn
->searches
.dirptrs
; dptr
; dptr
= dptr
->next
) {
164 if(dptr
->dnum
== key
) {
165 if (!forclose
&& !dptr
->dir_hnd
) {
166 if (sconn
->searches
.dirhandles_open
>= MAX_OPEN_DIRECTORIES
)
167 dptr_idleoldest(sconn
);
168 DEBUG(4,("dptr_get: Reopening dptr key %d\n",key
));
170 if (!(dptr
->dir_hnd
= OpenDir(NULL
,
175 DEBUG(4,("dptr_get: Failed to "
177 dptr
->smb_dname
->base_name
,
182 DLIST_PROMOTE(sconn
->searches
.dirptrs
,dptr
);
189 /****************************************************************************
190 Get the dir path for a dir index.
191 ****************************************************************************/
193 const char *dptr_path(struct smbd_server_connection
*sconn
, int key
)
195 struct dptr_struct
*dptr
= dptr_get(sconn
, key
, false);
197 return(dptr
->smb_dname
->base_name
);
201 /****************************************************************************
202 Get the dir wcard for a dir index.
203 ****************************************************************************/
205 const char *dptr_wcard(struct smbd_server_connection
*sconn
, int key
)
207 struct dptr_struct
*dptr
= dptr_get(sconn
, key
, false);
213 /****************************************************************************
214 Get the dir attrib for a dir index.
215 ****************************************************************************/
217 uint16_t dptr_attr(struct smbd_server_connection
*sconn
, int key
)
219 struct dptr_struct
*dptr
= dptr_get(sconn
, key
, false);
225 /****************************************************************************
226 Close a dptr (internal func).
227 ****************************************************************************/
229 static void dptr_close_internal(struct dptr_struct
*dptr
)
231 struct smbd_server_connection
*sconn
= dptr
->conn
->sconn
;
233 DEBUG(4,("closing dptr key %d\n",dptr
->dnum
));
239 if (sconn
->using_smb2
) {
243 DLIST_REMOVE(sconn
->searches
.dirptrs
, dptr
);
246 * Free the dnum in the bitmap. Remember the dnum value is always
247 * biased by one with respect to the bitmap.
250 if (!bitmap_query(sconn
->searches
.dptr_bmap
, dptr
->dnum
- 1)) {
251 DEBUG(0,("dptr_close_internal : Error - closing dnum = %d and bitmap not set !\n",
255 bitmap_clear(sconn
->searches
.dptr_bmap
, dptr
->dnum
- 1);
258 TALLOC_FREE(dptr
->dir_hnd
);
262 /****************************************************************************
263 Close a dptr given a key.
264 ****************************************************************************/
266 void dptr_close(struct smbd_server_connection
*sconn
, int *key
)
268 struct dptr_struct
*dptr
;
270 if(*key
== INVALID_DPTR_KEY
)
273 /* OS/2 seems to use -1 to indicate "close all directories" */
275 struct dptr_struct
*next
;
276 for(dptr
= sconn
->searches
.dirptrs
; dptr
; dptr
= next
) {
278 dptr_close_internal(dptr
);
280 *key
= INVALID_DPTR_KEY
;
284 dptr
= dptr_get(sconn
, *key
, true);
287 DEBUG(0,("Invalid key %d given to dptr_close\n", *key
));
291 dptr_close_internal(dptr
);
293 *key
= INVALID_DPTR_KEY
;
296 /****************************************************************************
297 Close all dptrs for a cnum.
298 ****************************************************************************/
300 void dptr_closecnum(connection_struct
*conn
)
302 struct dptr_struct
*dptr
, *next
;
303 struct smbd_server_connection
*sconn
= conn
->sconn
;
309 for(dptr
= sconn
->searches
.dirptrs
; dptr
; dptr
= next
) {
311 if (dptr
->conn
== conn
) {
312 dptr_close_internal(dptr
);
317 /****************************************************************************
318 Idle all dptrs for a cnum.
319 ****************************************************************************/
321 void dptr_idlecnum(connection_struct
*conn
)
323 struct dptr_struct
*dptr
;
324 struct smbd_server_connection
*sconn
= conn
->sconn
;
330 for(dptr
= sconn
->searches
.dirptrs
; dptr
; dptr
= dptr
->next
) {
331 if (dptr
->conn
== conn
&& dptr
->dir_hnd
) {
337 /****************************************************************************
338 Close a dptr that matches a given path, only if it matches the spid also.
339 ****************************************************************************/
341 void dptr_closepath(struct smbd_server_connection
*sconn
,
342 char *path
,uint16_t spid
)
344 struct dptr_struct
*dptr
, *next
;
345 for(dptr
= sconn
->searches
.dirptrs
; dptr
; dptr
= next
) {
347 if (spid
== dptr
->spid
&&
348 strequal(dptr
->smb_dname
->base_name
,path
)) {
349 dptr_close_internal(dptr
);
354 /****************************************************************************
355 Try and close the oldest handle not marked for
356 expect close in the hope that the client has
357 finished with that one.
358 ****************************************************************************/
360 static void dptr_close_oldest(struct smbd_server_connection
*sconn
,
363 struct dptr_struct
*dptr
;
366 * Go to the end of the list.
368 for(dptr
= sconn
->searches
.dirptrs
; dptr
&& dptr
->next
; dptr
= dptr
->next
)
372 DEBUG(0,("No old dptrs available to close oldest ?\n"));
377 * If 'old' is true, close the oldest oldhandle dnum (ie. 1 < dnum < 256) that
378 * does not have expect_close set. If 'old' is false, close
379 * one of the new dnum handles.
382 for(; dptr
; dptr
= DLIST_PREV(dptr
)) {
383 if ((old
&& (dptr
->dnum
< 256) && !dptr
->expect_close
) ||
384 (!old
&& (dptr
->dnum
> 255))) {
385 dptr_close_internal(dptr
);
391 /****************************************************************************
392 Safely do an OpenDir as root, ensuring we're in the right place.
393 ****************************************************************************/
395 static struct smb_Dir
*open_dir_with_privilege(connection_struct
*conn
,
396 struct smb_request
*req
,
397 const struct smb_filename
*smb_dname
,
401 struct smb_Dir
*dir_hnd
= NULL
;
402 struct smb_filename
*smb_fname_cwd
;
403 char *saved_dir
= vfs_GetWd(talloc_tos(), conn
);
404 struct privilege_paths
*priv_paths
= req
->priv_paths
;
407 if (saved_dir
== NULL
) {
411 if (vfs_ChDir(conn
, smb_dname
->base_name
) == -1) {
415 /* Now check the stat value is the same. */
416 smb_fname_cwd
= synthetic_smb_fname(talloc_tos(),
421 if (smb_fname_cwd
== NULL
) {
424 ret
= SMB_VFS_STAT(conn
, smb_fname_cwd
);
429 if (!check_same_stat(&smb_fname_cwd
->st
, &priv_paths
->parent_name
.st
)) {
430 DEBUG(0,("open_dir_with_privilege: stat mismatch between %s "
432 smb_dname
->base_name
,
433 smb_fname_str_dbg(&priv_paths
->parent_name
)));
437 dir_hnd
= OpenDir(NULL
, conn
, smb_fname_cwd
, wcard
, attr
);
441 vfs_ChDir(conn
, saved_dir
);
445 /****************************************************************************
446 Create a new dir ptr. If the flag old_handle is true then we must allocate
447 from the bitmap range 0 - 255 as old SMBsearch directory handles are only
448 one byte long. If old_handle is false we allocate from the range
449 256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
450 a directory handle is never zero.
451 wcard must not be zero.
452 ****************************************************************************/
454 NTSTATUS
dptr_create(connection_struct
*conn
,
455 struct smb_request
*req
,
457 const struct smb_filename
*smb_dname
,
464 struct dptr_struct
**dptr_ret
)
466 struct smbd_server_connection
*sconn
= conn
->sconn
;
467 struct dptr_struct
*dptr
= NULL
;
468 struct smb_Dir
*dir_hnd
;
470 if (fsp
&& fsp
->is_directory
&& fsp
->fh
->fd
!= -1) {
471 smb_dname
= fsp
->fsp_name
;
474 DEBUG(5,("dptr_create dir=%s\n", smb_dname
->base_name
));
477 DEBUG(0,("dptr_create: called with fake connection_struct\n"));
478 return NT_STATUS_INTERNAL_ERROR
;
482 return NT_STATUS_INVALID_PARAMETER
;
486 if (!(fsp
->access_mask
& SEC_DIR_LIST
)) {
487 DEBUG(5,("dptr_create: directory %s "
488 "not open for LIST access\n",
489 smb_dname
->base_name
));
490 return NT_STATUS_ACCESS_DENIED
;
492 dir_hnd
= OpenDir_fsp(NULL
, conn
, fsp
, wcard
, attr
);
495 bool backup_intent
= (req
&& req
->priv_paths
);
497 struct smb_filename
*smb_dname_cp
=
498 cp_smb_filename(talloc_tos(), smb_dname
);
500 if (smb_dname_cp
== NULL
) {
501 return NT_STATUS_NO_MEMORY
;
504 if (req
!= NULL
&& req
->posix_pathnames
) {
505 ret
= SMB_VFS_LSTAT(conn
, smb_dname_cp
);
507 ret
= SMB_VFS_STAT(conn
, smb_dname_cp
);
510 status
= map_nt_error_from_unix(errno
);
511 TALLOC_FREE(smb_dname_cp
);
514 if (!S_ISDIR(smb_dname_cp
->st
.st_ex_mode
)) {
515 TALLOC_FREE(smb_dname_cp
);
516 return NT_STATUS_NOT_A_DIRECTORY
;
518 status
= smbd_check_access_rights(conn
,
522 if (!NT_STATUS_IS_OK(status
)) {
523 TALLOC_FREE(smb_dname_cp
);
527 dir_hnd
= open_dir_with_privilege(conn
,
533 dir_hnd
= OpenDir(NULL
,
539 TALLOC_FREE(smb_dname_cp
);
543 return map_nt_error_from_unix(errno
);
546 if (sconn
->searches
.dirhandles_open
>= MAX_OPEN_DIRECTORIES
) {
547 dptr_idleoldest(sconn
);
550 dptr
= talloc_zero(NULL
, struct dptr_struct
);
552 DEBUG(0,("talloc fail in dptr_create.\n"));
553 TALLOC_FREE(dir_hnd
);
554 return NT_STATUS_NO_MEMORY
;
557 dptr
->smb_dname
= cp_smb_filename(dptr
, smb_dname
);
558 if (!dptr
->smb_dname
) {
560 TALLOC_FREE(dir_hnd
);
561 return NT_STATUS_NO_MEMORY
;
564 dptr
->dir_hnd
= dir_hnd
;
566 dptr
->expect_close
= expect_close
;
567 dptr
->wcard
= talloc_strdup(dptr
, wcard
);
570 TALLOC_FREE(dir_hnd
);
571 return NT_STATUS_NO_MEMORY
;
573 if ((req
!= NULL
&& req
->posix_pathnames
) ||
574 (wcard
[0] == '.' && wcard
[1] == 0)) {
575 dptr
->has_wild
= True
;
577 dptr
->has_wild
= wcard_has_wild
;
582 if (sconn
->using_smb2
) {
589 * This is an old-style SMBsearch request. Ensure the
590 * value we return will fit in the range 1-255.
593 dptr
->dnum
= bitmap_find(sconn
->searches
.dptr_bmap
, 0);
595 if(dptr
->dnum
== -1 || dptr
->dnum
> 254) {
598 * Try and close the oldest handle not marked for
599 * expect close in the hope that the client has
600 * finished with that one.
603 dptr_close_oldest(sconn
, true);
605 /* Now try again... */
606 dptr
->dnum
= bitmap_find(sconn
->searches
.dptr_bmap
, 0);
607 if(dptr
->dnum
== -1 || dptr
->dnum
> 254) {
608 DEBUG(0,("dptr_create: returned %d: Error - all old dirptrs in use ?\n", dptr
->dnum
));
610 TALLOC_FREE(dir_hnd
);
611 return NT_STATUS_TOO_MANY_OPENED_FILES
;
617 * This is a new-style trans2 request. Allocate from
618 * a range that will return 256 - MAX_DIRECTORY_HANDLES.
621 dptr
->dnum
= bitmap_find(sconn
->searches
.dptr_bmap
, 255);
623 if(dptr
->dnum
== -1 || dptr
->dnum
< 255) {
626 * Try and close the oldest handle close in the hope that
627 * the client has finished with that one. This will only
628 * happen in the case of the Win98 client bug where it leaks
632 dptr_close_oldest(sconn
, false);
634 /* Now try again... */
635 dptr
->dnum
= bitmap_find(sconn
->searches
.dptr_bmap
, 255);
637 if(dptr
->dnum
== -1 || dptr
->dnum
< 255) {
638 DEBUG(0,("dptr_create: returned %d: Error - all new dirptrs in use ?\n", dptr
->dnum
));
640 TALLOC_FREE(dir_hnd
);
641 return NT_STATUS_TOO_MANY_OPENED_FILES
;
646 bitmap_set(sconn
->searches
.dptr_bmap
, dptr
->dnum
);
648 dptr
->dnum
+= 1; /* Always bias the dnum by one - no zero dnums allowed. */
650 DLIST_ADD(sconn
->searches
.dirptrs
, dptr
);
653 DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
655 dptr
->smb_dname
->base_name
,
664 /****************************************************************************
665 Wrapper functions to access the lower level directory handles.
666 ****************************************************************************/
668 void dptr_CloseDir(files_struct
*fsp
)
672 * The destructor for the struct smb_Dir
673 * (fsp->dptr->dir_hnd) now handles
674 * all resource deallocation.
676 dptr_close_internal(fsp
->dptr
);
681 void dptr_SeekDir(struct dptr_struct
*dptr
, long offset
)
683 SeekDir(dptr
->dir_hnd
, offset
);
686 long dptr_TellDir(struct dptr_struct
*dptr
)
688 return TellDir(dptr
->dir_hnd
);
691 bool dptr_has_wild(struct dptr_struct
*dptr
)
693 return dptr
->has_wild
;
696 int dptr_dnum(struct dptr_struct
*dptr
)
701 bool dptr_get_priv(struct dptr_struct
*dptr
)
706 void dptr_set_priv(struct dptr_struct
*dptr
)
711 /****************************************************************************
712 Return the next visible file name, skipping veto'd and invisible files.
713 ****************************************************************************/
715 static const char *dptr_normal_ReadDirName(struct dptr_struct
*dptr
,
716 long *poffset
, SMB_STRUCT_STAT
*pst
,
719 /* Normal search for the next file. */
721 char *talloced
= NULL
;
723 while ((name
= ReadDirName(dptr
->dir_hnd
, poffset
, pst
, &talloced
))
725 if (is_visible_file(dptr
->conn
,
726 dptr
->smb_dname
->base_name
,
730 *ptalloced
= talloced
;
733 TALLOC_FREE(talloced
);
738 /****************************************************************************
739 Return the next visible file name, skipping veto'd and invisible files.
740 ****************************************************************************/
742 static char *dptr_ReadDirName(TALLOC_CTX
*ctx
,
743 struct dptr_struct
*dptr
,
745 SMB_STRUCT_STAT
*pst
)
747 struct smb_filename smb_fname_base
;
749 const char *name_temp
= NULL
;
750 char *talloced
= NULL
;
751 char *pathreal
= NULL
;
752 char *found_name
= NULL
;
755 SET_STAT_INVALID(*pst
);
757 if (dptr
->has_wild
|| dptr
->did_stat
) {
758 name_temp
= dptr_normal_ReadDirName(dptr
, poffset
, pst
,
760 if (name_temp
== NULL
) {
763 if (talloced
!= NULL
) {
764 return talloc_move(ctx
, &talloced
);
766 return talloc_strdup(ctx
, name_temp
);
769 /* If poffset is -1 then we know we returned this name before and we
770 * have no wildcards. We're at the end of the directory. */
771 if (*poffset
== END_OF_DIRECTORY_OFFSET
) {
775 /* We know the stored wcard contains no wildcard characters.
776 * See if we can match with a stat call. If we can't, then set
777 * did_stat to true to ensure we only do this once and keep
780 dptr
->did_stat
= true;
782 /* First check if it should be visible. */
783 if (!is_visible_file(dptr
->conn
,
784 dptr
->smb_dname
->base_name
,
788 /* This only returns false if the file was found, but
789 is explicitly not visible. Set us to end of
790 directory, but return NULL as we know we can't ever
795 if (VALID_STAT(*pst
)) {
796 name
= talloc_strdup(ctx
, dptr
->wcard
);
800 pathreal
= talloc_asprintf(ctx
,
802 dptr
->smb_dname
->base_name
,
807 /* Create an smb_filename with stream_name == NULL. */
808 smb_fname_base
= (struct smb_filename
) { .base_name
= pathreal
};
810 if (SMB_VFS_STAT(dptr
->conn
, &smb_fname_base
) == 0) {
811 *pst
= smb_fname_base
.st
;
812 name
= talloc_strdup(ctx
, dptr
->wcard
);
815 /* If we get any other error than ENOENT or ENOTDIR
816 then the file exists we just can't stat it. */
817 if (errno
!= ENOENT
&& errno
!= ENOTDIR
) {
818 name
= talloc_strdup(ctx
, dptr
->wcard
);
823 /* Stat failed. We know this is authoratiative if we are
824 * providing case sensitive semantics or the underlying
825 * filesystem is case sensitive.
827 if (dptr
->conn
->case_sensitive
||
828 !(dptr
->conn
->fs_capabilities
& FILE_CASE_SENSITIVE_SEARCH
))
834 * Try case-insensitive stat if the fs has the ability. This avoids
835 * scanning the whole directory.
837 ret
= SMB_VFS_GET_REAL_FILENAME(dptr
->conn
,
838 dptr
->smb_dname
->base_name
,
845 } else if (errno
== ENOENT
) {
846 /* The case-insensitive lookup was authoritative. */
850 TALLOC_FREE(pathreal
);
852 name_temp
= dptr_normal_ReadDirName(dptr
, poffset
, pst
, &talloced
);
853 if (name_temp
== NULL
) {
856 if (talloced
!= NULL
) {
857 return talloc_move(ctx
, &talloced
);
859 return talloc_strdup(ctx
, name_temp
);
862 TALLOC_FREE(pathreal
);
864 /* We need to set the underlying dir_hnd offset to -1
865 * also as this function is usually called with the
866 * output from TellDir. */
867 dptr
->dir_hnd
->offset
= *poffset
= END_OF_DIRECTORY_OFFSET
;
871 /****************************************************************************
872 Search for a file by name, skipping veto'ed and not visible files.
873 ****************************************************************************/
875 bool dptr_SearchDir(struct dptr_struct
*dptr
, const char *name
, long *poffset
, SMB_STRUCT_STAT
*pst
)
877 SET_STAT_INVALID(*pst
);
879 if (!dptr
->has_wild
&& (dptr
->dir_hnd
->offset
== END_OF_DIRECTORY_OFFSET
)) {
880 /* This is a singleton directory and we're already at the end. */
881 *poffset
= END_OF_DIRECTORY_OFFSET
;
885 return SearchDir(dptr
->dir_hnd
, name
, poffset
);
888 /****************************************************************************
889 Initialize variables & state data at the beginning of all search SMB requests.
890 ****************************************************************************/
891 void dptr_init_search_op(struct dptr_struct
*dptr
)
893 SMB_VFS_INIT_SEARCH_OP(dptr
->conn
, dptr
->dir_hnd
->dir
);
896 /****************************************************************************
897 Map a native directory offset to a 32-bit cookie.
898 ****************************************************************************/
900 static uint32_t map_dir_offset_to_wire(struct dptr_struct
*dptr
, long offset
)
905 if (offset
== END_OF_DIRECTORY_OFFSET
) {
906 return WIRE_END_OF_DIRECTORY_OFFSET
;
907 } else if(offset
== START_OF_DIRECTORY_OFFSET
) {
908 return WIRE_START_OF_DIRECTORY_OFFSET
;
909 } else if (offset
== DOT_DOT_DIRECTORY_OFFSET
) {
910 return WIRE_DOT_DOT_DIRECTORY_OFFSET
;
912 if (sizeof(long) == 4) {
913 /* 32-bit machine. We can cheat... */
914 return (uint32_t)offset
;
916 if (dptr
->dptr_cache
== NULL
) {
917 /* Lazy initialize cache. */
918 dptr
->dptr_cache
= memcache_init(dptr
, 0);
919 if (dptr
->dptr_cache
== NULL
) {
920 return WIRE_END_OF_DIRECTORY_OFFSET
;
923 /* Have we seen this offset before ? */
924 key
.data
= (void *)&offset
;
925 key
.length
= sizeof(offset
);
926 if (memcache_lookup(dptr
->dptr_cache
,
927 SMB1_SEARCH_OFFSET_MAP
,
930 uint32_t wire_offset
;
931 SMB_ASSERT(val
.length
== sizeof(wire_offset
));
932 memcpy(&wire_offset
, val
.data
, sizeof(wire_offset
));
933 DEBUG(10,("found wire %u <-> offset %ld\n",
934 (unsigned int)wire_offset
,
939 /* Allocate a new wire cookie. */
942 } while (dptr
->counter
== WIRE_START_OF_DIRECTORY_OFFSET
||
943 dptr
->counter
== WIRE_END_OF_DIRECTORY_OFFSET
||
944 dptr
->counter
== WIRE_DOT_DOT_DIRECTORY_OFFSET
);
945 /* Store it in the cache. */
946 key
.data
= (void *)&offset
;
947 key
.length
= sizeof(offset
);
948 val
.data
= (void *)&dptr
->counter
;
949 val
.length
= sizeof(dptr
->counter
); /* MUST BE uint32_t ! */
950 memcache_add(dptr
->dptr_cache
,
951 SMB1_SEARCH_OFFSET_MAP
,
954 /* And the reverse mapping for lookup from
955 map_wire_to_dir_offset(). */
956 memcache_add(dptr
->dptr_cache
,
957 SMB1_SEARCH_OFFSET_MAP
,
960 DEBUG(10,("stored wire %u <-> offset %ld\n",
961 (unsigned int)dptr
->counter
,
963 return dptr
->counter
;
966 /****************************************************************************
967 Fill the 5 byte server reserved dptr field.
968 ****************************************************************************/
970 bool dptr_fill(struct smbd_server_connection
*sconn
,
971 char *buf1
,unsigned int key
)
973 unsigned char *buf
= (unsigned char *)buf1
;
974 struct dptr_struct
*dptr
= dptr_get(sconn
, key
, false);
975 uint32_t wire_offset
;
977 DEBUG(1,("filling null dirptr %d\n",key
));
980 wire_offset
= map_dir_offset_to_wire(dptr
,TellDir(dptr
->dir_hnd
));
981 DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key
,
982 (long)dptr
->dir_hnd
,(int)wire_offset
));
984 SIVAL(buf
,1,wire_offset
);
988 /****************************************************************************
989 Map a 32-bit wire cookie to a native directory offset.
990 ****************************************************************************/
992 static long map_wire_to_dir_offset(struct dptr_struct
*dptr
, uint32_t wire_offset
)
997 if (wire_offset
== WIRE_END_OF_DIRECTORY_OFFSET
) {
998 return END_OF_DIRECTORY_OFFSET
;
999 } else if(wire_offset
== WIRE_START_OF_DIRECTORY_OFFSET
) {
1000 return START_OF_DIRECTORY_OFFSET
;
1001 } else if (wire_offset
== WIRE_DOT_DOT_DIRECTORY_OFFSET
) {
1002 return DOT_DOT_DIRECTORY_OFFSET
;
1004 if (sizeof(long) == 4) {
1005 /* 32-bit machine. We can cheat... */
1006 return (long)wire_offset
;
1008 if (dptr
->dptr_cache
== NULL
) {
1009 /* Logic error, cache should be initialized. */
1010 return END_OF_DIRECTORY_OFFSET
;
1012 key
.data
= (void *)&wire_offset
;
1013 key
.length
= sizeof(wire_offset
);
1014 if (memcache_lookup(dptr
->dptr_cache
,
1015 SMB1_SEARCH_OFFSET_MAP
,
1018 /* Found mapping. */
1020 SMB_ASSERT(val
.length
== sizeof(offset
));
1021 memcpy(&offset
, val
.data
, sizeof(offset
));
1022 DEBUG(10,("lookup wire %u <-> offset %ld\n",
1023 (unsigned int)wire_offset
,
1027 return END_OF_DIRECTORY_OFFSET
;
1030 /****************************************************************************
1031 Fetch the dir ptr and seek it given the 5 byte server field.
1032 ****************************************************************************/
1034 struct dptr_struct
*dptr_fetch(struct smbd_server_connection
*sconn
,
1035 char *buf
, int *num
)
1037 unsigned int key
= *(unsigned char *)buf
;
1038 struct dptr_struct
*dptr
= dptr_get(sconn
, key
, false);
1039 uint32_t wire_offset
;
1043 DEBUG(3,("fetched null dirptr %d\n",key
));
1047 wire_offset
= IVAL(buf
,1);
1048 seekoff
= map_wire_to_dir_offset(dptr
, wire_offset
);
1049 SeekDir(dptr
->dir_hnd
,seekoff
);
1050 DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
1051 key
, dptr
->smb_dname
->base_name
, (int)seekoff
));
1055 /****************************************************************************
1057 ****************************************************************************/
1059 struct dptr_struct
*dptr_fetch_lanman2(struct smbd_server_connection
*sconn
,
1062 struct dptr_struct
*dptr
= dptr_get(sconn
, dptr_num
, false);
1065 DEBUG(3,("fetched null dirptr %d\n",dptr_num
));
1068 DEBUG(3,("fetching dirptr %d for path %s\n",
1070 dptr
->smb_dname
->base_name
));
1074 static bool mangle_mask_match(connection_struct
*conn
,
1075 const char *filename
,
1080 if (!name_to_8_3(filename
,mname
,False
,conn
->params
)) {
1083 return mask_match_search(mname
,mask
,False
);
1086 bool smbd_dirptr_get_entry(TALLOC_CTX
*ctx
,
1087 struct dptr_struct
*dirptr
,
1092 bool (*match_fn
)(TALLOC_CTX
*ctx
,
1097 bool (*mode_fn
)(TALLOC_CTX
*ctx
,
1099 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
, &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 DirCacheAdd(dirptr
->dir_hnd
, dname
, cur_offset
);
1233 *_smb_fname
= cp_smb_filename(ctx
, &smb_fname
);
1234 TALLOC_FREE(pathreal
);
1235 if (*_smb_fname
== NULL
) {
1240 *_prev_offset
= prev_offset
;
1248 /****************************************************************************
1249 Get an 8.3 directory entry.
1250 ****************************************************************************/
1252 static bool smbd_dirptr_8_3_match_fn(TALLOC_CTX
*ctx
,
1258 connection_struct
*conn
= (connection_struct
*)private_data
;
1260 if ((strcmp(mask
,"*.*") == 0) ||
1261 mask_match_search(dname
, mask
, false) ||
1262 mangle_mask_match(conn
, dname
, mask
)) {
1266 * Ensure we can push the original name as UCS2. If
1267 * not, then just don't return this name.
1271 size_t len
= (strlen(dname
) + 2) * 4; /* Allow enough space. */
1272 uint8_t *tmp
= talloc_array(talloc_tos(),
1276 status
= srvstr_push(NULL
,
1277 FLAGS2_UNICODE_STRINGS
,
1286 if (!NT_STATUS_IS_OK(status
)) {
1290 if (!mangle_is_8_3(dname
, false, conn
->params
)) {
1291 bool ok
= name_to_8_3(dname
, mname
, false,
1301 *_fname
= talloc_strdup(ctx
, fname
);
1302 if (*_fname
== NULL
) {
1312 static bool smbd_dirptr_8_3_mode_fn(TALLOC_CTX
*ctx
,
1314 struct smb_filename
*smb_fname
,
1317 connection_struct
*conn
= (connection_struct
*)private_data
;
1319 if (!VALID_STAT(smb_fname
->st
)) {
1320 if ((SMB_VFS_STAT(conn
, smb_fname
)) != 0) {
1321 DEBUG(5,("smbd_dirptr_8_3_mode_fn: "
1322 "Couldn't stat [%s]. Error "
1324 smb_fname_str_dbg(smb_fname
),
1330 *_mode
= dos_mode(conn
, smb_fname
);
1334 bool get_dir_entry(TALLOC_CTX
*ctx
,
1335 struct dptr_struct
*dirptr
,
1341 struct timespec
*_date
,
1345 connection_struct
*conn
= dirptr
->conn
;
1347 struct smb_filename
*smb_fname
= NULL
;
1352 ok
= smbd_dirptr_get_entry(ctx
,
1358 smbd_dirptr_8_3_match_fn
,
1359 smbd_dirptr_8_3_mode_fn
,
1369 *_fname
= talloc_move(ctx
, &fname
);
1370 *_size
= smb_fname
->st
.st_ex_size
;
1372 *_date
= smb_fname
->st
.st_ex_mtime
;
1373 TALLOC_FREE(smb_fname
);
1377 /*******************************************************************
1378 Check to see if a user can read a file. This is only approximate,
1379 it is used as part of the "hide unreadable" option. Don't
1380 use it for anything security sensitive.
1381 ********************************************************************/
1383 static bool user_can_read_file(connection_struct
*conn
,
1384 struct smb_filename
*smb_fname
)
1387 uint32_t rejected_share_access
= 0;
1388 uint32_t rejected_mask
= 0;
1389 struct security_descriptor
*sd
= NULL
;
1390 uint32_t access_mask
= FILE_READ_DATA
|
1392 FILE_READ_ATTRIBUTES
|
1393 SEC_STD_READ_CONTROL
;
1396 * Never hide files from the root user.
1397 * We use (uid_t)0 here not sec_initial_uid()
1398 * as make test uses a single user context.
1401 if (get_current_uid(conn
) == (uid_t
)0) {
1406 * We can't directly use smbd_check_access_rights()
1407 * here, as this implicitly grants FILE_READ_ATTRIBUTES
1408 * which the Windows access-based-enumeration code
1409 * explicitly checks for on the file security descriptor.
1412 * https://bugzilla.samba.org/show_bug.cgi?id=10252
1414 * and the smb2.acl2.ACCESSBASED test for details.
1417 rejected_share_access
= access_mask
& ~(conn
->share_access
);
1418 if (rejected_share_access
) {
1419 DEBUG(10, ("rejected share access 0x%x "
1421 (unsigned int)access_mask
,
1422 smb_fname_str_dbg(smb_fname
),
1423 (unsigned int)rejected_share_access
));
1427 status
= SMB_VFS_GET_NT_ACL(conn
,
1435 if (!NT_STATUS_IS_OK(status
)) {
1436 DEBUG(10, ("Could not get acl "
1438 smb_fname_str_dbg(smb_fname
),
1439 nt_errstr(status
)));
1443 status
= se_file_access_check(sd
,
1444 get_current_nttok(conn
),
1451 if (NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)) {
1452 DEBUG(10,("rejected bits 0x%x read access for %s\n",
1453 (unsigned int)rejected_mask
,
1454 smb_fname_str_dbg(smb_fname
) ));
1460 /*******************************************************************
1461 Check to see if a user can write a file (and only files, we do not
1462 check dirs on this one). This is only approximate,
1463 it is used as part of the "hide unwriteable" option. Don't
1464 use it for anything security sensitive.
1465 ********************************************************************/
1467 static bool user_can_write_file(connection_struct
*conn
,
1468 const struct smb_filename
*smb_fname
)
1471 * Never hide files from the root user.
1472 * We use (uid_t)0 here not sec_initial_uid()
1473 * as make test uses a single user context.
1476 if (get_current_uid(conn
) == (uid_t
)0) {
1480 SMB_ASSERT(VALID_STAT(smb_fname
->st
));
1482 /* Pseudo-open the file */
1484 if(S_ISDIR(smb_fname
->st
.st_ex_mode
)) {
1488 return can_write_to_file(conn
, smb_fname
);
1491 /*******************************************************************
1492 Is a file a "special" type ?
1493 ********************************************************************/
1495 static bool file_is_special(connection_struct
*conn
,
1496 const struct smb_filename
*smb_fname
)
1499 * Never hide files from the root user.
1500 * We use (uid_t)0 here not sec_initial_uid()
1501 * as make test uses a single user context.
1504 if (get_current_uid(conn
) == (uid_t
)0) {
1508 SMB_ASSERT(VALID_STAT(smb_fname
->st
));
1510 if (S_ISREG(smb_fname
->st
.st_ex_mode
) ||
1511 S_ISDIR(smb_fname
->st
.st_ex_mode
) ||
1512 S_ISLNK(smb_fname
->st
.st_ex_mode
))
1518 /*******************************************************************
1519 Should the file be seen by the client?
1520 NOTE: A successful return is no guarantee of the file's existence.
1521 ********************************************************************/
1523 bool is_visible_file(connection_struct
*conn
, const char *dir_path
,
1524 const char *name
, SMB_STRUCT_STAT
*pst
, bool use_veto
)
1526 bool hide_unreadable
= lp_hide_unreadable(SNUM(conn
));
1527 bool hide_unwriteable
= lp_hide_unwriteable_files(SNUM(conn
));
1528 bool hide_special
= lp_hide_special_files(SNUM(conn
));
1530 struct smb_filename
*smb_fname_base
= NULL
;
1533 if ((strcmp(".",name
) == 0) || (strcmp("..",name
) == 0)) {
1534 return True
; /* . and .. are always visible. */
1537 /* If it's a vetoed file, pretend it doesn't even exist */
1538 if (use_veto
&& IS_VETO_PATH(conn
, name
)) {
1539 DEBUG(10,("is_visible_file: file %s is vetoed.\n", name
));
1543 if (hide_unreadable
|| hide_unwriteable
|| hide_special
) {
1544 entry
= talloc_asprintf(talloc_tos(), "%s/%s", dir_path
, name
);
1550 /* Create an smb_filename with stream_name == NULL. */
1551 smb_fname_base
= synthetic_smb_fname(talloc_tos(),
1556 if (smb_fname_base
== NULL
) {
1561 /* If the file name does not exist, there's no point checking
1562 * the configuration options. We succeed, on the basis that the
1563 * checks *might* have passed if the file was present.
1565 if (!VALID_STAT(*pst
)) {
1566 if (SMB_VFS_STAT(conn
, smb_fname_base
) != 0) {
1570 *pst
= smb_fname_base
->st
;
1573 /* Honour _hide unreadable_ option */
1574 if (hide_unreadable
&&
1575 !user_can_read_file(conn
, smb_fname_base
)) {
1576 DEBUG(10,("is_visible_file: file %s is unreadable.\n",
1581 /* Honour _hide unwriteable_ option */
1582 if (hide_unwriteable
&& !user_can_write_file(conn
,
1584 DEBUG(10,("is_visible_file: file %s is unwritable.\n",
1589 /* Honour _hide_special_ option */
1590 if (hide_special
&& file_is_special(conn
, smb_fname_base
)) {
1591 DEBUG(10,("is_visible_file: file %s is special.\n",
1600 TALLOC_FREE(smb_fname_base
);
1605 static int smb_Dir_destructor(struct smb_Dir
*dirp
)
1607 if (dirp
->dir
!= NULL
) {
1608 SMB_VFS_CLOSEDIR(dirp
->conn
,dirp
->dir
);
1609 if (dirp
->fsp
!= NULL
) {
1611 * The SMB_VFS_CLOSEDIR above
1612 * closes the underlying fd inside
1615 dirp
->fsp
->fh
->fd
= -1;
1616 if (dirp
->fsp
->dptr
!= NULL
) {
1617 SMB_ASSERT(dirp
->fsp
->dptr
->dir_hnd
== dirp
);
1618 dirp
->fsp
->dptr
->dir_hnd
= NULL
;
1623 if (dirp
->conn
->sconn
&& !dirp
->conn
->sconn
->using_smb2
) {
1624 dirp
->conn
->sconn
->searches
.dirhandles_open
--;
1629 /*******************************************************************
1631 ********************************************************************/
1633 struct smb_Dir
*OpenDir(TALLOC_CTX
*mem_ctx
, connection_struct
*conn
,
1634 const struct smb_filename
*smb_dname
,
1638 struct smb_Dir
*dirp
= talloc_zero(mem_ctx
, struct smb_Dir
);
1639 struct smbd_server_connection
*sconn
= conn
->sconn
;
1646 dirp
->name_cache_size
= lp_directory_name_cache_size(SNUM(conn
));
1648 dirp
->dir_smb_fname
= cp_smb_filename(dirp
, smb_dname
);
1649 if (!dirp
->dir_smb_fname
) {
1654 if (sconn
&& !sconn
->using_smb2
) {
1655 sconn
->searches
.dirhandles_open
++;
1657 talloc_set_destructor(dirp
, smb_Dir_destructor
);
1659 dirp
->dir
= SMB_VFS_OPENDIR(conn
, dirp
->dir_smb_fname
, mask
, attr
);
1662 DEBUG(5,("OpenDir: Can't open %s. %s\n",
1663 dirp
->dir_smb_fname
->base_name
,
1675 /*******************************************************************
1676 Open a directory from an fsp.
1677 ********************************************************************/
1679 static struct smb_Dir
*OpenDir_fsp(TALLOC_CTX
*mem_ctx
, connection_struct
*conn
,
1684 struct smb_Dir
*dirp
= talloc_zero(mem_ctx
, struct smb_Dir
);
1685 struct smbd_server_connection
*sconn
= conn
->sconn
;
1692 dirp
->name_cache_size
= lp_directory_name_cache_size(SNUM(conn
));
1694 dirp
->dir_smb_fname
= cp_smb_filename(dirp
, fsp
->fsp_name
);
1695 if (!dirp
->dir_smb_fname
) {
1700 if (sconn
&& !sconn
->using_smb2
) {
1701 sconn
->searches
.dirhandles_open
++;
1703 talloc_set_destructor(dirp
, smb_Dir_destructor
);
1705 if (fsp
->is_directory
&& fsp
->fh
->fd
!= -1) {
1706 dirp
->dir
= SMB_VFS_FDOPENDIR(fsp
, mask
, attr
);
1707 if (dirp
->dir
!= NULL
) {
1710 DEBUG(10,("OpenDir_fsp: SMB_VFS_FDOPENDIR on %s returned "
1712 dirp
->dir_smb_fname
->base_name
,
1714 if (errno
!= ENOSYS
) {
1720 if (dirp
->dir
== NULL
) {
1721 /* FDOPENDIR didn't work. Use OPENDIR instead. */
1722 dirp
->dir
= SMB_VFS_OPENDIR(conn
,
1723 dirp
->dir_smb_fname
,
1729 DEBUG(5,("OpenDir_fsp: Can't open %s. %s\n",
1730 dirp
->dir_smb_fname
->base_name
,
1743 /*******************************************************************
1744 Read from a directory.
1745 Return directory entry, current offset, and optional stat information.
1746 Don't check for veto or invisible files.
1747 ********************************************************************/
1749 const char *ReadDirName(struct smb_Dir
*dirp
, long *poffset
,
1750 SMB_STRUCT_STAT
*sbuf
, char **ptalloced
)
1753 char *talloced
= NULL
;
1754 connection_struct
*conn
= dirp
->conn
;
1756 /* Cheat to allow . and .. to be the first entries returned. */
1757 if (((*poffset
== START_OF_DIRECTORY_OFFSET
) ||
1758 (*poffset
== DOT_DOT_DIRECTORY_OFFSET
)) && (dirp
->file_number
< 2))
1760 if (dirp
->file_number
== 0) {
1762 *poffset
= dirp
->offset
= START_OF_DIRECTORY_OFFSET
;
1765 *poffset
= dirp
->offset
= DOT_DOT_DIRECTORY_OFFSET
;
1767 dirp
->file_number
++;
1772 if (*poffset
== END_OF_DIRECTORY_OFFSET
) {
1773 *poffset
= dirp
->offset
= END_OF_DIRECTORY_OFFSET
;
1777 /* A real offset, seek to it. */
1778 SeekDir(dirp
, *poffset
);
1780 while ((n
= vfs_readdirname(conn
, dirp
->dir
, sbuf
, &talloced
))) {
1781 /* Ignore . and .. - we've already returned them. */
1783 if ((n
[1] == '\0') || (n
[1] == '.' && n
[2] == '\0')) {
1784 TALLOC_FREE(talloced
);
1788 *poffset
= dirp
->offset
= SMB_VFS_TELLDIR(conn
, dirp
->dir
);
1789 *ptalloced
= talloced
;
1790 dirp
->file_number
++;
1793 *poffset
= dirp
->offset
= END_OF_DIRECTORY_OFFSET
;
1798 /*******************************************************************
1799 Rewind to the start.
1800 ********************************************************************/
1802 void RewindDir(struct smb_Dir
*dirp
, long *poffset
)
1804 SMB_VFS_REWINDDIR(dirp
->conn
, dirp
->dir
);
1805 dirp
->file_number
= 0;
1806 dirp
->offset
= START_OF_DIRECTORY_OFFSET
;
1807 *poffset
= START_OF_DIRECTORY_OFFSET
;
1810 /*******************************************************************
1812 ********************************************************************/
1814 void SeekDir(struct smb_Dir
*dirp
, long offset
)
1816 if (offset
!= dirp
->offset
) {
1817 if (offset
== START_OF_DIRECTORY_OFFSET
) {
1818 RewindDir(dirp
, &offset
);
1820 * Ok we should really set the file number here
1821 * to 1 to enable ".." to be returned next. Trouble
1822 * is I'm worried about callers using SeekDir(dirp,0)
1823 * as equivalent to RewindDir(). So leave this alone
1826 } else if (offset
== DOT_DOT_DIRECTORY_OFFSET
) {
1827 RewindDir(dirp
, &offset
);
1829 * Set the file number to 2 - we want to get the first
1830 * real file entry (the one we return after "..")
1831 * on the next ReadDir.
1833 dirp
->file_number
= 2;
1834 } else if (offset
== END_OF_DIRECTORY_OFFSET
) {
1835 ; /* Don't seek in this case. */
1837 SMB_VFS_SEEKDIR(dirp
->conn
, dirp
->dir
, offset
);
1839 dirp
->offset
= offset
;
1843 /*******************************************************************
1844 Tell a dir position.
1845 ********************************************************************/
1847 long TellDir(struct smb_Dir
*dirp
)
1849 return(dirp
->offset
);
1852 /*******************************************************************
1853 Add an entry into the dcache.
1854 ********************************************************************/
1856 static void DirCacheAdd(struct smb_Dir
*dirp
, const char *name
, long offset
)
1858 struct name_cache_entry
*e
;
1860 if (dirp
->name_cache_size
== 0) {
1864 if (dirp
->name_cache
== NULL
) {
1865 dirp
->name_cache
= talloc_zero_array(
1866 dirp
, struct name_cache_entry
, dirp
->name_cache_size
);
1868 if (dirp
->name_cache
== NULL
) {
1873 dirp
->name_cache_index
= (dirp
->name_cache_index
+1) %
1874 dirp
->name_cache_size
;
1875 e
= &dirp
->name_cache
[dirp
->name_cache_index
];
1876 TALLOC_FREE(e
->name
);
1877 e
->name
= talloc_strdup(dirp
, name
);
1881 /*******************************************************************
1882 Find an entry by name. Leave us at the offset after it.
1883 Don't check for veto or invisible files.
1884 ********************************************************************/
1886 bool SearchDir(struct smb_Dir
*dirp
, const char *name
, long *poffset
)
1889 const char *entry
= NULL
;
1890 char *talloced
= NULL
;
1891 connection_struct
*conn
= dirp
->conn
;
1893 /* Search back in the name cache. */
1894 if (dirp
->name_cache_size
&& dirp
->name_cache
) {
1895 for (i
= dirp
->name_cache_index
; i
>= 0; i
--) {
1896 struct name_cache_entry
*e
= &dirp
->name_cache
[i
];
1897 if (e
->name
&& (conn
->case_sensitive
? (strcmp(e
->name
, name
) == 0) : strequal(e
->name
, name
))) {
1898 *poffset
= e
->offset
;
1899 SeekDir(dirp
, e
->offset
);
1903 for (i
= dirp
->name_cache_size
- 1; i
> dirp
->name_cache_index
; i
--) {
1904 struct name_cache_entry
*e
= &dirp
->name_cache
[i
];
1905 if (e
->name
&& (conn
->case_sensitive
? (strcmp(e
->name
, name
) == 0) : strequal(e
->name
, name
))) {
1906 *poffset
= e
->offset
;
1907 SeekDir(dirp
, e
->offset
);
1913 /* Not found in the name cache. Rewind directory and start from scratch. */
1914 SMB_VFS_REWINDDIR(conn
, dirp
->dir
);
1915 dirp
->file_number
= 0;
1916 *poffset
= START_OF_DIRECTORY_OFFSET
;
1917 while ((entry
= ReadDirName(dirp
, poffset
, NULL
, &talloced
))) {
1918 if (conn
->case_sensitive
? (strcmp(entry
, name
) == 0) : strequal(entry
, name
)) {
1919 TALLOC_FREE(talloced
);
1922 TALLOC_FREE(talloced
);
1927 struct files_below_forall_state
{
1930 int (*fn
)(struct file_id fid
, const struct share_mode_data
*data
,
1931 void *private_data
);
1935 static int files_below_forall_fn(struct file_id fid
,
1936 const struct share_mode_data
*data
,
1939 struct files_below_forall_state
*state
= private_data
;
1940 char tmpbuf
[PATH_MAX
];
1941 char *fullpath
, *to_free
;
1944 len
= full_path_tos(data
->servicepath
, data
->base_name
,
1945 tmpbuf
, sizeof(tmpbuf
),
1946 &fullpath
, &to_free
);
1950 if (state
->dirpath_len
>= len
) {
1952 * Filter files above dirpath
1956 if (fullpath
[state
->dirpath_len
] != '/') {
1958 * Filter file that don't have a path separator at the end of
1964 if (memcmp(state
->dirpath
, fullpath
, state
->dirpath_len
) != 0) {
1971 return state
->fn(fid
, data
, state
->private_data
);
1974 static int files_below_forall(connection_struct
*conn
,
1975 const struct smb_filename
*dir_name
,
1976 int (*fn
)(struct file_id fid
,
1977 const struct share_mode_data
*data
,
1978 void *private_data
),
1981 struct files_below_forall_state state
= {
1983 .private_data
= private_data
,
1986 char tmpbuf
[PATH_MAX
];
1989 state
.dirpath_len
= full_path_tos(conn
->connectpath
,
1990 dir_name
->base_name
,
1991 tmpbuf
, sizeof(tmpbuf
),
1992 &state
.dirpath
, &to_free
);
1993 if (state
.dirpath_len
== -1) {
1997 ret
= share_mode_forall(files_below_forall_fn
, &state
);
1998 TALLOC_FREE(to_free
);
2002 struct have_file_open_below_state
{
2006 static int have_file_open_below_fn(struct file_id fid
,
2007 const struct share_mode_data
*data
,
2010 struct have_file_open_below_state
*state
= private_data
;
2011 state
->found_one
= true;
2015 bool have_file_open_below(connection_struct
*conn
,
2016 const struct smb_filename
*name
)
2018 struct have_file_open_below_state state
= {
2023 if (!VALID_STAT(name
->st
)) {
2026 if (!S_ISDIR(name
->st
.st_ex_mode
)) {
2030 ret
= files_below_forall(conn
, name
, have_file_open_below_fn
, &state
);
2035 return state
.found_one
;
2038 /*****************************************************************
2039 Is this directory empty ?
2040 *****************************************************************/
2042 NTSTATUS
can_delete_directory_fsp(files_struct
*fsp
)
2044 NTSTATUS status
= NT_STATUS_OK
;
2046 const char *dname
= NULL
;
2047 const char *dirname
= fsp
->fsp_name
->base_name
;
2048 char *talloced
= NULL
;
2050 struct connection_struct
*conn
= fsp
->conn
;
2051 struct smb_Dir
*dir_hnd
= OpenDir_fsp(talloc_tos(),
2058 return map_nt_error_from_unix(errno
);
2061 while ((dname
= ReadDirName(dir_hnd
, &dirpos
, &st
, &talloced
))) {
2062 /* Quick check for "." and ".." */
2063 if (dname
[0] == '.') {
2064 if (!dname
[1] || (dname
[1] == '.' && !dname
[2])) {
2065 TALLOC_FREE(talloced
);
2070 if (!is_visible_file(conn
, dirname
, dname
, &st
, True
)) {
2071 TALLOC_FREE(talloced
);
2075 DEBUG(10,("got name %s - can't delete\n",
2077 status
= NT_STATUS_DIRECTORY_NOT_EMPTY
;
2080 TALLOC_FREE(talloced
);
2081 TALLOC_FREE(dir_hnd
);
2083 if (!NT_STATUS_IS_OK(status
)) {
2087 if (!(fsp
->posix_flags
& FSP_POSIX_FLAGS_RENAME
) &&
2088 lp_strict_rename(SNUM(conn
)) &&
2089 have_file_open_below(fsp
->conn
, fsp
->fsp_name
))
2091 return NT_STATUS_ACCESS_DENIED
;
2094 return NT_STATUS_OK
;