Fix the developer O3 build
[Samba.git] / source3 / smbd / dir.c
blob36d95d5abe02e09040c03bcbf9afa8ed6176ffd6
1 /*
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/>.
21 #include "includes.h"
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 {
47 char *name;
48 long offset;
51 struct smb_Dir {
52 connection_struct *conn;
53 DIR *dir;
54 long offset;
55 char *dir_path;
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(). */
64 struct dptr_struct {
65 struct dptr_struct *next, *prev;
66 int dnum;
67 uint16 spid;
68 struct connection_struct *conn;
69 struct smb_Dir *dir_hnd;
70 bool expect_close;
71 char *wcard;
72 uint32 attr;
73 char *path;
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. */
77 uint32_t counter;
78 struct memcache *dptr_cache;
81 static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn,
82 files_struct *fsp,
83 const char *mask,
84 uint32 attr);
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) {
97 return true;
100 sconn->searches.dptr_bmap = bitmap_talloc(
101 sconn, MAX_DIRECTORY_HANDLES);
103 if (sconn->searches.dptr_bmap == NULL) {
104 return false;
107 return true;
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)
116 if (dptr->dir_hnd) {
117 DEBUG(4,("Idling dptr dnum %d\n",dptr->dnum));
118 TALLOC_FREE(dptr->dir_hnd);
119 TALLOC_FREE(dptr->dptr_cache);
120 dptr->counter = 0;
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);
137 if(!dptr) {
138 DEBUG(0,("No dptrs available to idle ?\n"));
139 return;
143 * Idle the oldest pointer.
146 for(; dptr; dptr = DLIST_PREV(dptr)) {
147 if (dptr->dir_hnd) {
148 dptr_idle(dptr);
149 return;
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));
169 if (!(dptr->dir_hnd = OpenDir(
170 NULL, dptr->conn, dptr->path,
171 dptr->wcard, dptr->attr))) {
172 DEBUG(4,("dptr_get: Failed to open %s (%s)\n",dptr->path,
173 strerror(errno)));
174 return NULL;
177 DLIST_PROMOTE(sconn->searches.dirptrs,dptr);
178 return dptr;
181 return(NULL);
184 /****************************************************************************
185 Get the dir path for a dir index.
186 ****************************************************************************/
188 const char *dptr_path(struct smbd_server_connection *sconn, int key)
190 struct dptr_struct *dptr = dptr_get(sconn, key, false);
191 if (dptr)
192 return(dptr->path);
193 return(NULL);
196 /****************************************************************************
197 Get the dir wcard for a dir index.
198 ****************************************************************************/
200 const char *dptr_wcard(struct smbd_server_connection *sconn, int key)
202 struct dptr_struct *dptr = dptr_get(sconn, key, false);
203 if (dptr)
204 return(dptr->wcard);
205 return(NULL);
208 /****************************************************************************
209 Get the dir attrib for a dir index.
210 ****************************************************************************/
212 uint16 dptr_attr(struct smbd_server_connection *sconn, int key)
214 struct dptr_struct *dptr = dptr_get(sconn, key, false);
215 if (dptr)
216 return(dptr->attr);
217 return(0);
220 /****************************************************************************
221 Close a dptr (internal func).
222 ****************************************************************************/
224 static void dptr_close_internal(struct dptr_struct *dptr)
226 struct smbd_server_connection *sconn = dptr->conn->sconn;
228 DEBUG(4,("closing dptr key %d\n",dptr->dnum));
230 if (sconn == NULL) {
231 goto done;
234 if (sconn->using_smb2) {
235 goto done;
238 DLIST_REMOVE(sconn->searches.dirptrs, dptr);
241 * Free the dnum in the bitmap. Remember the dnum value is always
242 * biased by one with respect to the bitmap.
245 if (!bitmap_query(sconn->searches.dptr_bmap, dptr->dnum - 1)) {
246 DEBUG(0,("dptr_close_internal : Error - closing dnum = %d and bitmap not set !\n",
247 dptr->dnum ));
250 bitmap_clear(sconn->searches.dptr_bmap, dptr->dnum - 1);
252 done:
253 TALLOC_FREE(dptr->dir_hnd);
254 TALLOC_FREE(dptr);
257 /****************************************************************************
258 Close a dptr given a key.
259 ****************************************************************************/
261 void dptr_close(struct smbd_server_connection *sconn, int *key)
263 struct dptr_struct *dptr;
265 if(*key == INVALID_DPTR_KEY)
266 return;
268 /* OS/2 seems to use -1 to indicate "close all directories" */
269 if (*key == -1) {
270 struct dptr_struct *next;
271 for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
272 next = dptr->next;
273 dptr_close_internal(dptr);
275 *key = INVALID_DPTR_KEY;
276 return;
279 dptr = dptr_get(sconn, *key, true);
281 if (!dptr) {
282 DEBUG(0,("Invalid key %d given to dptr_close\n", *key));
283 return;
286 dptr_close_internal(dptr);
288 *key = INVALID_DPTR_KEY;
291 /****************************************************************************
292 Close all dptrs for a cnum.
293 ****************************************************************************/
295 void dptr_closecnum(connection_struct *conn)
297 struct dptr_struct *dptr, *next;
298 struct smbd_server_connection *sconn = conn->sconn;
300 if (sconn == NULL) {
301 return;
304 for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
305 next = dptr->next;
306 if (dptr->conn == conn) {
307 dptr_close_internal(dptr);
312 /****************************************************************************
313 Idle all dptrs for a cnum.
314 ****************************************************************************/
316 void dptr_idlecnum(connection_struct *conn)
318 struct dptr_struct *dptr;
319 struct smbd_server_connection *sconn = conn->sconn;
321 if (sconn == NULL) {
322 return;
325 for(dptr = sconn->searches.dirptrs; dptr; dptr = dptr->next) {
326 if (dptr->conn == conn && dptr->dir_hnd) {
327 dptr_idle(dptr);
332 /****************************************************************************
333 Close a dptr that matches a given path, only if it matches the spid also.
334 ****************************************************************************/
336 void dptr_closepath(struct smbd_server_connection *sconn,
337 char *path,uint16 spid)
339 struct dptr_struct *dptr, *next;
340 for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
341 next = dptr->next;
342 if (spid == dptr->spid && strequal(dptr->path,path))
343 dptr_close_internal(dptr);
347 /****************************************************************************
348 Try and close the oldest handle not marked for
349 expect close in the hope that the client has
350 finished with that one.
351 ****************************************************************************/
353 static void dptr_close_oldest(struct smbd_server_connection *sconn,
354 bool old)
356 struct dptr_struct *dptr;
359 * Go to the end of the list.
361 for(dptr = sconn->searches.dirptrs; dptr && dptr->next; dptr = dptr->next)
364 if(!dptr) {
365 DEBUG(0,("No old dptrs available to close oldest ?\n"));
366 return;
370 * If 'old' is true, close the oldest oldhandle dnum (ie. 1 < dnum < 256) that
371 * does not have expect_close set. If 'old' is false, close
372 * one of the new dnum handles.
375 for(; dptr; dptr = DLIST_PREV(dptr)) {
376 if ((old && (dptr->dnum < 256) && !dptr->expect_close) ||
377 (!old && (dptr->dnum > 255))) {
378 dptr_close_internal(dptr);
379 return;
384 /****************************************************************************
385 Safely do an OpenDir as root, ensuring we're in the right place.
386 ****************************************************************************/
388 static struct smb_Dir *open_dir_with_privilege(connection_struct *conn,
389 struct smb_request *req,
390 const char *path,
391 const char *wcard,
392 uint32_t attr)
394 struct smb_Dir *dir_hnd = NULL;
395 struct smb_filename *smb_fname_cwd;
396 char *saved_dir = vfs_GetWd(talloc_tos(), conn);
397 struct privilege_paths *priv_paths = req->priv_paths;
398 int ret;
400 if (saved_dir == NULL) {
401 return NULL;
404 if (vfs_ChDir(conn, path) == -1) {
405 return NULL;
408 /* Now check the stat value is the same. */
409 smb_fname_cwd = synthetic_smb_fname(talloc_tos(), ".", NULL, NULL);
411 if (smb_fname_cwd == NULL) {
412 goto out;
414 ret = SMB_VFS_STAT(conn, smb_fname_cwd);
415 if (ret != 0) {
416 goto out;
419 if (!check_same_stat(&smb_fname_cwd->st, &priv_paths->parent_name.st)) {
420 DEBUG(0,("open_dir_with_privilege: stat mismatch between %s "
421 "and %s\n",
422 path,
423 smb_fname_str_dbg(&priv_paths->parent_name)));
424 goto out;
427 dir_hnd = OpenDir(NULL, conn, ".", wcard, attr);
429 out:
431 vfs_ChDir(conn, saved_dir);
432 return dir_hnd;
435 /****************************************************************************
436 Create a new dir ptr. If the flag old_handle is true then we must allocate
437 from the bitmap range 0 - 255 as old SMBsearch directory handles are only
438 one byte long. If old_handle is false we allocate from the range
439 256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
440 a directory handle is never zero.
441 wcard must not be zero.
442 ****************************************************************************/
444 NTSTATUS dptr_create(connection_struct *conn,
445 struct smb_request *req,
446 files_struct *fsp,
447 const char *path, bool old_handle, bool expect_close,uint16 spid,
448 const char *wcard, bool wcard_has_wild, uint32 attr, struct dptr_struct **dptr_ret)
450 struct smbd_server_connection *sconn = conn->sconn;
451 struct dptr_struct *dptr = NULL;
452 struct smb_Dir *dir_hnd;
454 if (fsp && fsp->is_directory && fsp->fh->fd != -1) {
455 path = fsp->fsp_name->base_name;
458 DEBUG(5,("dptr_create dir=%s\n", path));
460 if (sconn == NULL) {
461 DEBUG(0,("dptr_create: called with fake connection_struct\n"));
462 return NT_STATUS_INTERNAL_ERROR;
465 if (!wcard) {
466 return NT_STATUS_INVALID_PARAMETER;
469 if (fsp) {
470 if (!(fsp->access_mask & SEC_DIR_LIST)) {
471 DEBUG(5,("dptr_create: directory %s "
472 "not open for LIST access\n",
473 path));
474 return NT_STATUS_ACCESS_DENIED;
476 dir_hnd = OpenDir_fsp(NULL, conn, fsp, wcard, attr);
477 } else {
478 int ret;
479 bool backup_intent = (req && req->priv_paths);
480 struct smb_filename *smb_dname;
481 NTSTATUS status;
483 smb_dname = synthetic_smb_fname(talloc_tos(), path,
484 NULL, NULL);
485 if (smb_dname == NULL) {
486 return NT_STATUS_NO_MEMORY;
488 if (lp_posix_pathnames()) {
489 ret = SMB_VFS_LSTAT(conn, smb_dname);
490 } else {
491 ret = SMB_VFS_STAT(conn, smb_dname);
493 if (ret == -1) {
494 return map_nt_error_from_unix(errno);
496 if (!S_ISDIR(smb_dname->st.st_ex_mode)) {
497 return NT_STATUS_NOT_A_DIRECTORY;
499 status = smbd_check_access_rights(conn,
500 smb_dname,
501 backup_intent,
502 SEC_DIR_LIST);
503 if (!NT_STATUS_IS_OK(status)) {
504 return status;
506 if (backup_intent) {
507 dir_hnd = open_dir_with_privilege(conn,
508 req,
509 path,
510 wcard,
511 attr);
512 } else {
513 dir_hnd = OpenDir(NULL, conn, path, wcard, attr);
517 if (!dir_hnd) {
518 return map_nt_error_from_unix(errno);
521 if (sconn->searches.dirhandles_open >= MAX_OPEN_DIRECTORIES) {
522 dptr_idleoldest(sconn);
525 dptr = talloc(NULL, struct dptr_struct);
526 if(!dptr) {
527 DEBUG(0,("talloc fail in dptr_create.\n"));
528 TALLOC_FREE(dir_hnd);
529 return NT_STATUS_NO_MEMORY;
532 ZERO_STRUCTP(dptr);
534 dptr->path = talloc_strdup(dptr, path);
535 if (!dptr->path) {
536 TALLOC_FREE(dptr);
537 TALLOC_FREE(dir_hnd);
538 return NT_STATUS_NO_MEMORY;
540 dptr->conn = conn;
541 dptr->dir_hnd = dir_hnd;
542 dptr->spid = spid;
543 dptr->expect_close = expect_close;
544 dptr->wcard = talloc_strdup(dptr, wcard);
545 if (!dptr->wcard) {
546 TALLOC_FREE(dptr);
547 TALLOC_FREE(dir_hnd);
548 return NT_STATUS_NO_MEMORY;
550 if (lp_posix_pathnames() || (wcard[0] == '.' && wcard[1] == 0)) {
551 dptr->has_wild = True;
552 } else {
553 dptr->has_wild = wcard_has_wild;
556 dptr->attr = attr;
558 if (sconn->using_smb2) {
559 goto done;
562 if(old_handle) {
565 * This is an old-style SMBsearch request. Ensure the
566 * value we return will fit in the range 1-255.
569 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 0);
571 if(dptr->dnum == -1 || dptr->dnum > 254) {
574 * Try and close the oldest handle not marked for
575 * expect close in the hope that the client has
576 * finished with that one.
579 dptr_close_oldest(sconn, true);
581 /* Now try again... */
582 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 0);
583 if(dptr->dnum == -1 || dptr->dnum > 254) {
584 DEBUG(0,("dptr_create: returned %d: Error - all old dirptrs in use ?\n", dptr->dnum));
585 TALLOC_FREE(dptr);
586 TALLOC_FREE(dir_hnd);
587 return NT_STATUS_TOO_MANY_OPENED_FILES;
590 } else {
593 * This is a new-style trans2 request. Allocate from
594 * a range that will return 256 - MAX_DIRECTORY_HANDLES.
597 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 255);
599 if(dptr->dnum == -1 || dptr->dnum < 255) {
602 * Try and close the oldest handle close in the hope that
603 * the client has finished with that one. This will only
604 * happen in the case of the Win98 client bug where it leaks
605 * directory handles.
608 dptr_close_oldest(sconn, false);
610 /* Now try again... */
611 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 255);
613 if(dptr->dnum == -1 || dptr->dnum < 255) {
614 DEBUG(0,("dptr_create: returned %d: Error - all new dirptrs in use ?\n", dptr->dnum));
615 TALLOC_FREE(dptr);
616 TALLOC_FREE(dir_hnd);
617 return NT_STATUS_TOO_MANY_OPENED_FILES;
622 bitmap_set(sconn->searches.dptr_bmap, dptr->dnum);
624 dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
626 DLIST_ADD(sconn->searches.dirptrs, dptr);
628 done:
629 DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
630 dptr->dnum,path,expect_close));
632 *dptr_ret = dptr;
634 return NT_STATUS_OK;
638 /****************************************************************************
639 Wrapper functions to access the lower level directory handles.
640 ****************************************************************************/
642 void dptr_CloseDir(files_struct *fsp)
644 if (fsp->dptr) {
646 * The destructor for the struct smb_Dir
647 * (fsp->dptr->dir_hnd) now handles
648 * all resource deallocation.
650 dptr_close_internal(fsp->dptr);
651 fsp->dptr = NULL;
655 void dptr_SeekDir(struct dptr_struct *dptr, long offset)
657 SeekDir(dptr->dir_hnd, offset);
660 long dptr_TellDir(struct dptr_struct *dptr)
662 return TellDir(dptr->dir_hnd);
665 bool dptr_has_wild(struct dptr_struct *dptr)
667 return dptr->has_wild;
670 int dptr_dnum(struct dptr_struct *dptr)
672 return dptr->dnum;
675 bool dptr_get_priv(struct dptr_struct *dptr)
677 return dptr->priv;
680 void dptr_set_priv(struct dptr_struct *dptr)
682 dptr->priv = true;
685 /****************************************************************************
686 Return the next visible file name, skipping veto'd and invisible files.
687 ****************************************************************************/
689 static const char *dptr_normal_ReadDirName(struct dptr_struct *dptr,
690 long *poffset, SMB_STRUCT_STAT *pst,
691 char **ptalloced)
693 /* Normal search for the next file. */
694 const char *name;
695 char *talloced = NULL;
697 while ((name = ReadDirName(dptr->dir_hnd, poffset, pst, &talloced))
698 != NULL) {
699 if (is_visible_file(dptr->conn, dptr->path, name, pst, True)) {
700 *ptalloced = talloced;
701 return name;
703 TALLOC_FREE(talloced);
705 return NULL;
708 /****************************************************************************
709 Return the next visible file name, skipping veto'd and invisible files.
710 ****************************************************************************/
712 static char *dptr_ReadDirName(TALLOC_CTX *ctx,
713 struct dptr_struct *dptr,
714 long *poffset,
715 SMB_STRUCT_STAT *pst)
717 struct smb_filename smb_fname_base;
718 char *name = NULL;
719 const char *name_temp = NULL;
720 char *talloced = NULL;
721 char *pathreal = NULL;
722 char *found_name = NULL;
723 int ret;
725 SET_STAT_INVALID(*pst);
727 if (dptr->has_wild || dptr->did_stat) {
728 name_temp = dptr_normal_ReadDirName(dptr, poffset, pst,
729 &talloced);
730 if (name_temp == NULL) {
731 return NULL;
733 if (talloced != NULL) {
734 return talloc_move(ctx, &talloced);
736 return talloc_strdup(ctx, name_temp);
739 /* If poffset is -1 then we know we returned this name before and we
740 * have no wildcards. We're at the end of the directory. */
741 if (*poffset == END_OF_DIRECTORY_OFFSET) {
742 return NULL;
745 /* We know the stored wcard contains no wildcard characters.
746 * See if we can match with a stat call. If we can't, then set
747 * did_stat to true to ensure we only do this once and keep
748 * searching. */
750 dptr->did_stat = true;
752 /* First check if it should be visible. */
753 if (!is_visible_file(dptr->conn, dptr->path, dptr->wcard,
754 pst, true))
756 /* This only returns false if the file was found, but
757 is explicitly not visible. Set us to end of
758 directory, but return NULL as we know we can't ever
759 find it. */
760 goto ret;
763 if (VALID_STAT(*pst)) {
764 name = talloc_strdup(ctx, dptr->wcard);
765 goto ret;
768 pathreal = talloc_asprintf(ctx,
769 "%s/%s",
770 dptr->path,
771 dptr->wcard);
772 if (!pathreal)
773 return NULL;
775 /* Create an smb_filename with stream_name == NULL. */
776 ZERO_STRUCT(smb_fname_base);
777 smb_fname_base.base_name = pathreal;
779 if (SMB_VFS_STAT(dptr->conn, &smb_fname_base) == 0) {
780 *pst = smb_fname_base.st;
781 name = talloc_strdup(ctx, dptr->wcard);
782 goto clean;
783 } else {
784 /* If we get any other error than ENOENT or ENOTDIR
785 then the file exists we just can't stat it. */
786 if (errno != ENOENT && errno != ENOTDIR) {
787 name = talloc_strdup(ctx, dptr->wcard);
788 goto clean;
792 /* Stat failed. We know this is authoratiative if we are
793 * providing case sensitive semantics or the underlying
794 * filesystem is case sensitive.
796 if (dptr->conn->case_sensitive ||
797 !(dptr->conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH))
799 goto clean;
803 * Try case-insensitive stat if the fs has the ability. This avoids
804 * scanning the whole directory.
806 ret = SMB_VFS_GET_REAL_FILENAME(dptr->conn, dptr->path, dptr->wcard,
807 ctx, &found_name);
808 if (ret == 0) {
809 name = found_name;
810 goto clean;
811 } else if (errno == ENOENT) {
812 /* The case-insensitive lookup was authoritative. */
813 goto clean;
816 TALLOC_FREE(pathreal);
818 name_temp = dptr_normal_ReadDirName(dptr, poffset, pst, &talloced);
819 if (name_temp == NULL) {
820 return NULL;
822 if (talloced != NULL) {
823 return talloc_move(ctx, &talloced);
825 return talloc_strdup(ctx, name_temp);
827 clean:
828 TALLOC_FREE(pathreal);
829 ret:
830 /* We need to set the underlying dir_hnd offset to -1
831 * also as this function is usually called with the
832 * output from TellDir. */
833 dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
834 return name;
837 /****************************************************************************
838 Search for a file by name, skipping veto'ed and not visible files.
839 ****************************************************************************/
841 bool dptr_SearchDir(struct dptr_struct *dptr, const char *name, long *poffset, SMB_STRUCT_STAT *pst)
843 SET_STAT_INVALID(*pst);
845 if (!dptr->has_wild && (dptr->dir_hnd->offset == END_OF_DIRECTORY_OFFSET)) {
846 /* This is a singleton directory and we're already at the end. */
847 *poffset = END_OF_DIRECTORY_OFFSET;
848 return False;
851 return SearchDir(dptr->dir_hnd, name, poffset);
854 /****************************************************************************
855 Initialize variables & state data at the beginning of all search SMB requests.
856 ****************************************************************************/
857 void dptr_init_search_op(struct dptr_struct *dptr)
859 SMB_VFS_INIT_SEARCH_OP(dptr->conn, dptr->dir_hnd->dir);
862 /****************************************************************************
863 Map a native directory offset to a 32-bit cookie.
864 ****************************************************************************/
866 static uint32_t map_dir_offset_to_wire(struct dptr_struct *dptr, long offset)
868 DATA_BLOB key;
869 DATA_BLOB val;
871 if (offset == END_OF_DIRECTORY_OFFSET) {
872 return WIRE_END_OF_DIRECTORY_OFFSET;
873 } else if(offset == START_OF_DIRECTORY_OFFSET) {
874 return WIRE_START_OF_DIRECTORY_OFFSET;
875 } else if (offset == DOT_DOT_DIRECTORY_OFFSET) {
876 return WIRE_DOT_DOT_DIRECTORY_OFFSET;
878 if (sizeof(long) == 4) {
879 /* 32-bit machine. We can cheat... */
880 return (uint32_t)offset;
882 if (dptr->dptr_cache == NULL) {
883 /* Lazy initialize cache. */
884 dptr->dptr_cache = memcache_init(dptr, 0);
885 if (dptr->dptr_cache == NULL) {
886 return WIRE_END_OF_DIRECTORY_OFFSET;
888 } else {
889 /* Have we seen this offset before ? */
890 key.data = (void *)&offset;
891 key.length = sizeof(offset);
892 if (memcache_lookup(dptr->dptr_cache,
893 SMB1_SEARCH_OFFSET_MAP,
894 key,
895 &val)) {
896 uint32_t wire_offset;
897 SMB_ASSERT(val.length == sizeof(wire_offset));
898 memcpy(&wire_offset, val.data, sizeof(wire_offset));
899 DEBUG(10,("found wire %u <-> offset %ld\n",
900 (unsigned int)wire_offset,
901 (long)offset));
902 return wire_offset;
905 /* Allocate a new wire cookie. */
906 do {
907 dptr->counter++;
908 } while (dptr->counter == WIRE_START_OF_DIRECTORY_OFFSET ||
909 dptr->counter == WIRE_END_OF_DIRECTORY_OFFSET ||
910 dptr->counter == WIRE_DOT_DOT_DIRECTORY_OFFSET);
911 /* Store it in the cache. */
912 key.data = (void *)&offset;
913 key.length = sizeof(offset);
914 val.data = (void *)&dptr->counter;
915 val.length = sizeof(dptr->counter); /* MUST BE uint32_t ! */
916 memcache_add(dptr->dptr_cache,
917 SMB1_SEARCH_OFFSET_MAP,
918 key,
919 val);
920 /* And the reverse mapping for lookup from
921 map_wire_to_dir_offset(). */
922 memcache_add(dptr->dptr_cache,
923 SMB1_SEARCH_OFFSET_MAP,
924 val,
925 key);
926 DEBUG(10,("stored wire %u <-> offset %ld\n",
927 (unsigned int)dptr->counter,
928 (long)offset));
929 return dptr->counter;
932 /****************************************************************************
933 Fill the 5 byte server reserved dptr field.
934 ****************************************************************************/
936 bool dptr_fill(struct smbd_server_connection *sconn,
937 char *buf1,unsigned int key)
939 unsigned char *buf = (unsigned char *)buf1;
940 struct dptr_struct *dptr = dptr_get(sconn, key, false);
941 uint32_t wire_offset;
942 if (!dptr) {
943 DEBUG(1,("filling null dirptr %d\n",key));
944 return(False);
946 wire_offset = map_dir_offset_to_wire(dptr,TellDir(dptr->dir_hnd));
947 DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key,
948 (long)dptr->dir_hnd,(int)wire_offset));
949 buf[0] = key;
950 SIVAL(buf,1,wire_offset);
951 return(True);
954 /****************************************************************************
955 Map a 32-bit wire cookie to a native directory offset.
956 ****************************************************************************/
958 static long map_wire_to_dir_offset(struct dptr_struct *dptr, uint32_t wire_offset)
960 DATA_BLOB key;
961 DATA_BLOB val;
963 if (wire_offset == WIRE_END_OF_DIRECTORY_OFFSET) {
964 return END_OF_DIRECTORY_OFFSET;
965 } else if(wire_offset == WIRE_START_OF_DIRECTORY_OFFSET) {
966 return START_OF_DIRECTORY_OFFSET;
967 } else if (wire_offset == WIRE_DOT_DOT_DIRECTORY_OFFSET) {
968 return DOT_DOT_DIRECTORY_OFFSET;
970 if (sizeof(long) == 4) {
971 /* 32-bit machine. We can cheat... */
972 return (long)wire_offset;
974 if (dptr->dptr_cache == NULL) {
975 /* Logic error, cache should be initialized. */
976 return END_OF_DIRECTORY_OFFSET;
978 key.data = (void *)&wire_offset;
979 key.length = sizeof(wire_offset);
980 if (memcache_lookup(dptr->dptr_cache,
981 SMB1_SEARCH_OFFSET_MAP,
982 key,
983 &val)) {
984 /* Found mapping. */
985 long offset;
986 SMB_ASSERT(val.length == sizeof(offset));
987 memcpy(&offset, val.data, sizeof(offset));
988 DEBUG(10,("lookup wire %u <-> offset %ld\n",
989 (unsigned int)wire_offset,
990 (long)offset));
991 return offset;
993 return END_OF_DIRECTORY_OFFSET;
996 /****************************************************************************
997 Fetch the dir ptr and seek it given the 5 byte server field.
998 ****************************************************************************/
1000 struct dptr_struct *dptr_fetch(struct smbd_server_connection *sconn,
1001 char *buf, int *num)
1003 unsigned int key = *(unsigned char *)buf;
1004 struct dptr_struct *dptr = dptr_get(sconn, key, false);
1005 uint32_t wire_offset;
1006 long seekoff;
1008 if (!dptr) {
1009 DEBUG(3,("fetched null dirptr %d\n",key));
1010 return(NULL);
1012 *num = key;
1013 wire_offset = IVAL(buf,1);
1014 seekoff = map_wire_to_dir_offset(dptr, wire_offset);
1015 SeekDir(dptr->dir_hnd,seekoff);
1016 DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
1017 key, dptr->path, (int)seekoff));
1018 return(dptr);
1021 /****************************************************************************
1022 Fetch the dir ptr.
1023 ****************************************************************************/
1025 struct dptr_struct *dptr_fetch_lanman2(struct smbd_server_connection *sconn,
1026 int dptr_num)
1028 struct dptr_struct *dptr = dptr_get(sconn, dptr_num, false);
1030 if (!dptr) {
1031 DEBUG(3,("fetched null dirptr %d\n",dptr_num));
1032 return(NULL);
1034 DEBUG(3,("fetching dirptr %d for path %s\n",dptr_num,dptr->path));
1035 return(dptr);
1038 static bool mangle_mask_match(connection_struct *conn,
1039 const char *filename,
1040 const char *mask)
1042 char mname[13];
1044 if (!name_to_8_3(filename,mname,False,conn->params)) {
1045 return False;
1047 return mask_match_search(mname,mask,False);
1050 bool smbd_dirptr_get_entry(TALLOC_CTX *ctx,
1051 struct dptr_struct *dirptr,
1052 const char *mask,
1053 uint32_t dirtype,
1054 bool dont_descend,
1055 bool ask_sharemode,
1056 bool (*match_fn)(TALLOC_CTX *ctx,
1057 void *private_data,
1058 const char *dname,
1059 const char *mask,
1060 char **_fname),
1061 bool (*mode_fn)(TALLOC_CTX *ctx,
1062 void *private_data,
1063 struct smb_filename *smb_fname,
1064 uint32_t *_mode),
1065 void *private_data,
1066 char **_fname,
1067 struct smb_filename **_smb_fname,
1068 uint32_t *_mode,
1069 long *_prev_offset)
1071 connection_struct *conn = dirptr->conn;
1072 size_t slashlen;
1073 size_t pathlen;
1075 *_smb_fname = NULL;
1076 *_mode = 0;
1078 pathlen = strlen(dirptr->path);
1079 slashlen = ( dirptr->path[pathlen-1] != '/') ? 1 : 0;
1081 while (true) {
1082 long cur_offset;
1083 long prev_offset;
1084 SMB_STRUCT_STAT sbuf = { 0 };
1085 char *dname = NULL;
1086 bool isdots;
1087 char *fname = NULL;
1088 char *pathreal = NULL;
1089 struct smb_filename smb_fname;
1090 uint32_t mode = 0;
1091 bool ok;
1093 cur_offset = dptr_TellDir(dirptr);
1094 prev_offset = cur_offset;
1095 dname = dptr_ReadDirName(ctx, dirptr, &cur_offset, &sbuf);
1097 DEBUG(6,("smbd_dirptr_get_entry: dirptr 0x%lx now at offset %ld\n",
1098 (long)dirptr, cur_offset));
1100 if (dname == NULL) {
1101 return false;
1104 isdots = (ISDOT(dname) || ISDOTDOT(dname));
1105 if (dont_descend && !isdots) {
1106 TALLOC_FREE(dname);
1107 continue;
1111 * fname may get mangled, dname is never mangled.
1112 * Whenever we're accessing the filesystem we use
1113 * pathreal which is composed from dname.
1116 ok = match_fn(ctx, private_data, dname, mask, &fname);
1117 if (!ok) {
1118 TALLOC_FREE(dname);
1119 continue;
1123 * This used to be
1124 * pathreal = talloc_asprintf(ctx, "%s%s%s", dirptr->path,
1125 * needslash?"/":"", dname);
1126 * but this was measurably slower than doing the memcpy.
1129 pathreal = talloc_array(
1130 ctx, char,
1131 pathlen + slashlen + talloc_get_size(dname));
1132 if (!pathreal) {
1133 TALLOC_FREE(dname);
1134 TALLOC_FREE(fname);
1135 return false;
1138 memcpy(pathreal, dirptr->path, pathlen);
1139 pathreal[pathlen] = '/';
1140 memcpy(pathreal + slashlen + pathlen, dname,
1141 talloc_get_size(dname));
1143 /* Create smb_fname with NULL stream_name. */
1144 ZERO_STRUCT(smb_fname);
1145 smb_fname.base_name = pathreal;
1146 smb_fname.st = sbuf;
1148 ok = mode_fn(ctx, private_data, &smb_fname, &mode);
1149 if (!ok) {
1150 TALLOC_FREE(dname);
1151 TALLOC_FREE(fname);
1152 TALLOC_FREE(pathreal);
1153 continue;
1156 if (!dir_check_ftype(mode, dirtype)) {
1157 DEBUG(5,("[%s] attribs 0x%x didn't match 0x%x\n",
1158 fname, (unsigned int)mode, (unsigned int)dirtype));
1159 TALLOC_FREE(dname);
1160 TALLOC_FREE(fname);
1161 TALLOC_FREE(pathreal);
1162 continue;
1165 if (ask_sharemode) {
1166 struct timespec write_time_ts;
1167 struct file_id fileid;
1169 fileid = vfs_file_id_from_sbuf(conn,
1170 &smb_fname.st);
1171 get_file_infos(fileid, 0, NULL, &write_time_ts);
1172 if (!null_timespec(write_time_ts)) {
1173 update_stat_ex_mtime(&smb_fname.st,
1174 write_time_ts);
1178 DEBUG(3,("smbd_dirptr_get_entry mask=[%s] found %s "
1179 "fname=%s (%s)\n",
1180 mask, smb_fname_str_dbg(&smb_fname),
1181 dname, fname));
1183 DirCacheAdd(dirptr->dir_hnd, dname, cur_offset);
1185 TALLOC_FREE(dname);
1187 *_smb_fname = cp_smb_filename(ctx, &smb_fname);
1188 TALLOC_FREE(pathreal);
1189 if (*_smb_fname == NULL) {
1190 return false;
1192 *_fname = fname;
1193 *_mode = mode;
1194 *_prev_offset = prev_offset;
1196 return true;
1199 return false;
1202 /****************************************************************************
1203 Get an 8.3 directory entry.
1204 ****************************************************************************/
1206 static bool smbd_dirptr_8_3_match_fn(TALLOC_CTX *ctx,
1207 void *private_data,
1208 const char *dname,
1209 const char *mask,
1210 char **_fname)
1212 connection_struct *conn = (connection_struct *)private_data;
1214 if ((strcmp(mask,"*.*") == 0) ||
1215 mask_match_search(dname, mask, false) ||
1216 mangle_mask_match(conn, dname, mask)) {
1217 char mname[13];
1218 const char *fname;
1220 * Ensure we can push the original name as UCS2. If
1221 * not, then just don't return this name.
1223 NTSTATUS status;
1224 size_t ret_len = 0;
1225 size_t len = (strlen(dname) + 2) * 4; /* Allow enough space. */
1226 uint8_t *tmp = talloc_array(talloc_tos(),
1227 uint8,
1228 len);
1230 status = srvstr_push(NULL,
1231 FLAGS2_UNICODE_STRINGS,
1232 tmp,
1233 dname,
1234 len,
1235 STR_TERMINATE,
1236 &ret_len);
1238 TALLOC_FREE(tmp);
1240 if (!NT_STATUS_IS_OK(status)) {
1241 return false;
1244 if (!mangle_is_8_3(dname, false, conn->params)) {
1245 bool ok = name_to_8_3(dname, mname, false,
1246 conn->params);
1247 if (!ok) {
1248 return false;
1250 fname = mname;
1251 } else {
1252 fname = dname;
1255 *_fname = talloc_strdup(ctx, fname);
1256 if (*_fname == NULL) {
1257 return false;
1260 return true;
1263 return false;
1266 static bool smbd_dirptr_8_3_mode_fn(TALLOC_CTX *ctx,
1267 void *private_data,
1268 struct smb_filename *smb_fname,
1269 uint32_t *_mode)
1271 connection_struct *conn = (connection_struct *)private_data;
1273 if (!VALID_STAT(smb_fname->st)) {
1274 if ((SMB_VFS_STAT(conn, smb_fname)) != 0) {
1275 DEBUG(5,("smbd_dirptr_8_3_mode_fn: "
1276 "Couldn't stat [%s]. Error "
1277 "= %s\n",
1278 smb_fname_str_dbg(smb_fname),
1279 strerror(errno)));
1280 return false;
1284 *_mode = dos_mode(conn, smb_fname);
1285 return true;
1288 bool get_dir_entry(TALLOC_CTX *ctx,
1289 struct dptr_struct *dirptr,
1290 const char *mask,
1291 uint32_t dirtype,
1292 char **_fname,
1293 off_t *_size,
1294 uint32_t *_mode,
1295 struct timespec *_date,
1296 bool check_descend,
1297 bool ask_sharemode)
1299 connection_struct *conn = dirptr->conn;
1300 char *fname = NULL;
1301 struct smb_filename *smb_fname = NULL;
1302 uint32_t mode = 0;
1303 long prev_offset;
1304 bool ok;
1306 ok = smbd_dirptr_get_entry(ctx,
1307 dirptr,
1308 mask,
1309 dirtype,
1310 check_descend,
1311 ask_sharemode,
1312 smbd_dirptr_8_3_match_fn,
1313 smbd_dirptr_8_3_mode_fn,
1314 conn,
1315 &fname,
1316 &smb_fname,
1317 &mode,
1318 &prev_offset);
1319 if (!ok) {
1320 return false;
1323 *_fname = talloc_move(ctx, &fname);
1324 *_size = smb_fname->st.st_ex_size;
1325 *_mode = mode;
1326 *_date = smb_fname->st.st_ex_mtime;
1327 TALLOC_FREE(smb_fname);
1328 return true;
1331 /*******************************************************************
1332 Check to see if a user can read a file. This is only approximate,
1333 it is used as part of the "hide unreadable" option. Don't
1334 use it for anything security sensitive.
1335 ********************************************************************/
1337 static bool user_can_read_file(connection_struct *conn,
1338 struct smb_filename *smb_fname)
1341 * Never hide files from the root user.
1342 * We use (uid_t)0 here not sec_initial_uid()
1343 * as make test uses a single user context.
1346 if (get_current_uid(conn) == (uid_t)0) {
1347 return True;
1350 return NT_STATUS_IS_OK(smbd_check_access_rights(conn,
1351 smb_fname,
1352 false,
1353 FILE_READ_DATA));
1356 /*******************************************************************
1357 Check to see if a user can write a file (and only files, we do not
1358 check dirs on this one). This is only approximate,
1359 it is used as part of the "hide unwriteable" option. Don't
1360 use it for anything security sensitive.
1361 ********************************************************************/
1363 static bool user_can_write_file(connection_struct *conn,
1364 const struct smb_filename *smb_fname)
1367 * Never hide files from the root user.
1368 * We use (uid_t)0 here not sec_initial_uid()
1369 * as make test uses a single user context.
1372 if (get_current_uid(conn) == (uid_t)0) {
1373 return True;
1376 SMB_ASSERT(VALID_STAT(smb_fname->st));
1378 /* Pseudo-open the file */
1380 if(S_ISDIR(smb_fname->st.st_ex_mode)) {
1381 return True;
1384 return can_write_to_file(conn, smb_fname);
1387 /*******************************************************************
1388 Is a file a "special" type ?
1389 ********************************************************************/
1391 static bool file_is_special(connection_struct *conn,
1392 const struct smb_filename *smb_fname)
1395 * Never hide files from the root user.
1396 * We use (uid_t)0 here not sec_initial_uid()
1397 * as make test uses a single user context.
1400 if (get_current_uid(conn) == (uid_t)0) {
1401 return False;
1404 SMB_ASSERT(VALID_STAT(smb_fname->st));
1406 if (S_ISREG(smb_fname->st.st_ex_mode) ||
1407 S_ISDIR(smb_fname->st.st_ex_mode) ||
1408 S_ISLNK(smb_fname->st.st_ex_mode))
1409 return False;
1411 return True;
1414 /*******************************************************************
1415 Should the file be seen by the client?
1416 NOTE: A successful return is no guarantee of the file's existence.
1417 ********************************************************************/
1419 bool is_visible_file(connection_struct *conn, const char *dir_path,
1420 const char *name, SMB_STRUCT_STAT *pst, bool use_veto)
1422 bool hide_unreadable = lp_hide_unreadable(SNUM(conn));
1423 bool hide_unwriteable = lp_hide_unwriteable_files(SNUM(conn));
1424 bool hide_special = lp_hide_special_files(SNUM(conn));
1425 char *entry = NULL;
1426 struct smb_filename *smb_fname_base = NULL;
1427 bool ret = false;
1429 if ((strcmp(".",name) == 0) || (strcmp("..",name) == 0)) {
1430 return True; /* . and .. are always visible. */
1433 /* If it's a vetoed file, pretend it doesn't even exist */
1434 if (use_veto && IS_VETO_PATH(conn, name)) {
1435 DEBUG(10,("is_visible_file: file %s is vetoed.\n", name ));
1436 return False;
1439 if (hide_unreadable || hide_unwriteable || hide_special) {
1440 entry = talloc_asprintf(talloc_tos(), "%s/%s", dir_path, name);
1441 if (!entry) {
1442 ret = false;
1443 goto out;
1446 /* Create an smb_filename with stream_name == NULL. */
1447 smb_fname_base = synthetic_smb_fname(talloc_tos(), entry, NULL,
1448 pst);
1449 if (smb_fname_base == NULL) {
1450 ret = false;
1451 goto out;
1454 /* If the file name does not exist, there's no point checking
1455 * the configuration options. We succeed, on the basis that the
1456 * checks *might* have passed if the file was present.
1458 if (!VALID_STAT(*pst)) {
1459 if (SMB_VFS_STAT(conn, smb_fname_base) != 0) {
1460 ret = true;
1461 goto out;
1462 } else {
1463 *pst = smb_fname_base->st;
1467 /* Honour _hide unreadable_ option */
1468 if (hide_unreadable &&
1469 !user_can_read_file(conn, smb_fname_base)) {
1470 DEBUG(10,("is_visible_file: file %s is unreadable.\n",
1471 entry ));
1472 ret = false;
1473 goto out;
1475 /* Honour _hide unwriteable_ option */
1476 if (hide_unwriteable && !user_can_write_file(conn,
1477 smb_fname_base)) {
1478 DEBUG(10,("is_visible_file: file %s is unwritable.\n",
1479 entry ));
1480 ret = false;
1481 goto out;
1483 /* Honour _hide_special_ option */
1484 if (hide_special && file_is_special(conn, smb_fname_base)) {
1485 DEBUG(10,("is_visible_file: file %s is special.\n",
1486 entry ));
1487 ret = false;
1488 goto out;
1492 ret = true;
1493 out:
1494 TALLOC_FREE(smb_fname_base);
1495 TALLOC_FREE(entry);
1496 return ret;
1499 static int smb_Dir_destructor(struct smb_Dir *dirp)
1501 if (dirp->dir != NULL) {
1502 SMB_VFS_CLOSEDIR(dirp->conn,dirp->dir);
1503 if (dirp->fsp != NULL) {
1505 * The SMB_VFS_CLOSEDIR above
1506 * closes the underlying fd inside
1507 * dirp->fsp.
1509 dirp->fsp->fh->fd = -1;
1510 if (dirp->fsp->dptr != NULL) {
1511 SMB_ASSERT(dirp->fsp->dptr->dir_hnd == dirp);
1512 dirp->fsp->dptr->dir_hnd = NULL;
1514 dirp->fsp = NULL;
1517 if (dirp->conn->sconn && !dirp->conn->sconn->using_smb2) {
1518 dirp->conn->sconn->searches.dirhandles_open--;
1520 return 0;
1523 /*******************************************************************
1524 Open a directory.
1525 ********************************************************************/
1527 struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn,
1528 const char *name,
1529 const char *mask,
1530 uint32 attr)
1532 struct smb_Dir *dirp = talloc_zero(mem_ctx, struct smb_Dir);
1533 struct smbd_server_connection *sconn = conn->sconn;
1535 if (!dirp) {
1536 return NULL;
1539 dirp->conn = conn;
1540 dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
1542 dirp->dir_path = talloc_strdup(dirp, name);
1543 if (!dirp->dir_path) {
1544 errno = ENOMEM;
1545 goto fail;
1548 if (sconn && !sconn->using_smb2) {
1549 sconn->searches.dirhandles_open++;
1551 talloc_set_destructor(dirp, smb_Dir_destructor);
1553 dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path, mask, attr);
1554 if (!dirp->dir) {
1555 DEBUG(5,("OpenDir: Can't open %s. %s\n", dirp->dir_path,
1556 strerror(errno) ));
1557 goto fail;
1560 return dirp;
1562 fail:
1563 TALLOC_FREE(dirp);
1564 return NULL;
1567 /*******************************************************************
1568 Open a directory from an fsp.
1569 ********************************************************************/
1571 static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn,
1572 files_struct *fsp,
1573 const char *mask,
1574 uint32 attr)
1576 struct smb_Dir *dirp = talloc_zero(mem_ctx, struct smb_Dir);
1577 struct smbd_server_connection *sconn = conn->sconn;
1579 if (!dirp) {
1580 return NULL;
1583 dirp->conn = conn;
1584 dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
1586 dirp->dir_path = talloc_strdup(dirp, fsp->fsp_name->base_name);
1587 if (!dirp->dir_path) {
1588 errno = ENOMEM;
1589 goto fail;
1592 if (sconn && !sconn->using_smb2) {
1593 sconn->searches.dirhandles_open++;
1595 talloc_set_destructor(dirp, smb_Dir_destructor);
1597 if (fsp->is_directory && fsp->fh->fd != -1) {
1598 dirp->dir = SMB_VFS_FDOPENDIR(fsp, mask, attr);
1599 if (dirp->dir != NULL) {
1600 dirp->fsp = fsp;
1601 } else {
1602 DEBUG(10,("OpenDir_fsp: SMB_VFS_FDOPENDIR on %s returned "
1603 "NULL (%s)\n",
1604 dirp->dir_path,
1605 strerror(errno)));
1606 if (errno != ENOSYS) {
1607 return NULL;
1612 if (dirp->dir == NULL) {
1613 /* FDOPENDIR didn't work. Use OPENDIR instead. */
1614 dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path, mask, attr);
1617 if (!dirp->dir) {
1618 DEBUG(5,("OpenDir_fsp: Can't open %s. %s\n", dirp->dir_path,
1619 strerror(errno) ));
1620 goto fail;
1623 return dirp;
1625 fail:
1626 TALLOC_FREE(dirp);
1627 return NULL;
1631 /*******************************************************************
1632 Read from a directory.
1633 Return directory entry, current offset, and optional stat information.
1634 Don't check for veto or invisible files.
1635 ********************************************************************/
1637 const char *ReadDirName(struct smb_Dir *dirp, long *poffset,
1638 SMB_STRUCT_STAT *sbuf, char **ptalloced)
1640 const char *n;
1641 char *talloced = NULL;
1642 connection_struct *conn = dirp->conn;
1644 /* Cheat to allow . and .. to be the first entries returned. */
1645 if (((*poffset == START_OF_DIRECTORY_OFFSET) ||
1646 (*poffset == DOT_DOT_DIRECTORY_OFFSET)) && (dirp->file_number < 2))
1648 if (dirp->file_number == 0) {
1649 n = ".";
1650 *poffset = dirp->offset = START_OF_DIRECTORY_OFFSET;
1651 } else {
1652 n = "..";
1653 *poffset = dirp->offset = DOT_DOT_DIRECTORY_OFFSET;
1655 dirp->file_number++;
1656 *ptalloced = NULL;
1657 return n;
1658 } else if (*poffset == END_OF_DIRECTORY_OFFSET) {
1659 *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1660 return NULL;
1661 } else {
1662 /* A real offset, seek to it. */
1663 SeekDir(dirp, *poffset);
1666 while ((n = vfs_readdirname(conn, dirp->dir, sbuf, &talloced))) {
1667 /* Ignore . and .. - we've already returned them. */
1668 if (*n == '.') {
1669 if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) {
1670 TALLOC_FREE(talloced);
1671 continue;
1674 *poffset = dirp->offset = SMB_VFS_TELLDIR(conn, dirp->dir);
1675 *ptalloced = talloced;
1676 dirp->file_number++;
1677 return n;
1679 *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1680 *ptalloced = NULL;
1681 return NULL;
1684 /*******************************************************************
1685 Rewind to the start.
1686 ********************************************************************/
1688 void RewindDir(struct smb_Dir *dirp, long *poffset)
1690 SMB_VFS_REWINDDIR(dirp->conn, dirp->dir);
1691 dirp->file_number = 0;
1692 dirp->offset = START_OF_DIRECTORY_OFFSET;
1693 *poffset = START_OF_DIRECTORY_OFFSET;
1696 /*******************************************************************
1697 Seek a dir.
1698 ********************************************************************/
1700 void SeekDir(struct smb_Dir *dirp, long offset)
1702 if (offset != dirp->offset) {
1703 if (offset == START_OF_DIRECTORY_OFFSET) {
1704 RewindDir(dirp, &offset);
1706 * Ok we should really set the file number here
1707 * to 1 to enable ".." to be returned next. Trouble
1708 * is I'm worried about callers using SeekDir(dirp,0)
1709 * as equivalent to RewindDir(). So leave this alone
1710 * for now.
1712 } else if (offset == DOT_DOT_DIRECTORY_OFFSET) {
1713 RewindDir(dirp, &offset);
1715 * Set the file number to 2 - we want to get the first
1716 * real file entry (the one we return after "..")
1717 * on the next ReadDir.
1719 dirp->file_number = 2;
1720 } else if (offset == END_OF_DIRECTORY_OFFSET) {
1721 ; /* Don't seek in this case. */
1722 } else {
1723 SMB_VFS_SEEKDIR(dirp->conn, dirp->dir, offset);
1725 dirp->offset = offset;
1729 /*******************************************************************
1730 Tell a dir position.
1731 ********************************************************************/
1733 long TellDir(struct smb_Dir *dirp)
1735 return(dirp->offset);
1738 /*******************************************************************
1739 Add an entry into the dcache.
1740 ********************************************************************/
1742 static void DirCacheAdd(struct smb_Dir *dirp, const char *name, long offset)
1744 struct name_cache_entry *e;
1746 if (dirp->name_cache_size == 0) {
1747 return;
1750 if (dirp->name_cache == NULL) {
1751 dirp->name_cache = talloc_zero_array(
1752 dirp, struct name_cache_entry, dirp->name_cache_size);
1754 if (dirp->name_cache == NULL) {
1755 return;
1759 dirp->name_cache_index = (dirp->name_cache_index+1) %
1760 dirp->name_cache_size;
1761 e = &dirp->name_cache[dirp->name_cache_index];
1762 TALLOC_FREE(e->name);
1763 e->name = talloc_strdup(dirp, name);
1764 e->offset = offset;
1767 /*******************************************************************
1768 Find an entry by name. Leave us at the offset after it.
1769 Don't check for veto or invisible files.
1770 ********************************************************************/
1772 bool SearchDir(struct smb_Dir *dirp, const char *name, long *poffset)
1774 int i;
1775 const char *entry = NULL;
1776 char *talloced = NULL;
1777 connection_struct *conn = dirp->conn;
1779 /* Search back in the name cache. */
1780 if (dirp->name_cache_size && dirp->name_cache) {
1781 for (i = dirp->name_cache_index; i >= 0; i--) {
1782 struct name_cache_entry *e = &dirp->name_cache[i];
1783 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1784 *poffset = e->offset;
1785 SeekDir(dirp, e->offset);
1786 return True;
1789 for (i = dirp->name_cache_size - 1; i > dirp->name_cache_index; i--) {
1790 struct name_cache_entry *e = &dirp->name_cache[i];
1791 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1792 *poffset = e->offset;
1793 SeekDir(dirp, e->offset);
1794 return True;
1799 /* Not found in the name cache. Rewind directory and start from scratch. */
1800 SMB_VFS_REWINDDIR(conn, dirp->dir);
1801 dirp->file_number = 0;
1802 *poffset = START_OF_DIRECTORY_OFFSET;
1803 while ((entry = ReadDirName(dirp, poffset, NULL, &talloced))) {
1804 if (conn->case_sensitive ? (strcmp(entry, name) == 0) : strequal(entry, name)) {
1805 TALLOC_FREE(talloced);
1806 return True;
1808 TALLOC_FREE(talloced);
1810 return False;
1813 struct files_below_forall_state {
1814 char *dirpath;
1815 size_t dirpath_len;
1816 int (*fn)(struct file_id fid, const struct share_mode_data *data,
1817 void *private_data);
1818 void *private_data;
1821 static int files_below_forall_fn(struct file_id fid,
1822 const struct share_mode_data *data,
1823 void *private_data)
1825 struct files_below_forall_state *state = private_data;
1826 char tmpbuf[PATH_MAX];
1827 char *fullpath, *to_free;
1828 size_t len;
1830 len = full_path_tos(data->servicepath, data->base_name,
1831 tmpbuf, sizeof(tmpbuf),
1832 &fullpath, &to_free);
1833 if (len == -1) {
1834 return 0;
1836 if (state->dirpath_len >= len) {
1838 * Filter files above dirpath
1840 return 0;
1842 if (fullpath[state->dirpath_len] != '/') {
1844 * Filter file that don't have a path separator at the end of
1845 * dirpath's length
1847 return 0;
1850 if (memcmp(state->dirpath, fullpath, len) != 0) {
1852 * Not a parent
1854 return 0;
1857 return state->fn(fid, data, private_data);
1860 static int files_below_forall(connection_struct *conn,
1861 const struct smb_filename *dir_name,
1862 int (*fn)(struct file_id fid,
1863 const struct share_mode_data *data,
1864 void *private_data),
1865 void *private_data)
1867 struct files_below_forall_state state = {};
1868 int ret;
1869 char tmpbuf[PATH_MAX];
1870 char *to_free;
1872 state.dirpath_len = full_path_tos(conn->connectpath,
1873 dir_name->base_name,
1874 tmpbuf, sizeof(tmpbuf),
1875 &state.dirpath, &to_free);
1876 if (state.dirpath_len == -1) {
1877 return -1;
1881 ret = share_mode_forall(files_below_forall_fn, &state);
1882 TALLOC_FREE(to_free);
1883 return ret;
1886 struct have_file_open_below_state {
1887 bool found_one;
1890 static int have_file_open_below_fn(struct file_id fid,
1891 const struct share_mode_data *data,
1892 void *private_data)
1894 struct have_file_open_below_state *state = private_data;
1895 state->found_one = true;
1896 return 1;
1899 static bool have_file_open_below(connection_struct *conn,
1900 const struct smb_filename *name)
1902 struct have_file_open_below_state state = {};
1903 int ret;
1905 if (!VALID_STAT(name->st)) {
1906 return false;
1908 if (!S_ISDIR(name->st.st_ex_mode)) {
1909 return false;
1912 ret = files_below_forall(conn, name, have_file_open_below_fn, &state);
1913 if (ret == -1) {
1914 return false;
1917 return state.found_one;
1920 /*****************************************************************
1921 Is this directory empty ?
1922 *****************************************************************/
1924 NTSTATUS can_delete_directory_fsp(files_struct *fsp)
1926 NTSTATUS status = NT_STATUS_OK;
1927 long dirpos = 0;
1928 const char *dname = NULL;
1929 const char *dirname = fsp->fsp_name->base_name;
1930 char *talloced = NULL;
1931 SMB_STRUCT_STAT st;
1932 struct connection_struct *conn = fsp->conn;
1933 struct smb_Dir *dir_hnd = OpenDir_fsp(talloc_tos(),
1934 conn,
1935 fsp,
1936 NULL,
1939 if (!dir_hnd) {
1940 return map_nt_error_from_unix(errno);
1943 while ((dname = ReadDirName(dir_hnd, &dirpos, &st, &talloced))) {
1944 /* Quick check for "." and ".." */
1945 if (dname[0] == '.') {
1946 if (!dname[1] || (dname[1] == '.' && !dname[2])) {
1947 TALLOC_FREE(talloced);
1948 continue;
1952 if (!is_visible_file(conn, dirname, dname, &st, True)) {
1953 TALLOC_FREE(talloced);
1954 continue;
1957 DEBUG(10,("got name %s - can't delete\n",
1958 dname ));
1959 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
1960 break;
1962 TALLOC_FREE(talloced);
1963 TALLOC_FREE(dir_hnd);
1965 if (!NT_STATUS_IS_OK(status)) {
1966 return status;
1969 if (!lp_posix_pathnames() &&
1970 lp_strict_rename(SNUM(conn)) &&
1971 have_file_open_below(fsp->conn, fsp->fsp_name))
1973 return NT_STATUS_ACCESS_DENIED;
1976 return NT_STATUS_OK;