Revert "buildtools: Rename perl vendorarch configure option."
[Samba.git] / source3 / smbd / dir.c
blob3c3f662001f23dbe8200237474889b622052347d
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"
30 This module implements directory related functions for Samba.
33 /* "Special" directory offsets. */
34 #define END_OF_DIRECTORY_OFFSET ((long)-1)
35 #define START_OF_DIRECTORY_OFFSET ((long)0)
36 #define DOT_DOT_DIRECTORY_OFFSET ((long)0x80000000)
38 /* "Special" directory offsets in 32-bit wire format. */
39 #define WIRE_END_OF_DIRECTORY_OFFSET ((uint32_t)0xFFFFFFFF)
40 #define WIRE_START_OF_DIRECTORY_OFFSET ((uint32_t)0)
41 #define WIRE_DOT_DOT_DIRECTORY_OFFSET ((uint32_t)0x80000000)
43 /* Make directory handle internals available. */
45 struct name_cache_entry {
46 char *name;
47 long offset;
50 struct smb_Dir {
51 connection_struct *conn;
52 DIR *dir;
53 long offset;
54 char *dir_path;
55 size_t name_cache_size;
56 struct name_cache_entry *name_cache;
57 unsigned int name_cache_index;
58 unsigned int file_number;
59 files_struct *fsp; /* Back pointer to containing fsp, only
60 set from OpenDir_fsp(). */
63 struct dptr_struct {
64 struct dptr_struct *next, *prev;
65 int dnum;
66 uint16 spid;
67 struct connection_struct *conn;
68 struct smb_Dir *dir_hnd;
69 bool expect_close;
70 char *wcard;
71 uint32 attr;
72 char *path;
73 bool has_wild; /* Set to true if the wcard entry has MS wildcard characters in it. */
74 bool did_stat; /* Optimisation for non-wcard searches. */
75 bool priv; /* Directory handle opened with privilege. */
76 uint32_t counter;
77 struct memcache *dptr_cache;
80 static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn,
81 files_struct *fsp,
82 const char *mask,
83 uint32 attr);
85 static void DirCacheAdd(struct smb_Dir *dirp, const char *name, long offset);
87 #define INVALID_DPTR_KEY (-3)
89 /****************************************************************************
90 Make a dir struct.
91 ****************************************************************************/
93 bool make_dir_struct(TALLOC_CTX *ctx,
94 char *buf,
95 const char *mask,
96 const char *fname,
97 off_t size,
98 uint32 mode,
99 time_t date,
100 bool uc)
102 char *p;
103 char *mask2 = talloc_strdup(ctx, mask);
105 if (!mask2) {
106 return False;
109 if ((mode & FILE_ATTRIBUTE_DIRECTORY) != 0) {
110 size = 0;
113 memset(buf+1,' ',11);
114 if ((p = strchr_m(mask2,'.')) != NULL) {
115 *p = 0;
116 push_ascii(buf+1,mask2,8, 0);
117 push_ascii(buf+9,p+1,3, 0);
118 *p = '.';
119 } else {
120 push_ascii(buf+1,mask2,11, 0);
123 memset(buf+21,'\0',DIR_STRUCT_SIZE-21);
124 SCVAL(buf,21,mode);
125 srv_put_dos_date(buf,22,date);
126 SSVAL(buf,26,size & 0xFFFF);
127 SSVAL(buf,28,(size >> 16)&0xFFFF);
128 /* We only uppercase if FLAGS2_LONG_PATH_COMPONENTS is zero in the input buf.
129 Strange, but verified on W2K3. Needed for OS/2. JRA. */
130 push_ascii(buf+30,fname,12, uc ? STR_UPPER : 0);
131 DEBUG(8,("put name [%s] from [%s] into dir struct\n",buf+30, fname));
132 return True;
135 /****************************************************************************
136 Initialise the dir bitmap.
137 ****************************************************************************/
139 bool init_dptrs(struct smbd_server_connection *sconn)
141 if (sconn->searches.dptr_bmap) {
142 return true;
145 sconn->searches.dptr_bmap = bitmap_talloc(
146 sconn, MAX_DIRECTORY_HANDLES);
148 if (sconn->searches.dptr_bmap == NULL) {
149 return false;
152 return true;
155 /****************************************************************************
156 Idle a dptr - the directory is closed but the control info is kept.
157 ****************************************************************************/
159 static void dptr_idle(struct dptr_struct *dptr)
161 if (dptr->dir_hnd) {
162 DEBUG(4,("Idling dptr dnum %d\n",dptr->dnum));
163 TALLOC_FREE(dptr->dir_hnd);
164 TALLOC_FREE(dptr->dptr_cache);
165 dptr->counter = 0;
169 /****************************************************************************
170 Idle the oldest dptr.
171 ****************************************************************************/
173 static void dptr_idleoldest(struct smbd_server_connection *sconn)
175 struct dptr_struct *dptr;
178 * Go to the end of the list.
180 dptr = DLIST_TAIL(sconn->searches.dirptrs);
182 if(!dptr) {
183 DEBUG(0,("No dptrs available to idle ?\n"));
184 return;
188 * Idle the oldest pointer.
191 for(; dptr; dptr = DLIST_PREV(dptr)) {
192 if (dptr->dir_hnd) {
193 dptr_idle(dptr);
194 return;
199 /****************************************************************************
200 Get the struct dptr_struct for a dir index.
201 ****************************************************************************/
203 static struct dptr_struct *dptr_get(struct smbd_server_connection *sconn,
204 int key, bool forclose)
206 struct dptr_struct *dptr;
208 for(dptr = sconn->searches.dirptrs; dptr; dptr = dptr->next) {
209 if(dptr->dnum == key) {
210 if (!forclose && !dptr->dir_hnd) {
211 if (sconn->searches.dirhandles_open >= MAX_OPEN_DIRECTORIES)
212 dptr_idleoldest(sconn);
213 DEBUG(4,("dptr_get: Reopening dptr key %d\n",key));
214 if (!(dptr->dir_hnd = OpenDir(
215 NULL, dptr->conn, dptr->path,
216 dptr->wcard, dptr->attr))) {
217 DEBUG(4,("dptr_get: Failed to open %s (%s)\n",dptr->path,
218 strerror(errno)));
219 return NULL;
222 DLIST_PROMOTE(sconn->searches.dirptrs,dptr);
223 return dptr;
226 return(NULL);
229 /****************************************************************************
230 Get the dir path for a dir index.
231 ****************************************************************************/
233 const char *dptr_path(struct smbd_server_connection *sconn, int key)
235 struct dptr_struct *dptr = dptr_get(sconn, key, false);
236 if (dptr)
237 return(dptr->path);
238 return(NULL);
241 /****************************************************************************
242 Get the dir wcard for a dir index.
243 ****************************************************************************/
245 const char *dptr_wcard(struct smbd_server_connection *sconn, int key)
247 struct dptr_struct *dptr = dptr_get(sconn, key, false);
248 if (dptr)
249 return(dptr->wcard);
250 return(NULL);
253 /****************************************************************************
254 Get the dir attrib for a dir index.
255 ****************************************************************************/
257 uint16 dptr_attr(struct smbd_server_connection *sconn, int key)
259 struct dptr_struct *dptr = dptr_get(sconn, key, false);
260 if (dptr)
261 return(dptr->attr);
262 return(0);
265 /****************************************************************************
266 Close a dptr (internal func).
267 ****************************************************************************/
269 static void dptr_close_internal(struct dptr_struct *dptr)
271 struct smbd_server_connection *sconn = dptr->conn->sconn;
273 DEBUG(4,("closing dptr key %d\n",dptr->dnum));
275 if (sconn == NULL) {
276 goto done;
279 if (sconn->using_smb2) {
280 goto done;
283 DLIST_REMOVE(sconn->searches.dirptrs, dptr);
286 * Free the dnum in the bitmap. Remember the dnum value is always
287 * biased by one with respect to the bitmap.
290 if (!bitmap_query(sconn->searches.dptr_bmap, dptr->dnum - 1)) {
291 DEBUG(0,("dptr_close_internal : Error - closing dnum = %d and bitmap not set !\n",
292 dptr->dnum ));
295 bitmap_clear(sconn->searches.dptr_bmap, dptr->dnum - 1);
297 done:
298 TALLOC_FREE(dptr->dir_hnd);
299 TALLOC_FREE(dptr);
302 /****************************************************************************
303 Close a dptr given a key.
304 ****************************************************************************/
306 void dptr_close(struct smbd_server_connection *sconn, int *key)
308 struct dptr_struct *dptr;
310 if(*key == INVALID_DPTR_KEY)
311 return;
313 /* OS/2 seems to use -1 to indicate "close all directories" */
314 if (*key == -1) {
315 struct dptr_struct *next;
316 for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
317 next = dptr->next;
318 dptr_close_internal(dptr);
320 *key = INVALID_DPTR_KEY;
321 return;
324 dptr = dptr_get(sconn, *key, true);
326 if (!dptr) {
327 DEBUG(0,("Invalid key %d given to dptr_close\n", *key));
328 return;
331 dptr_close_internal(dptr);
333 *key = INVALID_DPTR_KEY;
336 /****************************************************************************
337 Close all dptrs for a cnum.
338 ****************************************************************************/
340 void dptr_closecnum(connection_struct *conn)
342 struct dptr_struct *dptr, *next;
343 struct smbd_server_connection *sconn = conn->sconn;
345 if (sconn == NULL) {
346 return;
349 for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
350 next = dptr->next;
351 if (dptr->conn == conn) {
352 dptr_close_internal(dptr);
357 /****************************************************************************
358 Idle all dptrs for a cnum.
359 ****************************************************************************/
361 void dptr_idlecnum(connection_struct *conn)
363 struct dptr_struct *dptr;
364 struct smbd_server_connection *sconn = conn->sconn;
366 if (sconn == NULL) {
367 return;
370 for(dptr = sconn->searches.dirptrs; dptr; dptr = dptr->next) {
371 if (dptr->conn == conn && dptr->dir_hnd) {
372 dptr_idle(dptr);
377 /****************************************************************************
378 Close a dptr that matches a given path, only if it matches the spid also.
379 ****************************************************************************/
381 void dptr_closepath(struct smbd_server_connection *sconn,
382 char *path,uint16 spid)
384 struct dptr_struct *dptr, *next;
385 for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
386 next = dptr->next;
387 if (spid == dptr->spid && strequal(dptr->path,path))
388 dptr_close_internal(dptr);
392 /****************************************************************************
393 Try and close the oldest handle not marked for
394 expect close in the hope that the client has
395 finished with that one.
396 ****************************************************************************/
398 static void dptr_close_oldest(struct smbd_server_connection *sconn,
399 bool old)
401 struct dptr_struct *dptr;
404 * Go to the end of the list.
406 for(dptr = sconn->searches.dirptrs; dptr && dptr->next; dptr = dptr->next)
409 if(!dptr) {
410 DEBUG(0,("No old dptrs available to close oldest ?\n"));
411 return;
415 * If 'old' is true, close the oldest oldhandle dnum (ie. 1 < dnum < 256) that
416 * does not have expect_close set. If 'old' is false, close
417 * one of the new dnum handles.
420 for(; dptr; dptr = DLIST_PREV(dptr)) {
421 if ((old && (dptr->dnum < 256) && !dptr->expect_close) ||
422 (!old && (dptr->dnum > 255))) {
423 dptr_close_internal(dptr);
424 return;
429 /****************************************************************************
430 Safely do an OpenDir as root, ensuring we're in the right place.
431 ****************************************************************************/
433 static struct smb_Dir *open_dir_with_privilege(connection_struct *conn,
434 struct smb_request *req,
435 const char *path,
436 const char *wcard,
437 uint32_t attr)
439 struct smb_Dir *dir_hnd = NULL;
440 struct smb_filename *smb_fname_cwd;
441 char *saved_dir = vfs_GetWd(talloc_tos(), conn);
442 struct privilege_paths *priv_paths = req->priv_paths;
443 int ret;
445 if (saved_dir == NULL) {
446 return NULL;
449 if (vfs_ChDir(conn, path) == -1) {
450 return NULL;
453 /* Now check the stat value is the same. */
454 smb_fname_cwd = synthetic_smb_fname(talloc_tos(), ".", NULL, NULL);
456 if (smb_fname_cwd == NULL) {
457 goto out;
459 ret = SMB_VFS_STAT(conn, smb_fname_cwd);
460 if (ret != 0) {
461 goto out;
464 if (!check_same_stat(&smb_fname_cwd->st, &priv_paths->parent_name.st)) {
465 DEBUG(0,("open_dir_with_privilege: stat mismatch between %s "
466 "and %s\n",
467 path,
468 smb_fname_str_dbg(&priv_paths->parent_name)));
469 goto out;
472 dir_hnd = OpenDir(NULL, conn, ".", wcard, attr);
474 out:
476 vfs_ChDir(conn, saved_dir);
477 return dir_hnd;
480 /****************************************************************************
481 Create a new dir ptr. If the flag old_handle is true then we must allocate
482 from the bitmap range 0 - 255 as old SMBsearch directory handles are only
483 one byte long. If old_handle is false we allocate from the range
484 256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
485 a directory handle is never zero.
486 wcard must not be zero.
487 ****************************************************************************/
489 NTSTATUS dptr_create(connection_struct *conn,
490 struct smb_request *req,
491 files_struct *fsp,
492 const char *path, bool old_handle, bool expect_close,uint16 spid,
493 const char *wcard, bool wcard_has_wild, uint32 attr, struct dptr_struct **dptr_ret)
495 struct smbd_server_connection *sconn = conn->sconn;
496 struct dptr_struct *dptr = NULL;
497 struct smb_Dir *dir_hnd;
499 if (fsp && fsp->is_directory && fsp->fh->fd != -1) {
500 path = fsp->fsp_name->base_name;
503 DEBUG(5,("dptr_create dir=%s\n", path));
505 if (sconn == NULL) {
506 DEBUG(0,("dptr_create: called with fake connection_struct\n"));
507 return NT_STATUS_INTERNAL_ERROR;
510 if (!wcard) {
511 return NT_STATUS_INVALID_PARAMETER;
514 if (fsp) {
515 if (!(fsp->access_mask & SEC_DIR_LIST)) {
516 DEBUG(5,("dptr_create: directory %s "
517 "not open for LIST access\n",
518 path));
519 return NT_STATUS_ACCESS_DENIED;
521 dir_hnd = OpenDir_fsp(NULL, conn, fsp, wcard, attr);
522 } else {
523 int ret;
524 bool backup_intent = (req && req->priv_paths);
525 struct smb_filename *smb_dname;
526 NTSTATUS status;
528 smb_dname = synthetic_smb_fname(talloc_tos(), path,
529 NULL, NULL);
530 if (smb_dname == NULL) {
531 return NT_STATUS_NO_MEMORY;
533 if (lp_posix_pathnames()) {
534 ret = SMB_VFS_LSTAT(conn, smb_dname);
535 } else {
536 ret = SMB_VFS_STAT(conn, smb_dname);
538 if (ret == -1) {
539 return map_nt_error_from_unix(errno);
541 if (!S_ISDIR(smb_dname->st.st_ex_mode)) {
542 return NT_STATUS_NOT_A_DIRECTORY;
544 status = smbd_check_access_rights(conn,
545 smb_dname,
546 backup_intent,
547 SEC_DIR_LIST);
548 if (!NT_STATUS_IS_OK(status)) {
549 return status;
551 if (backup_intent) {
552 dir_hnd = open_dir_with_privilege(conn,
553 req,
554 path,
555 wcard,
556 attr);
557 } else {
558 dir_hnd = OpenDir(NULL, conn, path, wcard, attr);
562 if (!dir_hnd) {
563 return map_nt_error_from_unix(errno);
566 if (sconn->searches.dirhandles_open >= MAX_OPEN_DIRECTORIES) {
567 dptr_idleoldest(sconn);
570 dptr = talloc(NULL, struct dptr_struct);
571 if(!dptr) {
572 DEBUG(0,("talloc fail in dptr_create.\n"));
573 TALLOC_FREE(dir_hnd);
574 return NT_STATUS_NO_MEMORY;
577 ZERO_STRUCTP(dptr);
579 dptr->path = talloc_strdup(dptr, path);
580 if (!dptr->path) {
581 TALLOC_FREE(dptr);
582 TALLOC_FREE(dir_hnd);
583 return NT_STATUS_NO_MEMORY;
585 dptr->conn = conn;
586 dptr->dir_hnd = dir_hnd;
587 dptr->spid = spid;
588 dptr->expect_close = expect_close;
589 dptr->wcard = talloc_strdup(dptr, wcard);
590 if (!dptr->wcard) {
591 TALLOC_FREE(dptr);
592 TALLOC_FREE(dir_hnd);
593 return NT_STATUS_NO_MEMORY;
595 if (lp_posix_pathnames() || (wcard[0] == '.' && wcard[1] == 0)) {
596 dptr->has_wild = True;
597 } else {
598 dptr->has_wild = wcard_has_wild;
601 dptr->attr = attr;
603 if (sconn->using_smb2) {
604 goto done;
607 if(old_handle) {
610 * This is an old-style SMBsearch request. Ensure the
611 * value we return will fit in the range 1-255.
614 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 0);
616 if(dptr->dnum == -1 || dptr->dnum > 254) {
619 * Try and close the oldest handle not marked for
620 * expect close in the hope that the client has
621 * finished with that one.
624 dptr_close_oldest(sconn, true);
626 /* Now try again... */
627 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 0);
628 if(dptr->dnum == -1 || dptr->dnum > 254) {
629 DEBUG(0,("dptr_create: returned %d: Error - all old dirptrs in use ?\n", dptr->dnum));
630 TALLOC_FREE(dptr);
631 TALLOC_FREE(dir_hnd);
632 return NT_STATUS_TOO_MANY_OPENED_FILES;
635 } else {
638 * This is a new-style trans2 request. Allocate from
639 * a range that will return 256 - MAX_DIRECTORY_HANDLES.
642 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 255);
644 if(dptr->dnum == -1 || dptr->dnum < 255) {
647 * Try and close the oldest handle close in the hope that
648 * the client has finished with that one. This will only
649 * happen in the case of the Win98 client bug where it leaks
650 * directory handles.
653 dptr_close_oldest(sconn, false);
655 /* Now try again... */
656 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 255);
658 if(dptr->dnum == -1 || dptr->dnum < 255) {
659 DEBUG(0,("dptr_create: returned %d: Error - all new dirptrs in use ?\n", dptr->dnum));
660 TALLOC_FREE(dptr);
661 TALLOC_FREE(dir_hnd);
662 return NT_STATUS_TOO_MANY_OPENED_FILES;
667 bitmap_set(sconn->searches.dptr_bmap, dptr->dnum);
669 dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
671 DLIST_ADD(sconn->searches.dirptrs, dptr);
673 done:
674 DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
675 dptr->dnum,path,expect_close));
677 *dptr_ret = dptr;
679 return NT_STATUS_OK;
683 /****************************************************************************
684 Wrapper functions to access the lower level directory handles.
685 ****************************************************************************/
687 void dptr_CloseDir(files_struct *fsp)
689 if (fsp->dptr) {
691 * The destructor for the struct smb_Dir
692 * (fsp->dptr->dir_hnd) now handles
693 * all resource deallocation.
695 dptr_close_internal(fsp->dptr);
696 fsp->dptr = NULL;
700 void dptr_SeekDir(struct dptr_struct *dptr, long offset)
702 SeekDir(dptr->dir_hnd, offset);
705 long dptr_TellDir(struct dptr_struct *dptr)
707 return TellDir(dptr->dir_hnd);
710 bool dptr_has_wild(struct dptr_struct *dptr)
712 return dptr->has_wild;
715 int dptr_dnum(struct dptr_struct *dptr)
717 return dptr->dnum;
720 bool dptr_get_priv(struct dptr_struct *dptr)
722 return dptr->priv;
725 void dptr_set_priv(struct dptr_struct *dptr)
727 dptr->priv = true;
730 /****************************************************************************
731 Return the next visible file name, skipping veto'd and invisible files.
732 ****************************************************************************/
734 static const char *dptr_normal_ReadDirName(struct dptr_struct *dptr,
735 long *poffset, SMB_STRUCT_STAT *pst,
736 char **ptalloced)
738 /* Normal search for the next file. */
739 const char *name;
740 char *talloced = NULL;
742 while ((name = ReadDirName(dptr->dir_hnd, poffset, pst, &talloced))
743 != NULL) {
744 if (is_visible_file(dptr->conn, dptr->path, name, pst, True)) {
745 *ptalloced = talloced;
746 return name;
748 TALLOC_FREE(talloced);
750 return NULL;
753 /****************************************************************************
754 Return the next visible file name, skipping veto'd and invisible files.
755 ****************************************************************************/
757 char *dptr_ReadDirName(TALLOC_CTX *ctx,
758 struct dptr_struct *dptr,
759 long *poffset,
760 SMB_STRUCT_STAT *pst)
762 struct smb_filename smb_fname_base;
763 char *name = NULL;
764 const char *name_temp = NULL;
765 char *talloced = NULL;
766 char *pathreal = NULL;
767 char *found_name = NULL;
768 int ret;
770 SET_STAT_INVALID(*pst);
772 if (dptr->has_wild || dptr->did_stat) {
773 name_temp = dptr_normal_ReadDirName(dptr, poffset, pst,
774 &talloced);
775 if (name_temp == NULL) {
776 return NULL;
778 if (talloced != NULL) {
779 return talloc_move(ctx, &talloced);
781 return talloc_strdup(ctx, name_temp);
784 /* If poffset is -1 then we know we returned this name before and we
785 * have no wildcards. We're at the end of the directory. */
786 if (*poffset == END_OF_DIRECTORY_OFFSET) {
787 return NULL;
790 /* We know the stored wcard contains no wildcard characters.
791 * See if we can match with a stat call. If we can't, then set
792 * did_stat to true to ensure we only do this once and keep
793 * searching. */
795 dptr->did_stat = true;
797 /* First check if it should be visible. */
798 if (!is_visible_file(dptr->conn, dptr->path, dptr->wcard,
799 pst, true))
801 /* This only returns false if the file was found, but
802 is explicitly not visible. Set us to end of
803 directory, but return NULL as we know we can't ever
804 find it. */
805 goto ret;
808 if (VALID_STAT(*pst)) {
809 name = talloc_strdup(ctx, dptr->wcard);
810 goto ret;
813 pathreal = talloc_asprintf(ctx,
814 "%s/%s",
815 dptr->path,
816 dptr->wcard);
817 if (!pathreal)
818 return NULL;
820 /* Create an smb_filename with stream_name == NULL. */
821 ZERO_STRUCT(smb_fname_base);
822 smb_fname_base.base_name = pathreal;
824 if (SMB_VFS_STAT(dptr->conn, &smb_fname_base) == 0) {
825 *pst = smb_fname_base.st;
826 name = talloc_strdup(ctx, dptr->wcard);
827 goto clean;
828 } else {
829 /* If we get any other error than ENOENT or ENOTDIR
830 then the file exists we just can't stat it. */
831 if (errno != ENOENT && errno != ENOTDIR) {
832 name = talloc_strdup(ctx, dptr->wcard);
833 goto clean;
837 /* Stat failed. We know this is authoratiative if we are
838 * providing case sensitive semantics or the underlying
839 * filesystem is case sensitive.
841 if (dptr->conn->case_sensitive ||
842 !(dptr->conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH))
844 goto clean;
848 * Try case-insensitive stat if the fs has the ability. This avoids
849 * scanning the whole directory.
851 ret = SMB_VFS_GET_REAL_FILENAME(dptr->conn, dptr->path, dptr->wcard,
852 ctx, &found_name);
853 if (ret == 0) {
854 name = found_name;
855 goto clean;
856 } else if (errno == ENOENT) {
857 /* The case-insensitive lookup was authoritative. */
858 goto clean;
861 TALLOC_FREE(pathreal);
863 name_temp = dptr_normal_ReadDirName(dptr, poffset, pst, &talloced);
864 if (name_temp == NULL) {
865 return NULL;
867 if (talloced != NULL) {
868 return talloc_move(ctx, &talloced);
870 return talloc_strdup(ctx, name_temp);
872 clean:
873 TALLOC_FREE(pathreal);
874 ret:
875 /* We need to set the underlying dir_hnd offset to -1
876 * also as this function is usually called with the
877 * output from TellDir. */
878 dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
879 return name;
882 /****************************************************************************
883 Search for a file by name, skipping veto'ed and not visible files.
884 ****************************************************************************/
886 bool dptr_SearchDir(struct dptr_struct *dptr, const char *name, long *poffset, SMB_STRUCT_STAT *pst)
888 SET_STAT_INVALID(*pst);
890 if (!dptr->has_wild && (dptr->dir_hnd->offset == END_OF_DIRECTORY_OFFSET)) {
891 /* This is a singleton directory and we're already at the end. */
892 *poffset = END_OF_DIRECTORY_OFFSET;
893 return False;
896 return SearchDir(dptr->dir_hnd, name, poffset);
899 /****************************************************************************
900 Initialize variables & state data at the beginning of all search SMB requests.
901 ****************************************************************************/
902 void dptr_init_search_op(struct dptr_struct *dptr)
904 SMB_VFS_INIT_SEARCH_OP(dptr->conn, dptr->dir_hnd->dir);
907 /****************************************************************************
908 Map a native directory offset to a 32-bit cookie.
909 ****************************************************************************/
911 static uint32_t map_dir_offset_to_wire(struct dptr_struct *dptr, long offset)
913 DATA_BLOB key;
914 DATA_BLOB val;
916 if (offset == END_OF_DIRECTORY_OFFSET) {
917 return WIRE_END_OF_DIRECTORY_OFFSET;
918 } else if(offset == START_OF_DIRECTORY_OFFSET) {
919 return WIRE_START_OF_DIRECTORY_OFFSET;
920 } else if (offset == DOT_DOT_DIRECTORY_OFFSET) {
921 return WIRE_DOT_DOT_DIRECTORY_OFFSET;
923 if (sizeof(long) == 4) {
924 /* 32-bit machine. We can cheat... */
925 return (uint32_t)offset;
927 if (dptr->dptr_cache == NULL) {
928 /* Lazy initialize cache. */
929 dptr->dptr_cache = memcache_init(dptr, 0);
930 if (dptr->dptr_cache == NULL) {
931 return WIRE_END_OF_DIRECTORY_OFFSET;
933 } else {
934 /* Have we seen this offset before ? */
935 key.data = (void *)&offset;
936 key.length = sizeof(offset);
937 if (memcache_lookup(dptr->dptr_cache,
938 SMB1_SEARCH_OFFSET_MAP,
939 key,
940 &val)) {
941 uint32_t wire_offset;
942 SMB_ASSERT(val.length == sizeof(wire_offset));
943 memcpy(&wire_offset, val.data, sizeof(wire_offset));
944 DEBUG(10,("found wire %u <-> offset %ld\n",
945 (unsigned int)wire_offset,
946 (long)offset));
947 return wire_offset;
950 /* Allocate a new wire cookie. */
951 do {
952 dptr->counter++;
953 } while (dptr->counter == WIRE_START_OF_DIRECTORY_OFFSET ||
954 dptr->counter == WIRE_END_OF_DIRECTORY_OFFSET ||
955 dptr->counter == WIRE_DOT_DOT_DIRECTORY_OFFSET);
956 /* Store it in the cache. */
957 key.data = (void *)&offset;
958 key.length = sizeof(offset);
959 val.data = (void *)&dptr->counter;
960 val.length = sizeof(dptr->counter); /* MUST BE uint32_t ! */
961 memcache_add(dptr->dptr_cache,
962 SMB1_SEARCH_OFFSET_MAP,
963 key,
964 val);
965 /* And the reverse mapping for lookup from
966 map_wire_to_dir_offset(). */
967 memcache_add(dptr->dptr_cache,
968 SMB1_SEARCH_OFFSET_MAP,
969 val,
970 key);
971 DEBUG(10,("stored wire %u <-> offset %ld\n",
972 (unsigned int)dptr->counter,
973 (long)offset));
974 return dptr->counter;
977 /****************************************************************************
978 Fill the 5 byte server reserved dptr field.
979 ****************************************************************************/
981 bool dptr_fill(struct smbd_server_connection *sconn,
982 char *buf1,unsigned int key)
984 unsigned char *buf = (unsigned char *)buf1;
985 struct dptr_struct *dptr = dptr_get(sconn, key, false);
986 uint32_t wire_offset;
987 if (!dptr) {
988 DEBUG(1,("filling null dirptr %d\n",key));
989 return(False);
991 wire_offset = map_dir_offset_to_wire(dptr,TellDir(dptr->dir_hnd));
992 DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key,
993 (long)dptr->dir_hnd,(int)wire_offset));
994 buf[0] = key;
995 SIVAL(buf,1,wire_offset);
996 return(True);
999 /****************************************************************************
1000 Map a 32-bit wire cookie to a native directory offset.
1001 ****************************************************************************/
1003 static long map_wire_to_dir_offset(struct dptr_struct *dptr, uint32_t wire_offset)
1005 DATA_BLOB key;
1006 DATA_BLOB val;
1008 if (wire_offset == WIRE_END_OF_DIRECTORY_OFFSET) {
1009 return END_OF_DIRECTORY_OFFSET;
1010 } else if(wire_offset == WIRE_START_OF_DIRECTORY_OFFSET) {
1011 return START_OF_DIRECTORY_OFFSET;
1012 } else if (wire_offset == WIRE_DOT_DOT_DIRECTORY_OFFSET) {
1013 return DOT_DOT_DIRECTORY_OFFSET;
1015 if (sizeof(long) == 4) {
1016 /* 32-bit machine. We can cheat... */
1017 return (long)wire_offset;
1019 if (dptr->dptr_cache == NULL) {
1020 /* Logic error, cache should be initialized. */
1021 return END_OF_DIRECTORY_OFFSET;
1023 key.data = (void *)&wire_offset;
1024 key.length = sizeof(wire_offset);
1025 if (memcache_lookup(dptr->dptr_cache,
1026 SMB1_SEARCH_OFFSET_MAP,
1027 key,
1028 &val)) {
1029 /* Found mapping. */
1030 long offset;
1031 SMB_ASSERT(val.length == sizeof(offset));
1032 memcpy(&offset, val.data, sizeof(offset));
1033 DEBUG(10,("lookup wire %u <-> offset %ld\n",
1034 (unsigned int)wire_offset,
1035 (long)offset));
1036 return offset;
1038 return END_OF_DIRECTORY_OFFSET;
1041 /****************************************************************************
1042 Fetch the dir ptr and seek it given the 5 byte server field.
1043 ****************************************************************************/
1045 struct dptr_struct *dptr_fetch(struct smbd_server_connection *sconn,
1046 char *buf, int *num)
1048 unsigned int key = *(unsigned char *)buf;
1049 struct dptr_struct *dptr = dptr_get(sconn, key, false);
1050 uint32_t wire_offset;
1051 long seekoff;
1053 if (!dptr) {
1054 DEBUG(3,("fetched null dirptr %d\n",key));
1055 return(NULL);
1057 *num = key;
1058 wire_offset = IVAL(buf,1);
1059 seekoff = map_wire_to_dir_offset(dptr, wire_offset);
1060 SeekDir(dptr->dir_hnd,seekoff);
1061 DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
1062 key, dptr->path, (int)seekoff));
1063 return(dptr);
1066 /****************************************************************************
1067 Fetch the dir ptr.
1068 ****************************************************************************/
1070 struct dptr_struct *dptr_fetch_lanman2(struct smbd_server_connection *sconn,
1071 int dptr_num)
1073 struct dptr_struct *dptr = dptr_get(sconn, dptr_num, false);
1075 if (!dptr) {
1076 DEBUG(3,("fetched null dirptr %d\n",dptr_num));
1077 return(NULL);
1079 DEBUG(3,("fetching dirptr %d for path %s\n",dptr_num,dptr->path));
1080 return(dptr);
1083 static bool mangle_mask_match(connection_struct *conn,
1084 const char *filename,
1085 const char *mask)
1087 char mname[13];
1089 if (!name_to_8_3(filename,mname,False,conn->params)) {
1090 return False;
1092 return mask_match_search(mname,mask,False);
1095 bool smbd_dirptr_get_entry(TALLOC_CTX *ctx,
1096 struct dptr_struct *dirptr,
1097 const char *mask,
1098 uint32_t dirtype,
1099 bool dont_descend,
1100 bool ask_sharemode,
1101 bool (*match_fn)(TALLOC_CTX *ctx,
1102 void *private_data,
1103 const char *dname,
1104 const char *mask,
1105 char **_fname),
1106 bool (*mode_fn)(TALLOC_CTX *ctx,
1107 void *private_data,
1108 struct smb_filename *smb_fname,
1109 uint32_t *_mode),
1110 void *private_data,
1111 char **_fname,
1112 struct smb_filename **_smb_fname,
1113 uint32_t *_mode,
1114 long *_prev_offset)
1116 connection_struct *conn = dirptr->conn;
1117 size_t slashlen;
1118 size_t pathlen;
1120 *_smb_fname = NULL;
1121 *_mode = 0;
1123 pathlen = strlen(dirptr->path);
1124 slashlen = ( dirptr->path[pathlen-1] != '/') ? 1 : 0;
1126 while (true) {
1127 long cur_offset;
1128 long prev_offset;
1129 SMB_STRUCT_STAT sbuf;
1130 char *dname = NULL;
1131 bool isdots;
1132 char *fname = NULL;
1133 char *pathreal = NULL;
1134 struct smb_filename smb_fname;
1135 uint32_t mode = 0;
1136 bool ok;
1138 cur_offset = dptr_TellDir(dirptr);
1139 prev_offset = cur_offset;
1140 dname = dptr_ReadDirName(ctx, dirptr, &cur_offset, &sbuf);
1142 DEBUG(6,("smbd_dirptr_get_entry: dirptr 0x%lx now at offset %ld\n",
1143 (long)dirptr, cur_offset));
1145 if (dname == NULL) {
1146 return false;
1149 isdots = (ISDOT(dname) || ISDOTDOT(dname));
1150 if (dont_descend && !isdots) {
1151 TALLOC_FREE(dname);
1152 continue;
1156 * fname may get mangled, dname is never mangled.
1157 * Whenever we're accessing the filesystem we use
1158 * pathreal which is composed from dname.
1161 ok = match_fn(ctx, private_data, dname, mask, &fname);
1162 if (!ok) {
1163 TALLOC_FREE(dname);
1164 continue;
1168 * This used to be
1169 * pathreal = talloc_asprintf(ctx, "%s%s%s", dirptr->path,
1170 * needslash?"/":"", dname);
1171 * but this was measurably slower than doing the memcpy.
1174 pathreal = talloc_array(
1175 ctx, char,
1176 pathlen + slashlen + talloc_get_size(dname));
1177 if (!pathreal) {
1178 TALLOC_FREE(dname);
1179 TALLOC_FREE(fname);
1180 return false;
1183 memcpy(pathreal, dirptr->path, pathlen);
1184 pathreal[pathlen] = '/';
1185 memcpy(pathreal + slashlen + pathlen, dname,
1186 talloc_get_size(dname));
1188 /* Create smb_fname with NULL stream_name. */
1189 ZERO_STRUCT(smb_fname);
1190 smb_fname.base_name = pathreal;
1191 smb_fname.st = sbuf;
1193 ok = mode_fn(ctx, private_data, &smb_fname, &mode);
1194 if (!ok) {
1195 TALLOC_FREE(dname);
1196 TALLOC_FREE(fname);
1197 TALLOC_FREE(pathreal);
1198 continue;
1201 if (!dir_check_ftype(mode, dirtype)) {
1202 DEBUG(5,("[%s] attribs 0x%x didn't match 0x%x\n",
1203 fname, (unsigned int)mode, (unsigned int)dirtype));
1204 TALLOC_FREE(dname);
1205 TALLOC_FREE(fname);
1206 TALLOC_FREE(pathreal);
1207 continue;
1210 if (ask_sharemode) {
1211 struct timespec write_time_ts;
1212 struct file_id fileid;
1214 fileid = vfs_file_id_from_sbuf(conn,
1215 &smb_fname.st);
1216 get_file_infos(fileid, 0, NULL, &write_time_ts);
1217 if (!null_timespec(write_time_ts)) {
1218 update_stat_ex_mtime(&smb_fname.st,
1219 write_time_ts);
1223 DEBUG(3,("smbd_dirptr_get_entry mask=[%s] found %s "
1224 "fname=%s (%s)\n",
1225 mask, smb_fname_str_dbg(&smb_fname),
1226 dname, fname));
1228 DirCacheAdd(dirptr->dir_hnd, dname, cur_offset);
1230 TALLOC_FREE(dname);
1232 *_smb_fname = cp_smb_filename(ctx, &smb_fname);
1233 TALLOC_FREE(pathreal);
1234 if (*_smb_fname == NULL) {
1235 return false;
1237 *_fname = fname;
1238 *_mode = mode;
1239 *_prev_offset = prev_offset;
1241 return true;
1244 return false;
1247 /****************************************************************************
1248 Get an 8.3 directory entry.
1249 ****************************************************************************/
1251 static bool smbd_dirptr_8_3_match_fn(TALLOC_CTX *ctx,
1252 void *private_data,
1253 const char *dname,
1254 const char *mask,
1255 char **_fname)
1257 connection_struct *conn = (connection_struct *)private_data;
1259 if ((strcmp(mask,"*.*") == 0) ||
1260 mask_match_search(dname, mask, false) ||
1261 mangle_mask_match(conn, dname, mask)) {
1262 char mname[13];
1263 const char *fname;
1265 if (!mangle_is_8_3(dname, false, conn->params)) {
1266 bool ok = name_to_8_3(dname, mname, false,
1267 conn->params);
1268 if (!ok) {
1269 return false;
1271 fname = mname;
1272 } else {
1273 fname = dname;
1276 *_fname = talloc_strdup(ctx, fname);
1277 if (*_fname == NULL) {
1278 return false;
1281 return true;
1284 return false;
1287 static bool smbd_dirptr_8_3_mode_fn(TALLOC_CTX *ctx,
1288 void *private_data,
1289 struct smb_filename *smb_fname,
1290 uint32_t *_mode)
1292 connection_struct *conn = (connection_struct *)private_data;
1294 if (!VALID_STAT(smb_fname->st)) {
1295 if ((SMB_VFS_STAT(conn, smb_fname)) != 0) {
1296 DEBUG(5,("smbd_dirptr_8_3_mode_fn: "
1297 "Couldn't stat [%s]. Error "
1298 "= %s\n",
1299 smb_fname_str_dbg(smb_fname),
1300 strerror(errno)));
1301 return false;
1305 *_mode = dos_mode(conn, smb_fname);
1306 return true;
1309 bool get_dir_entry(TALLOC_CTX *ctx,
1310 struct dptr_struct *dirptr,
1311 const char *mask,
1312 uint32_t dirtype,
1313 char **_fname,
1314 off_t *_size,
1315 uint32_t *_mode,
1316 struct timespec *_date,
1317 bool check_descend,
1318 bool ask_sharemode)
1320 connection_struct *conn = dirptr->conn;
1321 char *fname = NULL;
1322 struct smb_filename *smb_fname = NULL;
1323 uint32_t mode = 0;
1324 long prev_offset;
1325 bool ok;
1327 ok = smbd_dirptr_get_entry(ctx,
1328 dirptr,
1329 mask,
1330 dirtype,
1331 check_descend,
1332 ask_sharemode,
1333 smbd_dirptr_8_3_match_fn,
1334 smbd_dirptr_8_3_mode_fn,
1335 conn,
1336 &fname,
1337 &smb_fname,
1338 &mode,
1339 &prev_offset);
1340 if (!ok) {
1341 return false;
1344 *_fname = talloc_move(ctx, &fname);
1345 *_size = smb_fname->st.st_ex_size;
1346 *_mode = mode;
1347 *_date = smb_fname->st.st_ex_mtime;
1348 TALLOC_FREE(smb_fname);
1349 return true;
1352 /*******************************************************************
1353 Check to see if a user can read a file. This is only approximate,
1354 it is used as part of the "hide unreadable" option. Don't
1355 use it for anything security sensitive.
1356 ********************************************************************/
1358 static bool user_can_read_file(connection_struct *conn,
1359 struct smb_filename *smb_fname)
1362 * Never hide files from the root user.
1363 * We use (uid_t)0 here not sec_initial_uid()
1364 * as make test uses a single user context.
1367 if (get_current_uid(conn) == (uid_t)0) {
1368 return True;
1371 return NT_STATUS_IS_OK(smbd_check_access_rights(conn,
1372 smb_fname,
1373 false,
1374 FILE_READ_DATA));
1377 /*******************************************************************
1378 Check to see if a user can write a file (and only files, we do not
1379 check dirs on this one). This is only approximate,
1380 it is used as part of the "hide unwriteable" option. Don't
1381 use it for anything security sensitive.
1382 ********************************************************************/
1384 static bool user_can_write_file(connection_struct *conn,
1385 const struct smb_filename *smb_fname)
1388 * Never hide files from the root user.
1389 * We use (uid_t)0 here not sec_initial_uid()
1390 * as make test uses a single user context.
1393 if (get_current_uid(conn) == (uid_t)0) {
1394 return True;
1397 SMB_ASSERT(VALID_STAT(smb_fname->st));
1399 /* Pseudo-open the file */
1401 if(S_ISDIR(smb_fname->st.st_ex_mode)) {
1402 return True;
1405 return can_write_to_file(conn, smb_fname);
1408 /*******************************************************************
1409 Is a file a "special" type ?
1410 ********************************************************************/
1412 static bool file_is_special(connection_struct *conn,
1413 const struct smb_filename *smb_fname)
1416 * Never hide files from the root user.
1417 * We use (uid_t)0 here not sec_initial_uid()
1418 * as make test uses a single user context.
1421 if (get_current_uid(conn) == (uid_t)0) {
1422 return False;
1425 SMB_ASSERT(VALID_STAT(smb_fname->st));
1427 if (S_ISREG(smb_fname->st.st_ex_mode) ||
1428 S_ISDIR(smb_fname->st.st_ex_mode) ||
1429 S_ISLNK(smb_fname->st.st_ex_mode))
1430 return False;
1432 return True;
1435 /*******************************************************************
1436 Should the file be seen by the client?
1437 NOTE: A successful return is no guarantee of the file's existence.
1438 ********************************************************************/
1440 bool is_visible_file(connection_struct *conn, const char *dir_path,
1441 const char *name, SMB_STRUCT_STAT *pst, bool use_veto)
1443 bool hide_unreadable = lp_hideunreadable(SNUM(conn));
1444 bool hide_unwriteable = lp_hideunwriteable_files(SNUM(conn));
1445 bool hide_special = lp_hide_special_files(SNUM(conn));
1446 char *entry = NULL;
1447 struct smb_filename *smb_fname_base = NULL;
1448 bool ret = false;
1450 if ((strcmp(".",name) == 0) || (strcmp("..",name) == 0)) {
1451 return True; /* . and .. are always visible. */
1454 /* If it's a vetoed file, pretend it doesn't even exist */
1455 if (use_veto && IS_VETO_PATH(conn, name)) {
1456 DEBUG(10,("is_visible_file: file %s is vetoed.\n", name ));
1457 return False;
1460 if (hide_unreadable || hide_unwriteable || hide_special) {
1461 entry = talloc_asprintf(talloc_tos(), "%s/%s", dir_path, name);
1462 if (!entry) {
1463 ret = false;
1464 goto out;
1467 /* Create an smb_filename with stream_name == NULL. */
1468 smb_fname_base = synthetic_smb_fname(talloc_tos(), entry, NULL,
1469 pst);
1470 if (smb_fname_base == NULL) {
1471 ret = false;
1472 goto out;
1475 /* If the file name does not exist, there's no point checking
1476 * the configuration options. We succeed, on the basis that the
1477 * checks *might* have passed if the file was present.
1479 if (!VALID_STAT(*pst)) {
1480 if (SMB_VFS_STAT(conn, smb_fname_base) != 0) {
1481 ret = true;
1482 goto out;
1483 } else {
1484 *pst = smb_fname_base->st;
1488 /* Honour _hide unreadable_ option */
1489 if (hide_unreadable &&
1490 !user_can_read_file(conn, smb_fname_base)) {
1491 DEBUG(10,("is_visible_file: file %s is unreadable.\n",
1492 entry ));
1493 ret = false;
1494 goto out;
1496 /* Honour _hide unwriteable_ option */
1497 if (hide_unwriteable && !user_can_write_file(conn,
1498 smb_fname_base)) {
1499 DEBUG(10,("is_visible_file: file %s is unwritable.\n",
1500 entry ));
1501 ret = false;
1502 goto out;
1504 /* Honour _hide_special_ option */
1505 if (hide_special && file_is_special(conn, smb_fname_base)) {
1506 DEBUG(10,("is_visible_file: file %s is special.\n",
1507 entry ));
1508 ret = false;
1509 goto out;
1513 ret = true;
1514 out:
1515 TALLOC_FREE(smb_fname_base);
1516 TALLOC_FREE(entry);
1517 return ret;
1520 static int smb_Dir_destructor(struct smb_Dir *dirp)
1522 if (dirp->dir != NULL) {
1523 SMB_VFS_CLOSEDIR(dirp->conn,dirp->dir);
1524 if (dirp->fsp != NULL) {
1526 * The SMB_VFS_CLOSEDIR above
1527 * closes the underlying fd inside
1528 * dirp->fsp.
1530 dirp->fsp->fh->fd = -1;
1531 if (dirp->fsp->dptr != NULL) {
1532 SMB_ASSERT(dirp->fsp->dptr->dir_hnd == dirp);
1533 dirp->fsp->dptr->dir_hnd = NULL;
1535 dirp->fsp = NULL;
1538 if (dirp->conn->sconn && !dirp->conn->sconn->using_smb2) {
1539 dirp->conn->sconn->searches.dirhandles_open--;
1541 return 0;
1544 /*******************************************************************
1545 Open a directory.
1546 ********************************************************************/
1548 struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn,
1549 const char *name,
1550 const char *mask,
1551 uint32 attr)
1553 struct smb_Dir *dirp = talloc_zero(mem_ctx, struct smb_Dir);
1554 struct smbd_server_connection *sconn = conn->sconn;
1556 if (!dirp) {
1557 return NULL;
1560 dirp->conn = conn;
1561 dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
1563 dirp->dir_path = talloc_strdup(dirp, name);
1564 if (!dirp->dir_path) {
1565 errno = ENOMEM;
1566 goto fail;
1569 if (sconn && !sconn->using_smb2) {
1570 sconn->searches.dirhandles_open++;
1572 talloc_set_destructor(dirp, smb_Dir_destructor);
1574 dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path, mask, attr);
1575 if (!dirp->dir) {
1576 DEBUG(5,("OpenDir: Can't open %s. %s\n", dirp->dir_path,
1577 strerror(errno) ));
1578 goto fail;
1581 return dirp;
1583 fail:
1584 TALLOC_FREE(dirp);
1585 return NULL;
1588 /*******************************************************************
1589 Open a directory from an fsp.
1590 ********************************************************************/
1592 static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn,
1593 files_struct *fsp,
1594 const char *mask,
1595 uint32 attr)
1597 struct smb_Dir *dirp = talloc_zero(mem_ctx, struct smb_Dir);
1598 struct smbd_server_connection *sconn = conn->sconn;
1600 if (!dirp) {
1601 return NULL;
1604 dirp->conn = conn;
1605 dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
1607 dirp->dir_path = talloc_strdup(dirp, fsp->fsp_name->base_name);
1608 if (!dirp->dir_path) {
1609 errno = ENOMEM;
1610 goto fail;
1613 if (sconn && !sconn->using_smb2) {
1614 sconn->searches.dirhandles_open++;
1616 talloc_set_destructor(dirp, smb_Dir_destructor);
1618 if (fsp->is_directory && fsp->fh->fd != -1) {
1619 dirp->dir = SMB_VFS_FDOPENDIR(fsp, mask, attr);
1620 if (dirp->dir != NULL) {
1621 dirp->fsp = fsp;
1622 } else {
1623 DEBUG(10,("OpenDir_fsp: SMB_VFS_FDOPENDIR on %s returned "
1624 "NULL (%s)\n",
1625 dirp->dir_path,
1626 strerror(errno)));
1627 if (errno != ENOSYS) {
1628 return NULL;
1633 if (dirp->dir == NULL) {
1634 /* FDOPENDIR didn't work. Use OPENDIR instead. */
1635 dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path, mask, attr);
1638 if (!dirp->dir) {
1639 DEBUG(5,("OpenDir_fsp: Can't open %s. %s\n", dirp->dir_path,
1640 strerror(errno) ));
1641 goto fail;
1644 return dirp;
1646 fail:
1647 TALLOC_FREE(dirp);
1648 return NULL;
1652 /*******************************************************************
1653 Read from a directory.
1654 Return directory entry, current offset, and optional stat information.
1655 Don't check for veto or invisible files.
1656 ********************************************************************/
1658 const char *ReadDirName(struct smb_Dir *dirp, long *poffset,
1659 SMB_STRUCT_STAT *sbuf, char **ptalloced)
1661 const char *n;
1662 char *talloced = NULL;
1663 connection_struct *conn = dirp->conn;
1665 /* Cheat to allow . and .. to be the first entries returned. */
1666 if (((*poffset == START_OF_DIRECTORY_OFFSET) ||
1667 (*poffset == DOT_DOT_DIRECTORY_OFFSET)) && (dirp->file_number < 2))
1669 if (dirp->file_number == 0) {
1670 n = ".";
1671 *poffset = dirp->offset = START_OF_DIRECTORY_OFFSET;
1672 } else {
1673 n = "..";
1674 *poffset = dirp->offset = DOT_DOT_DIRECTORY_OFFSET;
1676 dirp->file_number++;
1677 *ptalloced = NULL;
1678 return n;
1679 } else if (*poffset == END_OF_DIRECTORY_OFFSET) {
1680 *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1681 return NULL;
1682 } else {
1683 /* A real offset, seek to it. */
1684 SeekDir(dirp, *poffset);
1687 while ((n = vfs_readdirname(conn, dirp->dir, sbuf, &talloced))) {
1688 /* Ignore . and .. - we've already returned them. */
1689 if (*n == '.') {
1690 if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) {
1691 TALLOC_FREE(talloced);
1692 continue;
1695 *poffset = dirp->offset = SMB_VFS_TELLDIR(conn, dirp->dir);
1696 *ptalloced = talloced;
1697 dirp->file_number++;
1698 return n;
1700 *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1701 *ptalloced = NULL;
1702 return NULL;
1705 /*******************************************************************
1706 Rewind to the start.
1707 ********************************************************************/
1709 void RewindDir(struct smb_Dir *dirp, long *poffset)
1711 SMB_VFS_REWINDDIR(dirp->conn, dirp->dir);
1712 dirp->file_number = 0;
1713 dirp->offset = START_OF_DIRECTORY_OFFSET;
1714 *poffset = START_OF_DIRECTORY_OFFSET;
1717 /*******************************************************************
1718 Seek a dir.
1719 ********************************************************************/
1721 void SeekDir(struct smb_Dir *dirp, long offset)
1723 if (offset != dirp->offset) {
1724 if (offset == START_OF_DIRECTORY_OFFSET) {
1725 RewindDir(dirp, &offset);
1727 * Ok we should really set the file number here
1728 * to 1 to enable ".." to be returned next. Trouble
1729 * is I'm worried about callers using SeekDir(dirp,0)
1730 * as equivalent to RewindDir(). So leave this alone
1731 * for now.
1733 } else if (offset == DOT_DOT_DIRECTORY_OFFSET) {
1734 RewindDir(dirp, &offset);
1736 * Set the file number to 2 - we want to get the first
1737 * real file entry (the one we return after "..")
1738 * on the next ReadDir.
1740 dirp->file_number = 2;
1741 } else if (offset == END_OF_DIRECTORY_OFFSET) {
1742 ; /* Don't seek in this case. */
1743 } else {
1744 SMB_VFS_SEEKDIR(dirp->conn, dirp->dir, offset);
1746 dirp->offset = offset;
1750 /*******************************************************************
1751 Tell a dir position.
1752 ********************************************************************/
1754 long TellDir(struct smb_Dir *dirp)
1756 return(dirp->offset);
1759 /*******************************************************************
1760 Add an entry into the dcache.
1761 ********************************************************************/
1763 static void DirCacheAdd(struct smb_Dir *dirp, const char *name, long offset)
1765 struct name_cache_entry *e;
1767 if (dirp->name_cache_size == 0) {
1768 return;
1771 if (dirp->name_cache == NULL) {
1772 dirp->name_cache = talloc_zero_array(
1773 dirp, struct name_cache_entry, dirp->name_cache_size);
1775 if (dirp->name_cache == NULL) {
1776 return;
1780 dirp->name_cache_index = (dirp->name_cache_index+1) %
1781 dirp->name_cache_size;
1782 e = &dirp->name_cache[dirp->name_cache_index];
1783 TALLOC_FREE(e->name);
1784 e->name = talloc_strdup(dirp, name);
1785 e->offset = offset;
1788 /*******************************************************************
1789 Find an entry by name. Leave us at the offset after it.
1790 Don't check for veto or invisible files.
1791 ********************************************************************/
1793 bool SearchDir(struct smb_Dir *dirp, const char *name, long *poffset)
1795 int i;
1796 const char *entry = NULL;
1797 char *talloced = NULL;
1798 connection_struct *conn = dirp->conn;
1800 /* Search back in the name cache. */
1801 if (dirp->name_cache_size && dirp->name_cache) {
1802 for (i = dirp->name_cache_index; i >= 0; i--) {
1803 struct name_cache_entry *e = &dirp->name_cache[i];
1804 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1805 *poffset = e->offset;
1806 SeekDir(dirp, e->offset);
1807 return True;
1810 for (i = dirp->name_cache_size - 1; i > dirp->name_cache_index; i--) {
1811 struct name_cache_entry *e = &dirp->name_cache[i];
1812 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1813 *poffset = e->offset;
1814 SeekDir(dirp, e->offset);
1815 return True;
1820 /* Not found in the name cache. Rewind directory and start from scratch. */
1821 SMB_VFS_REWINDDIR(conn, dirp->dir);
1822 dirp->file_number = 0;
1823 *poffset = START_OF_DIRECTORY_OFFSET;
1824 while ((entry = ReadDirName(dirp, poffset, NULL, &talloced))) {
1825 if (conn->case_sensitive ? (strcmp(entry, name) == 0) : strequal(entry, name)) {
1826 TALLOC_FREE(talloced);
1827 return True;
1829 TALLOC_FREE(talloced);
1831 return False;
1834 /*****************************************************************
1835 Is this directory empty ?
1836 *****************************************************************/
1838 NTSTATUS can_delete_directory_fsp(files_struct *fsp)
1840 NTSTATUS status = NT_STATUS_OK;
1841 long dirpos = 0;
1842 const char *dname = NULL;
1843 const char *dirname = fsp->fsp_name->base_name;
1844 char *talloced = NULL;
1845 SMB_STRUCT_STAT st;
1846 struct connection_struct *conn = fsp->conn;
1847 struct smb_Dir *dir_hnd = OpenDir_fsp(talloc_tos(),
1848 conn,
1849 fsp,
1850 NULL,
1853 if (!dir_hnd) {
1854 return map_nt_error_from_unix(errno);
1857 while ((dname = ReadDirName(dir_hnd, &dirpos, &st, &talloced))) {
1858 /* Quick check for "." and ".." */
1859 if (dname[0] == '.') {
1860 if (!dname[1] || (dname[1] == '.' && !dname[2])) {
1861 TALLOC_FREE(talloced);
1862 continue;
1866 if (!is_visible_file(conn, dirname, dname, &st, True)) {
1867 TALLOC_FREE(talloced);
1868 continue;
1871 DEBUG(10,("got name %s - can't delete\n",
1872 dname ));
1873 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
1874 break;
1876 TALLOC_FREE(talloced);
1877 TALLOC_FREE(dir_hnd);
1879 return status;