s3: dir - Introduce 32-bit wire versions of the 'special' values.
[Samba.git] / source3 / smbd / dir.c
blob2bae122006d94d9962b5d7d2eabc2936ad1383dc
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"
29 This module implements directory related functions for Samba.
32 /* "Special" directory offsets. */
33 #define END_OF_DIRECTORY_OFFSET ((long)-1)
34 #define START_OF_DIRECTORY_OFFSET ((long)0)
35 #define DOT_DOT_DIRECTORY_OFFSET ((long)0x80000000)
37 /* "Special" directory offsets in 32-bit wire format. */
38 #define WIRE_END_OF_DIRECTORY_OFFSET ((uint32_t)0xFFFFFFFF)
39 #define WIRE_START_OF_DIRECTORY_OFFSET ((uint32_t)0)
40 #define WIRE_DOT_DOT_DIRECTORY_OFFSET ((uint32_t)0x80000000)
42 /* Make directory handle internals available. */
44 struct name_cache_entry {
45 char *name;
46 long offset;
49 struct smb_Dir {
50 connection_struct *conn;
51 DIR *dir;
52 long offset;
53 char *dir_path;
54 size_t name_cache_size;
55 struct name_cache_entry *name_cache;
56 unsigned int name_cache_index;
57 unsigned int file_number;
58 files_struct *fsp; /* Back pointer to containing fsp, only
59 set from OpenDir_fsp(). */
62 struct dptr_struct {
63 struct dptr_struct *next, *prev;
64 int dnum;
65 uint16 spid;
66 struct connection_struct *conn;
67 struct smb_Dir *dir_hnd;
68 bool expect_close;
69 char *wcard;
70 uint32 attr;
71 char *path;
72 bool has_wild; /* Set to true if the wcard entry has MS wildcard characters in it. */
73 bool did_stat; /* Optimisation for non-wcard searches. */
74 bool priv; /* Directory handle opened with privilege. */
77 static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn,
78 files_struct *fsp,
79 const char *mask,
80 uint32 attr);
82 #define INVALID_DPTR_KEY (-3)
84 /****************************************************************************
85 Make a dir struct.
86 ****************************************************************************/
88 bool make_dir_struct(TALLOC_CTX *ctx,
89 char *buf,
90 const char *mask,
91 const char *fname,
92 off_t size,
93 uint32 mode,
94 time_t date,
95 bool uc)
97 char *p;
98 char *mask2 = talloc_strdup(ctx, mask);
100 if (!mask2) {
101 return False;
104 if ((mode & FILE_ATTRIBUTE_DIRECTORY) != 0) {
105 size = 0;
108 memset(buf+1,' ',11);
109 if ((p = strchr_m(mask2,'.')) != NULL) {
110 *p = 0;
111 push_ascii(buf+1,mask2,8, 0);
112 push_ascii(buf+9,p+1,3, 0);
113 *p = '.';
114 } else {
115 push_ascii(buf+1,mask2,11, 0);
118 memset(buf+21,'\0',DIR_STRUCT_SIZE-21);
119 SCVAL(buf,21,mode);
120 srv_put_dos_date(buf,22,date);
121 SSVAL(buf,26,size & 0xFFFF);
122 SSVAL(buf,28,(size >> 16)&0xFFFF);
123 /* We only uppercase if FLAGS2_LONG_PATH_COMPONENTS is zero in the input buf.
124 Strange, but verified on W2K3. Needed for OS/2. JRA. */
125 push_ascii(buf+30,fname,12, uc ? STR_UPPER : 0);
126 DEBUG(8,("put name [%s] from [%s] into dir struct\n",buf+30, fname));
127 return True;
130 /****************************************************************************
131 Initialise the dir bitmap.
132 ****************************************************************************/
134 bool init_dptrs(struct smbd_server_connection *sconn)
136 if (sconn->searches.dptr_bmap) {
137 return true;
140 sconn->searches.dptr_bmap = bitmap_talloc(
141 sconn, MAX_DIRECTORY_HANDLES);
143 if (sconn->searches.dptr_bmap == NULL) {
144 return false;
147 return true;
150 /****************************************************************************
151 Idle a dptr - the directory is closed but the control info is kept.
152 ****************************************************************************/
154 static void dptr_idle(struct dptr_struct *dptr)
156 if (dptr->dir_hnd) {
157 DEBUG(4,("Idling dptr dnum %d\n",dptr->dnum));
158 TALLOC_FREE(dptr->dir_hnd);
162 /****************************************************************************
163 Idle the oldest dptr.
164 ****************************************************************************/
166 static void dptr_idleoldest(struct smbd_server_connection *sconn)
168 struct dptr_struct *dptr;
171 * Go to the end of the list.
173 dptr = DLIST_TAIL(sconn->searches.dirptrs);
175 if(!dptr) {
176 DEBUG(0,("No dptrs available to idle ?\n"));
177 return;
181 * Idle the oldest pointer.
184 for(; dptr; dptr = DLIST_PREV(dptr)) {
185 if (dptr->dir_hnd) {
186 dptr_idle(dptr);
187 return;
192 /****************************************************************************
193 Get the struct dptr_struct for a dir index.
194 ****************************************************************************/
196 static struct dptr_struct *dptr_get(struct smbd_server_connection *sconn,
197 int key, bool forclose)
199 struct dptr_struct *dptr;
201 for(dptr = sconn->searches.dirptrs; dptr; dptr = dptr->next) {
202 if(dptr->dnum == key) {
203 if (!forclose && !dptr->dir_hnd) {
204 if (sconn->searches.dirhandles_open >= MAX_OPEN_DIRECTORIES)
205 dptr_idleoldest(sconn);
206 DEBUG(4,("dptr_get: Reopening dptr key %d\n",key));
207 if (!(dptr->dir_hnd = OpenDir(
208 NULL, dptr->conn, dptr->path,
209 dptr->wcard, dptr->attr))) {
210 DEBUG(4,("dptr_get: Failed to open %s (%s)\n",dptr->path,
211 strerror(errno)));
212 return NULL;
215 DLIST_PROMOTE(sconn->searches.dirptrs,dptr);
216 return dptr;
219 return(NULL);
222 /****************************************************************************
223 Get the dir path for a dir index.
224 ****************************************************************************/
226 const char *dptr_path(struct smbd_server_connection *sconn, int key)
228 struct dptr_struct *dptr = dptr_get(sconn, key, false);
229 if (dptr)
230 return(dptr->path);
231 return(NULL);
234 /****************************************************************************
235 Get the dir wcard for a dir index.
236 ****************************************************************************/
238 const char *dptr_wcard(struct smbd_server_connection *sconn, int key)
240 struct dptr_struct *dptr = dptr_get(sconn, key, false);
241 if (dptr)
242 return(dptr->wcard);
243 return(NULL);
246 /****************************************************************************
247 Get the dir attrib for a dir index.
248 ****************************************************************************/
250 uint16 dptr_attr(struct smbd_server_connection *sconn, int key)
252 struct dptr_struct *dptr = dptr_get(sconn, key, false);
253 if (dptr)
254 return(dptr->attr);
255 return(0);
258 /****************************************************************************
259 Close a dptr (internal func).
260 ****************************************************************************/
262 static void dptr_close_internal(struct dptr_struct *dptr)
264 struct smbd_server_connection *sconn = dptr->conn->sconn;
266 DEBUG(4,("closing dptr key %d\n",dptr->dnum));
268 if (sconn == NULL) {
269 goto done;
272 if (sconn->using_smb2) {
273 goto done;
276 DLIST_REMOVE(sconn->searches.dirptrs, dptr);
279 * Free the dnum in the bitmap. Remember the dnum value is always
280 * biased by one with respect to the bitmap.
283 if (!bitmap_query(sconn->searches.dptr_bmap, dptr->dnum - 1)) {
284 DEBUG(0,("dptr_close_internal : Error - closing dnum = %d and bitmap not set !\n",
285 dptr->dnum ));
288 bitmap_clear(sconn->searches.dptr_bmap, dptr->dnum - 1);
290 done:
291 TALLOC_FREE(dptr->dir_hnd);
292 TALLOC_FREE(dptr);
295 /****************************************************************************
296 Close a dptr given a key.
297 ****************************************************************************/
299 void dptr_close(struct smbd_server_connection *sconn, int *key)
301 struct dptr_struct *dptr;
303 if(*key == INVALID_DPTR_KEY)
304 return;
306 /* OS/2 seems to use -1 to indicate "close all directories" */
307 if (*key == -1) {
308 struct dptr_struct *next;
309 for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
310 next = dptr->next;
311 dptr_close_internal(dptr);
313 *key = INVALID_DPTR_KEY;
314 return;
317 dptr = dptr_get(sconn, *key, true);
319 if (!dptr) {
320 DEBUG(0,("Invalid key %d given to dptr_close\n", *key));
321 return;
324 dptr_close_internal(dptr);
326 *key = INVALID_DPTR_KEY;
329 /****************************************************************************
330 Close all dptrs for a cnum.
331 ****************************************************************************/
333 void dptr_closecnum(connection_struct *conn)
335 struct dptr_struct *dptr, *next;
336 struct smbd_server_connection *sconn = conn->sconn;
338 if (sconn == NULL) {
339 return;
342 for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
343 next = dptr->next;
344 if (dptr->conn == conn) {
345 dptr_close_internal(dptr);
350 /****************************************************************************
351 Idle all dptrs for a cnum.
352 ****************************************************************************/
354 void dptr_idlecnum(connection_struct *conn)
356 struct dptr_struct *dptr;
357 struct smbd_server_connection *sconn = conn->sconn;
359 if (sconn == NULL) {
360 return;
363 for(dptr = sconn->searches.dirptrs; dptr; dptr = dptr->next) {
364 if (dptr->conn == conn && dptr->dir_hnd) {
365 dptr_idle(dptr);
370 /****************************************************************************
371 Close a dptr that matches a given path, only if it matches the spid also.
372 ****************************************************************************/
374 void dptr_closepath(struct smbd_server_connection *sconn,
375 char *path,uint16 spid)
377 struct dptr_struct *dptr, *next;
378 for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
379 next = dptr->next;
380 if (spid == dptr->spid && strequal(dptr->path,path))
381 dptr_close_internal(dptr);
385 /****************************************************************************
386 Try and close the oldest handle not marked for
387 expect close in the hope that the client has
388 finished with that one.
389 ****************************************************************************/
391 static void dptr_close_oldest(struct smbd_server_connection *sconn,
392 bool old)
394 struct dptr_struct *dptr;
397 * Go to the end of the list.
399 for(dptr = sconn->searches.dirptrs; dptr && dptr->next; dptr = dptr->next)
402 if(!dptr) {
403 DEBUG(0,("No old dptrs available to close oldest ?\n"));
404 return;
408 * If 'old' is true, close the oldest oldhandle dnum (ie. 1 < dnum < 256) that
409 * does not have expect_close set. If 'old' is false, close
410 * one of the new dnum handles.
413 for(; dptr; dptr = DLIST_PREV(dptr)) {
414 if ((old && (dptr->dnum < 256) && !dptr->expect_close) ||
415 (!old && (dptr->dnum > 255))) {
416 dptr_close_internal(dptr);
417 return;
422 /****************************************************************************
423 Safely do an OpenDir as root, ensuring we're in the right place.
424 ****************************************************************************/
426 static struct smb_Dir *open_dir_with_privilege(connection_struct *conn,
427 struct smb_request *req,
428 const char *path,
429 const char *wcard,
430 uint32_t attr)
432 NTSTATUS status;
433 struct smb_Dir *dir_hnd = NULL;
434 struct smb_filename *smb_fname_cwd = NULL;
435 char *saved_dir = vfs_GetWd(talloc_tos(), conn);
436 struct privilege_paths *priv_paths = req->priv_paths;
437 int ret;
439 if (saved_dir == NULL) {
440 return NULL;
443 if (vfs_ChDir(conn, path) == -1) {
444 return NULL;
447 /* Now check the stat value is the same. */
448 status = create_synthetic_smb_fname(talloc_tos(), ".",
449 NULL, NULL,
450 &smb_fname_cwd);
452 if (!NT_STATUS_IS_OK(status)) {
453 goto out;
455 ret = SMB_VFS_STAT(conn, smb_fname_cwd);
456 if (ret != 0) {
457 goto out;
460 if (!check_same_stat(&smb_fname_cwd->st, &priv_paths->parent_name.st)) {
461 DEBUG(0,("open_dir_with_privilege: stat mismatch between %s "
462 "and %s\n",
463 path,
464 smb_fname_str_dbg(&priv_paths->parent_name)));
465 goto out;
468 dir_hnd = OpenDir(NULL, conn, ".", wcard, attr);
470 out:
472 vfs_ChDir(conn, saved_dir);
473 return dir_hnd;
476 /****************************************************************************
477 Create a new dir ptr. If the flag old_handle is true then we must allocate
478 from the bitmap range 0 - 255 as old SMBsearch directory handles are only
479 one byte long. If old_handle is false we allocate from the range
480 256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
481 a directory handle is never zero.
482 wcard must not be zero.
483 ****************************************************************************/
485 NTSTATUS dptr_create(connection_struct *conn,
486 struct smb_request *req,
487 files_struct *fsp,
488 const char *path, bool old_handle, bool expect_close,uint16 spid,
489 const char *wcard, bool wcard_has_wild, uint32 attr, struct dptr_struct **dptr_ret)
491 struct smbd_server_connection *sconn = conn->sconn;
492 struct dptr_struct *dptr = NULL;
493 struct smb_Dir *dir_hnd;
495 if (fsp && fsp->is_directory && fsp->fh->fd != -1) {
496 path = fsp->fsp_name->base_name;
499 DEBUG(5,("dptr_create dir=%s\n", path));
501 if (sconn == NULL) {
502 DEBUG(0,("dptr_create: called with fake connection_struct\n"));
503 return NT_STATUS_INTERNAL_ERROR;
506 if (!wcard) {
507 return NT_STATUS_INVALID_PARAMETER;
510 if (fsp) {
511 if (!(fsp->access_mask & SEC_DIR_LIST)) {
512 DEBUG(5,("dptr_create: directory %s "
513 "not open for LIST access\n",
514 path));
515 return NT_STATUS_ACCESS_DENIED;
517 dir_hnd = OpenDir_fsp(NULL, conn, fsp, wcard, attr);
518 } else {
519 int ret;
520 struct smb_filename *smb_dname = NULL;
521 NTSTATUS status = create_synthetic_smb_fname(talloc_tos(),
522 path,
523 NULL,
524 NULL,
525 &smb_dname);
526 if (!NT_STATUS_IS_OK(status)) {
527 return status;
529 if (lp_posix_pathnames()) {
530 ret = SMB_VFS_LSTAT(conn, smb_dname);
531 } else {
532 ret = SMB_VFS_STAT(conn, smb_dname);
534 if (ret == -1) {
535 return map_nt_error_from_unix(errno);
537 if (!S_ISDIR(smb_dname->st.st_ex_mode)) {
538 return NT_STATUS_NOT_A_DIRECTORY;
540 status = smbd_check_access_rights(conn,
541 smb_dname,
542 SEC_DIR_LIST);
543 if (!NT_STATUS_IS_OK(status)) {
544 return status;
546 if (req && req->priv_paths) {
547 dir_hnd = open_dir_with_privilege(conn,
548 req,
549 path,
550 wcard,
551 attr);
552 } else {
553 dir_hnd = OpenDir(NULL, conn, path, wcard, attr);
557 if (!dir_hnd) {
558 return map_nt_error_from_unix(errno);
561 if (sconn->searches.dirhandles_open >= MAX_OPEN_DIRECTORIES) {
562 dptr_idleoldest(sconn);
565 dptr = talloc(NULL, struct dptr_struct);
566 if(!dptr) {
567 DEBUG(0,("talloc fail in dptr_create.\n"));
568 TALLOC_FREE(dir_hnd);
569 return NT_STATUS_NO_MEMORY;
572 ZERO_STRUCTP(dptr);
574 dptr->path = talloc_strdup(dptr, path);
575 if (!dptr->path) {
576 TALLOC_FREE(dptr);
577 TALLOC_FREE(dir_hnd);
578 return NT_STATUS_NO_MEMORY;
580 dptr->conn = conn;
581 dptr->dir_hnd = dir_hnd;
582 dptr->spid = spid;
583 dptr->expect_close = expect_close;
584 dptr->wcard = talloc_strdup(dptr, wcard);
585 if (!dptr->wcard) {
586 TALLOC_FREE(dptr);
587 TALLOC_FREE(dir_hnd);
588 return NT_STATUS_NO_MEMORY;
590 if (lp_posix_pathnames() || (wcard[0] == '.' && wcard[1] == 0)) {
591 dptr->has_wild = True;
592 } else {
593 dptr->has_wild = wcard_has_wild;
596 dptr->attr = attr;
598 if (sconn->using_smb2) {
599 goto done;
602 if(old_handle) {
605 * This is an old-style SMBsearch request. Ensure the
606 * value we return will fit in the range 1-255.
609 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 0);
611 if(dptr->dnum == -1 || dptr->dnum > 254) {
614 * Try and close the oldest handle not marked for
615 * expect close in the hope that the client has
616 * finished with that one.
619 dptr_close_oldest(sconn, true);
621 /* Now try again... */
622 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 0);
623 if(dptr->dnum == -1 || dptr->dnum > 254) {
624 DEBUG(0,("dptr_create: returned %d: Error - all old dirptrs in use ?\n", dptr->dnum));
625 TALLOC_FREE(dptr);
626 TALLOC_FREE(dir_hnd);
627 return NT_STATUS_TOO_MANY_OPENED_FILES;
630 } else {
633 * This is a new-style trans2 request. Allocate from
634 * a range that will return 256 - MAX_DIRECTORY_HANDLES.
637 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 255);
639 if(dptr->dnum == -1 || dptr->dnum < 255) {
642 * Try and close the oldest handle close in the hope that
643 * the client has finished with that one. This will only
644 * happen in the case of the Win98 client bug where it leaks
645 * directory handles.
648 dptr_close_oldest(sconn, false);
650 /* Now try again... */
651 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 255);
653 if(dptr->dnum == -1 || dptr->dnum < 255) {
654 DEBUG(0,("dptr_create: returned %d: Error - all new dirptrs in use ?\n", dptr->dnum));
655 TALLOC_FREE(dptr);
656 TALLOC_FREE(dir_hnd);
657 return NT_STATUS_TOO_MANY_OPENED_FILES;
662 bitmap_set(sconn->searches.dptr_bmap, dptr->dnum);
664 dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
666 DLIST_ADD(sconn->searches.dirptrs, dptr);
668 done:
669 DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
670 dptr->dnum,path,expect_close));
672 *dptr_ret = dptr;
674 return NT_STATUS_OK;
678 /****************************************************************************
679 Wrapper functions to access the lower level directory handles.
680 ****************************************************************************/
682 void dptr_CloseDir(files_struct *fsp)
684 if (fsp->dptr) {
686 * The destructor for the struct smb_Dir
687 * (fsp->dptr->dir_hnd) now handles
688 * all resource deallocation.
690 dptr_close_internal(fsp->dptr);
691 fsp->dptr = NULL;
695 void dptr_SeekDir(struct dptr_struct *dptr, long offset)
697 SeekDir(dptr->dir_hnd, offset);
700 long dptr_TellDir(struct dptr_struct *dptr)
702 return TellDir(dptr->dir_hnd);
705 bool dptr_has_wild(struct dptr_struct *dptr)
707 return dptr->has_wild;
710 int dptr_dnum(struct dptr_struct *dptr)
712 return dptr->dnum;
715 bool dptr_get_priv(struct dptr_struct *dptr)
717 return dptr->priv;
720 void dptr_set_priv(struct dptr_struct *dptr)
722 dptr->priv = true;
725 /****************************************************************************
726 Return the next visible file name, skipping veto'd and invisible files.
727 ****************************************************************************/
729 static const char *dptr_normal_ReadDirName(struct dptr_struct *dptr,
730 long *poffset, SMB_STRUCT_STAT *pst,
731 char **ptalloced)
733 /* Normal search for the next file. */
734 const char *name;
735 char *talloced = NULL;
737 while ((name = ReadDirName(dptr->dir_hnd, poffset, pst, &talloced))
738 != NULL) {
739 if (is_visible_file(dptr->conn, dptr->path, name, pst, True)) {
740 *ptalloced = talloced;
741 return name;
743 TALLOC_FREE(talloced);
745 return NULL;
748 /****************************************************************************
749 Return the next visible file name, skipping veto'd and invisible files.
750 ****************************************************************************/
752 char *dptr_ReadDirName(TALLOC_CTX *ctx,
753 struct dptr_struct *dptr,
754 long *poffset,
755 SMB_STRUCT_STAT *pst)
757 struct smb_filename smb_fname_base;
758 char *name = NULL;
759 const char *name_temp = NULL;
760 char *talloced = NULL;
761 char *pathreal = NULL;
762 char *found_name = NULL;
763 int ret;
765 SET_STAT_INVALID(*pst);
767 if (dptr->has_wild || dptr->did_stat) {
768 name_temp = dptr_normal_ReadDirName(dptr, poffset, pst,
769 &talloced);
770 if (name_temp == NULL) {
771 return NULL;
773 if (talloced != NULL) {
774 return talloc_move(ctx, &talloced);
776 return talloc_strdup(ctx, name_temp);
779 /* If poffset is -1 then we know we returned this name before and we
780 * have no wildcards. We're at the end of the directory. */
781 if (*poffset == END_OF_DIRECTORY_OFFSET) {
782 return NULL;
785 /* We know the stored wcard contains no wildcard characters.
786 * See if we can match with a stat call. If we can't, then set
787 * did_stat to true to ensure we only do this once and keep
788 * searching. */
790 dptr->did_stat = true;
792 /* First check if it should be visible. */
793 if (!is_visible_file(dptr->conn, dptr->path, dptr->wcard,
794 pst, true))
796 /* This only returns false if the file was found, but
797 is explicitly not visible. Set us to end of
798 directory, but return NULL as we know we can't ever
799 find it. */
800 goto ret;
803 if (VALID_STAT(*pst)) {
804 name = talloc_strdup(ctx, dptr->wcard);
805 goto ret;
808 pathreal = talloc_asprintf(ctx,
809 "%s/%s",
810 dptr->path,
811 dptr->wcard);
812 if (!pathreal)
813 return NULL;
815 /* Create an smb_filename with stream_name == NULL. */
816 ZERO_STRUCT(smb_fname_base);
817 smb_fname_base.base_name = pathreal;
819 if (SMB_VFS_STAT(dptr->conn, &smb_fname_base) == 0) {
820 *pst = smb_fname_base.st;
821 name = talloc_strdup(ctx, dptr->wcard);
822 goto clean;
823 } else {
824 /* If we get any other error than ENOENT or ENOTDIR
825 then the file exists we just can't stat it. */
826 if (errno != ENOENT && errno != ENOTDIR) {
827 name = talloc_strdup(ctx, dptr->wcard);
828 goto clean;
832 /* Stat failed. We know this is authoratiative if we are
833 * providing case sensitive semantics or the underlying
834 * filesystem is case sensitive.
836 if (dptr->conn->case_sensitive ||
837 !(dptr->conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH))
839 goto clean;
843 * Try case-insensitive stat if the fs has the ability. This avoids
844 * scanning the whole directory.
846 ret = SMB_VFS_GET_REAL_FILENAME(dptr->conn, dptr->path, dptr->wcard,
847 ctx, &found_name);
848 if (ret == 0) {
849 name = found_name;
850 goto clean;
851 } else if (errno == ENOENT) {
852 /* The case-insensitive lookup was authoritative. */
853 goto clean;
856 TALLOC_FREE(pathreal);
858 name_temp = dptr_normal_ReadDirName(dptr, poffset, pst, &talloced);
859 if (name_temp == NULL) {
860 return NULL;
862 if (talloced != NULL) {
863 return talloc_move(ctx, &talloced);
865 return talloc_strdup(ctx, name_temp);
867 clean:
868 TALLOC_FREE(pathreal);
869 ret:
870 /* We need to set the underlying dir_hnd offset to -1
871 * also as this function is usually called with the
872 * output from TellDir. */
873 dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
874 return name;
877 /****************************************************************************
878 Search for a file by name, skipping veto'ed and not visible files.
879 ****************************************************************************/
881 bool dptr_SearchDir(struct dptr_struct *dptr, const char *name, long *poffset, SMB_STRUCT_STAT *pst)
883 SET_STAT_INVALID(*pst);
885 if (!dptr->has_wild && (dptr->dir_hnd->offset == END_OF_DIRECTORY_OFFSET)) {
886 /* This is a singleton directory and we're already at the end. */
887 *poffset = END_OF_DIRECTORY_OFFSET;
888 return False;
891 return SearchDir(dptr->dir_hnd, name, poffset);
894 /****************************************************************************
895 Add the name we're returning into the underlying cache.
896 ****************************************************************************/
898 void dptr_DirCacheAdd(struct dptr_struct *dptr, const char *name, long offset)
900 DirCacheAdd(dptr->dir_hnd, name, offset);
903 /****************************************************************************
904 Initialize variables & state data at the beginning of all search SMB requests.
905 ****************************************************************************/
906 void dptr_init_search_op(struct dptr_struct *dptr)
908 SMB_VFS_INIT_SEARCH_OP(dptr->conn, dptr->dir_hnd->dir);
911 /****************************************************************************
912 Map a native directory offset to a 32-bit cookie.
913 ****************************************************************************/
915 static uint32_t map_dir_offset_to_wire(struct dptr_struct *dptr, long offset)
917 return (uint32_t)offset;
920 /****************************************************************************
921 Fill the 5 byte server reserved dptr field.
922 ****************************************************************************/
924 bool dptr_fill(struct smbd_server_connection *sconn,
925 char *buf1,unsigned int key)
927 unsigned char *buf = (unsigned char *)buf1;
928 struct dptr_struct *dptr = dptr_get(sconn, key, false);
929 uint32_t wire_offset;
930 if (!dptr) {
931 DEBUG(1,("filling null dirptr %d\n",key));
932 return(False);
934 wire_offset = map_dir_offset_to_wire(dptr,TellDir(dptr->dir_hnd));
935 DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key,
936 (long)dptr->dir_hnd,(int)wire_offset));
937 buf[0] = key;
938 SIVAL(buf,1,wire_offset);
939 return(True);
942 /****************************************************************************
943 Fetch the dir ptr and seek it given the 5 byte server field.
944 ****************************************************************************/
946 struct dptr_struct *dptr_fetch(struct smbd_server_connection *sconn,
947 char *buf, int *num)
949 unsigned int key = *(unsigned char *)buf;
950 struct dptr_struct *dptr = dptr_get(sconn, key, false);
951 uint32_t wire_offset;
952 long seekoff;
954 if (!dptr) {
955 DEBUG(3,("fetched null dirptr %d\n",key));
956 return(NULL);
958 *num = key;
959 wire_offset = IVAL(buf,1);
960 if (wire_offset == (uint32_t)-1) {
961 seekoff = END_OF_DIRECTORY_OFFSET;
962 } else {
963 seekoff = (long)wire_offset;
965 SeekDir(dptr->dir_hnd,seekoff);
966 DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
967 key, dptr->path, (int)seekoff));
968 return(dptr);
971 /****************************************************************************
972 Fetch the dir ptr.
973 ****************************************************************************/
975 struct dptr_struct *dptr_fetch_lanman2(struct smbd_server_connection *sconn,
976 int dptr_num)
978 struct dptr_struct *dptr = dptr_get(sconn, dptr_num, false);
980 if (!dptr) {
981 DEBUG(3,("fetched null dirptr %d\n",dptr_num));
982 return(NULL);
984 DEBUG(3,("fetching dirptr %d for path %s\n",dptr_num,dptr->path));
985 return(dptr);
988 /****************************************************************************
989 Check that a file matches a particular file type.
990 ****************************************************************************/
992 bool dir_check_ftype(connection_struct *conn, uint32 mode, uint32 dirtype)
994 uint32 mask;
996 /* Check the "may have" search bits. */
997 if (((mode & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY)) != 0)
998 return False;
1000 /* Check the "must have" bits, which are the may have bits shifted eight */
1001 /* If must have bit is set, the file/dir can not be returned in search unless the matching
1002 file attribute is set */
1003 mask = ((dirtype >> 8) & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)); /* & 0x37 */
1004 if(mask) {
1005 if((mask & (mode & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM))) == mask) /* check if matching attribute present */
1006 return True;
1007 else
1008 return False;
1011 return True;
1014 static bool mangle_mask_match(connection_struct *conn,
1015 const char *filename,
1016 const char *mask)
1018 char mname[13];
1020 if (!name_to_8_3(filename,mname,False,conn->params)) {
1021 return False;
1023 return mask_match_search(mname,mask,False);
1026 bool smbd_dirptr_get_entry(TALLOC_CTX *ctx,
1027 struct dptr_struct *dirptr,
1028 const char *mask,
1029 uint32_t dirtype,
1030 bool dont_descend,
1031 bool ask_sharemode,
1032 bool (*match_fn)(TALLOC_CTX *ctx,
1033 void *private_data,
1034 const char *dname,
1035 const char *mask,
1036 char **_fname),
1037 bool (*mode_fn)(TALLOC_CTX *ctx,
1038 void *private_data,
1039 struct smb_filename *smb_fname,
1040 uint32_t *_mode),
1041 void *private_data,
1042 char **_fname,
1043 struct smb_filename **_smb_fname,
1044 uint32_t *_mode,
1045 long *_prev_offset)
1047 connection_struct *conn = dirptr->conn;
1048 size_t slashlen;
1049 size_t pathlen;
1051 *_smb_fname = NULL;
1052 *_mode = 0;
1054 pathlen = strlen(dirptr->path);
1055 slashlen = ( dirptr->path[pathlen-1] != '/') ? 1 : 0;
1057 while (true) {
1058 long cur_offset;
1059 long prev_offset;
1060 SMB_STRUCT_STAT sbuf;
1061 char *dname = NULL;
1062 bool isdots;
1063 char *fname = NULL;
1064 char *pathreal = NULL;
1065 struct smb_filename smb_fname;
1066 uint32_t mode = 0;
1067 bool ok;
1068 NTSTATUS status;
1070 cur_offset = dptr_TellDir(dirptr);
1071 prev_offset = cur_offset;
1072 dname = dptr_ReadDirName(ctx, dirptr, &cur_offset, &sbuf);
1074 DEBUG(6,("smbd_dirptr_get_entry: dirptr 0x%lx now at offset %ld\n",
1075 (long)dirptr, cur_offset));
1077 if (dname == NULL) {
1078 return false;
1081 isdots = (ISDOT(dname) || ISDOTDOT(dname));
1082 if (dont_descend && !isdots) {
1083 TALLOC_FREE(dname);
1084 continue;
1088 * fname may get mangled, dname is never mangled.
1089 * Whenever we're accessing the filesystem we use
1090 * pathreal which is composed from dname.
1093 ok = match_fn(ctx, private_data, dname, mask, &fname);
1094 if (!ok) {
1095 TALLOC_FREE(dname);
1096 continue;
1100 * This used to be
1101 * pathreal = talloc_asprintf(ctx, "%s%s%s", dirptr->path,
1102 * needslash?"/":"", dname);
1103 * but this was measurably slower than doing the memcpy.
1106 pathreal = talloc_array(
1107 ctx, char,
1108 pathlen + slashlen + talloc_get_size(dname));
1109 if (!pathreal) {
1110 TALLOC_FREE(dname);
1111 TALLOC_FREE(fname);
1112 return false;
1115 memcpy(pathreal, dirptr->path, pathlen);
1116 pathreal[pathlen] = '/';
1117 memcpy(pathreal + slashlen + pathlen, dname,
1118 talloc_get_size(dname));
1120 /* Create smb_fname with NULL stream_name. */
1121 ZERO_STRUCT(smb_fname);
1122 smb_fname.base_name = pathreal;
1123 smb_fname.st = sbuf;
1125 ok = mode_fn(ctx, private_data, &smb_fname, &mode);
1126 if (!ok) {
1127 TALLOC_FREE(dname);
1128 TALLOC_FREE(fname);
1129 TALLOC_FREE(pathreal);
1130 continue;
1133 if (!dir_check_ftype(conn, mode, dirtype)) {
1134 DEBUG(5,("[%s] attribs 0x%x didn't match 0x%x\n",
1135 fname, (unsigned int)mode, (unsigned int)dirtype));
1136 TALLOC_FREE(dname);
1137 TALLOC_FREE(fname);
1138 TALLOC_FREE(pathreal);
1139 continue;
1142 if (ask_sharemode) {
1143 struct timespec write_time_ts;
1144 struct file_id fileid;
1146 fileid = vfs_file_id_from_sbuf(conn,
1147 &smb_fname.st);
1148 get_file_infos(fileid, 0, NULL, &write_time_ts);
1149 if (!null_timespec(write_time_ts)) {
1150 update_stat_ex_mtime(&smb_fname.st,
1151 write_time_ts);
1155 DEBUG(3,("smbd_dirptr_get_entry mask=[%s] found %s "
1156 "fname=%s (%s)\n",
1157 mask, smb_fname_str_dbg(&smb_fname),
1158 dname, fname));
1160 DirCacheAdd(dirptr->dir_hnd, dname, cur_offset);
1162 TALLOC_FREE(dname);
1164 status = copy_smb_filename(ctx, &smb_fname, _smb_fname);
1165 TALLOC_FREE(pathreal);
1166 if (!NT_STATUS_IS_OK(status)) {
1167 return false;
1169 *_fname = fname;
1170 *_mode = mode;
1171 *_prev_offset = prev_offset;
1173 return true;
1176 return false;
1179 /****************************************************************************
1180 Get an 8.3 directory entry.
1181 ****************************************************************************/
1183 static bool smbd_dirptr_8_3_match_fn(TALLOC_CTX *ctx,
1184 void *private_data,
1185 const char *dname,
1186 const char *mask,
1187 char **_fname)
1189 connection_struct *conn = (connection_struct *)private_data;
1191 if ((strcmp(mask,"*.*") == 0) ||
1192 mask_match_search(dname, mask, false) ||
1193 mangle_mask_match(conn, dname, mask)) {
1194 char mname[13];
1195 const char *fname;
1197 if (!mangle_is_8_3(dname, false, conn->params)) {
1198 bool ok = name_to_8_3(dname, mname, false,
1199 conn->params);
1200 if (!ok) {
1201 return false;
1203 fname = mname;
1204 } else {
1205 fname = dname;
1208 *_fname = talloc_strdup(ctx, fname);
1209 if (*_fname == NULL) {
1210 return false;
1213 return true;
1216 return false;
1219 static bool smbd_dirptr_8_3_mode_fn(TALLOC_CTX *ctx,
1220 void *private_data,
1221 struct smb_filename *smb_fname,
1222 uint32_t *_mode)
1224 connection_struct *conn = (connection_struct *)private_data;
1226 if (!VALID_STAT(smb_fname->st)) {
1227 if ((SMB_VFS_STAT(conn, smb_fname)) != 0) {
1228 DEBUG(5,("smbd_dirptr_8_3_mode_fn: "
1229 "Couldn't stat [%s]. Error "
1230 "= %s\n",
1231 smb_fname_str_dbg(smb_fname),
1232 strerror(errno)));
1233 return false;
1237 *_mode = dos_mode(conn, smb_fname);
1238 return true;
1241 bool get_dir_entry(TALLOC_CTX *ctx,
1242 struct dptr_struct *dirptr,
1243 const char *mask,
1244 uint32_t dirtype,
1245 char **_fname,
1246 off_t *_size,
1247 uint32_t *_mode,
1248 struct timespec *_date,
1249 bool check_descend,
1250 bool ask_sharemode)
1252 connection_struct *conn = dirptr->conn;
1253 char *fname = NULL;
1254 struct smb_filename *smb_fname = NULL;
1255 uint32_t mode = 0;
1256 long prev_offset;
1257 bool ok;
1259 ok = smbd_dirptr_get_entry(ctx,
1260 dirptr,
1261 mask,
1262 dirtype,
1263 check_descend,
1264 ask_sharemode,
1265 smbd_dirptr_8_3_match_fn,
1266 smbd_dirptr_8_3_mode_fn,
1267 conn,
1268 &fname,
1269 &smb_fname,
1270 &mode,
1271 &prev_offset);
1272 if (!ok) {
1273 return false;
1276 *_fname = talloc_move(ctx, &fname);
1277 *_size = smb_fname->st.st_ex_size;
1278 *_mode = mode;
1279 *_date = smb_fname->st.st_ex_mtime;
1280 TALLOC_FREE(smb_fname);
1281 return true;
1284 /*******************************************************************
1285 Check to see if a user can read a file. This is only approximate,
1286 it is used as part of the "hide unreadable" option. Don't
1287 use it for anything security sensitive.
1288 ********************************************************************/
1290 static bool user_can_read_file(connection_struct *conn,
1291 struct smb_filename *smb_fname)
1294 * Never hide files from the root user.
1295 * We use (uid_t)0 here not sec_initial_uid()
1296 * as make test uses a single user context.
1299 if (get_current_uid(conn) == (uid_t)0) {
1300 return True;
1303 return NT_STATUS_IS_OK(smbd_check_access_rights(conn,
1304 smb_fname,
1305 FILE_READ_DATA));
1308 /*******************************************************************
1309 Check to see if a user can write a file (and only files, we do not
1310 check dirs on this one). This is only approximate,
1311 it is used as part of the "hide unwriteable" option. Don't
1312 use it for anything security sensitive.
1313 ********************************************************************/
1315 static bool user_can_write_file(connection_struct *conn,
1316 const struct smb_filename *smb_fname)
1319 * Never hide files from the root user.
1320 * We use (uid_t)0 here not sec_initial_uid()
1321 * as make test uses a single user context.
1324 if (get_current_uid(conn) == (uid_t)0) {
1325 return True;
1328 SMB_ASSERT(VALID_STAT(smb_fname->st));
1330 /* Pseudo-open the file */
1332 if(S_ISDIR(smb_fname->st.st_ex_mode)) {
1333 return True;
1336 return can_write_to_file(conn, smb_fname);
1339 /*******************************************************************
1340 Is a file a "special" type ?
1341 ********************************************************************/
1343 static bool file_is_special(connection_struct *conn,
1344 const struct smb_filename *smb_fname)
1347 * Never hide files from the root user.
1348 * We use (uid_t)0 here not sec_initial_uid()
1349 * as make test uses a single user context.
1352 if (get_current_uid(conn) == (uid_t)0) {
1353 return False;
1356 SMB_ASSERT(VALID_STAT(smb_fname->st));
1358 if (S_ISREG(smb_fname->st.st_ex_mode) ||
1359 S_ISDIR(smb_fname->st.st_ex_mode) ||
1360 S_ISLNK(smb_fname->st.st_ex_mode))
1361 return False;
1363 return True;
1366 /*******************************************************************
1367 Should the file be seen by the client?
1368 NOTE: A successful return is no guarantee of the file's existence.
1369 ********************************************************************/
1371 bool is_visible_file(connection_struct *conn, const char *dir_path,
1372 const char *name, SMB_STRUCT_STAT *pst, bool use_veto)
1374 bool hide_unreadable = lp_hideunreadable(SNUM(conn));
1375 bool hide_unwriteable = lp_hideunwriteable_files(SNUM(conn));
1376 bool hide_special = lp_hide_special_files(SNUM(conn));
1377 char *entry = NULL;
1378 struct smb_filename *smb_fname_base = NULL;
1379 NTSTATUS status;
1380 bool ret = false;
1382 if ((strcmp(".",name) == 0) || (strcmp("..",name) == 0)) {
1383 return True; /* . and .. are always visible. */
1386 /* If it's a vetoed file, pretend it doesn't even exist */
1387 if (use_veto && IS_VETO_PATH(conn, name)) {
1388 DEBUG(10,("is_visible_file: file %s is vetoed.\n", name ));
1389 return False;
1392 if (hide_unreadable || hide_unwriteable || hide_special) {
1393 entry = talloc_asprintf(talloc_tos(), "%s/%s", dir_path, name);
1394 if (!entry) {
1395 ret = false;
1396 goto out;
1399 /* Create an smb_filename with stream_name == NULL. */
1400 status = create_synthetic_smb_fname(talloc_tos(), entry, NULL,
1401 pst, &smb_fname_base);
1402 if (!NT_STATUS_IS_OK(status)) {
1403 ret = false;
1404 goto out;
1407 /* If the file name does not exist, there's no point checking
1408 * the configuration options. We succeed, on the basis that the
1409 * checks *might* have passed if the file was present.
1411 if (!VALID_STAT(*pst)) {
1412 if (SMB_VFS_STAT(conn, smb_fname_base) != 0) {
1413 ret = true;
1414 goto out;
1415 } else {
1416 *pst = smb_fname_base->st;
1420 /* Honour _hide unreadable_ option */
1421 if (hide_unreadable &&
1422 !user_can_read_file(conn, smb_fname_base)) {
1423 DEBUG(10,("is_visible_file: file %s is unreadable.\n",
1424 entry ));
1425 ret = false;
1426 goto out;
1428 /* Honour _hide unwriteable_ option */
1429 if (hide_unwriteable && !user_can_write_file(conn,
1430 smb_fname_base)) {
1431 DEBUG(10,("is_visible_file: file %s is unwritable.\n",
1432 entry ));
1433 ret = false;
1434 goto out;
1436 /* Honour _hide_special_ option */
1437 if (hide_special && file_is_special(conn, smb_fname_base)) {
1438 DEBUG(10,("is_visible_file: file %s is special.\n",
1439 entry ));
1440 ret = false;
1441 goto out;
1445 ret = true;
1446 out:
1447 TALLOC_FREE(smb_fname_base);
1448 TALLOC_FREE(entry);
1449 return ret;
1452 static int smb_Dir_destructor(struct smb_Dir *dirp)
1454 if (dirp->dir != NULL) {
1455 SMB_VFS_CLOSEDIR(dirp->conn,dirp->dir);
1456 if (dirp->fsp != NULL) {
1458 * The SMB_VFS_CLOSEDIR above
1459 * closes the underlying fd inside
1460 * dirp->fsp.
1462 dirp->fsp->fh->fd = -1;
1463 if (dirp->fsp->dptr != NULL) {
1464 SMB_ASSERT(dirp->fsp->dptr->dir_hnd == dirp);
1465 dirp->fsp->dptr->dir_hnd = NULL;
1467 dirp->fsp = NULL;
1470 if (dirp->conn->sconn && !dirp->conn->sconn->using_smb2) {
1471 dirp->conn->sconn->searches.dirhandles_open--;
1473 return 0;
1476 /*******************************************************************
1477 Open a directory.
1478 ********************************************************************/
1480 struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn,
1481 const char *name,
1482 const char *mask,
1483 uint32 attr)
1485 struct smb_Dir *dirp = talloc_zero(mem_ctx, struct smb_Dir);
1486 struct smbd_server_connection *sconn = conn->sconn;
1488 if (!dirp) {
1489 return NULL;
1492 dirp->conn = conn;
1493 dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
1495 dirp->dir_path = talloc_strdup(dirp, name);
1496 if (!dirp->dir_path) {
1497 errno = ENOMEM;
1498 goto fail;
1501 if (sconn && !sconn->using_smb2) {
1502 sconn->searches.dirhandles_open++;
1504 talloc_set_destructor(dirp, smb_Dir_destructor);
1506 dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path, mask, attr);
1507 if (!dirp->dir) {
1508 DEBUG(5,("OpenDir: Can't open %s. %s\n", dirp->dir_path,
1509 strerror(errno) ));
1510 goto fail;
1513 return dirp;
1515 fail:
1516 TALLOC_FREE(dirp);
1517 return NULL;
1520 /*******************************************************************
1521 Open a directory from an fsp.
1522 ********************************************************************/
1524 static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn,
1525 files_struct *fsp,
1526 const char *mask,
1527 uint32 attr)
1529 struct smb_Dir *dirp = talloc_zero(mem_ctx, struct smb_Dir);
1530 struct smbd_server_connection *sconn = conn->sconn;
1532 if (!dirp) {
1533 return NULL;
1536 dirp->conn = conn;
1537 dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
1539 dirp->dir_path = talloc_strdup(dirp, fsp->fsp_name->base_name);
1540 if (!dirp->dir_path) {
1541 errno = ENOMEM;
1542 goto fail;
1545 if (sconn && !sconn->using_smb2) {
1546 sconn->searches.dirhandles_open++;
1548 talloc_set_destructor(dirp, smb_Dir_destructor);
1550 if (fsp->is_directory && fsp->fh->fd != -1) {
1551 dirp->dir = SMB_VFS_FDOPENDIR(fsp, mask, attr);
1552 if (dirp->dir != NULL) {
1553 dirp->fsp = fsp;
1554 } else {
1555 DEBUG(10,("OpenDir_fsp: SMB_VFS_FDOPENDIR on %s returned "
1556 "NULL (%s)\n",
1557 dirp->dir_path,
1558 strerror(errno)));
1559 if (errno != ENOSYS) {
1560 return NULL;
1565 if (dirp->dir == NULL) {
1566 /* FDOPENDIR didn't work. Use OPENDIR instead. */
1567 dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path, mask, attr);
1570 if (!dirp->dir) {
1571 DEBUG(5,("OpenDir_fsp: Can't open %s. %s\n", dirp->dir_path,
1572 strerror(errno) ));
1573 goto fail;
1576 return dirp;
1578 fail:
1579 TALLOC_FREE(dirp);
1580 return NULL;
1584 /*******************************************************************
1585 Read from a directory.
1586 Return directory entry, current offset, and optional stat information.
1587 Don't check for veto or invisible files.
1588 ********************************************************************/
1590 const char *ReadDirName(struct smb_Dir *dirp, long *poffset,
1591 SMB_STRUCT_STAT *sbuf, char **ptalloced)
1593 const char *n;
1594 char *talloced = NULL;
1595 connection_struct *conn = dirp->conn;
1597 /* Cheat to allow . and .. to be the first entries returned. */
1598 if (((*poffset == START_OF_DIRECTORY_OFFSET) ||
1599 (*poffset == DOT_DOT_DIRECTORY_OFFSET)) && (dirp->file_number < 2))
1601 if (dirp->file_number == 0) {
1602 n = ".";
1603 *poffset = dirp->offset = START_OF_DIRECTORY_OFFSET;
1604 } else {
1605 n = "..";
1606 *poffset = dirp->offset = DOT_DOT_DIRECTORY_OFFSET;
1608 dirp->file_number++;
1609 *ptalloced = NULL;
1610 return n;
1611 } else if (*poffset == END_OF_DIRECTORY_OFFSET) {
1612 *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1613 return NULL;
1614 } else {
1615 /* A real offset, seek to it. */
1616 SeekDir(dirp, *poffset);
1619 while ((n = vfs_readdirname(conn, dirp->dir, sbuf, &talloced))) {
1620 /* Ignore . and .. - we've already returned them. */
1621 if (*n == '.') {
1622 if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) {
1623 TALLOC_FREE(talloced);
1624 continue;
1627 *poffset = dirp->offset = SMB_VFS_TELLDIR(conn, dirp->dir);
1628 *ptalloced = talloced;
1629 dirp->file_number++;
1630 return n;
1632 *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1633 *ptalloced = NULL;
1634 return NULL;
1637 /*******************************************************************
1638 Rewind to the start.
1639 ********************************************************************/
1641 void RewindDir(struct smb_Dir *dirp, long *poffset)
1643 SMB_VFS_REWINDDIR(dirp->conn, dirp->dir);
1644 dirp->file_number = 0;
1645 dirp->offset = START_OF_DIRECTORY_OFFSET;
1646 *poffset = START_OF_DIRECTORY_OFFSET;
1649 /*******************************************************************
1650 Seek a dir.
1651 ********************************************************************/
1653 void SeekDir(struct smb_Dir *dirp, long offset)
1655 if (offset != dirp->offset) {
1656 if (offset == START_OF_DIRECTORY_OFFSET) {
1657 RewindDir(dirp, &offset);
1659 * Ok we should really set the file number here
1660 * to 1 to enable ".." to be returned next. Trouble
1661 * is I'm worried about callers using SeekDir(dirp,0)
1662 * as equivalent to RewindDir(). So leave this alone
1663 * for now.
1665 } else if (offset == DOT_DOT_DIRECTORY_OFFSET) {
1666 RewindDir(dirp, &offset);
1668 * Set the file number to 2 - we want to get the first
1669 * real file entry (the one we return after "..")
1670 * on the next ReadDir.
1672 dirp->file_number = 2;
1673 } else if (offset == END_OF_DIRECTORY_OFFSET) {
1674 ; /* Don't seek in this case. */
1675 } else {
1676 SMB_VFS_SEEKDIR(dirp->conn, dirp->dir, offset);
1678 dirp->offset = offset;
1682 /*******************************************************************
1683 Tell a dir position.
1684 ********************************************************************/
1686 long TellDir(struct smb_Dir *dirp)
1688 return(dirp->offset);
1691 /*******************************************************************
1692 Add an entry into the dcache.
1693 ********************************************************************/
1695 void DirCacheAdd(struct smb_Dir *dirp, const char *name, long offset)
1697 struct name_cache_entry *e;
1699 if (dirp->name_cache_size == 0) {
1700 return;
1703 if (dirp->name_cache == NULL) {
1704 dirp->name_cache = talloc_zero_array(
1705 dirp, struct name_cache_entry, dirp->name_cache_size);
1707 if (dirp->name_cache == NULL) {
1708 return;
1712 dirp->name_cache_index = (dirp->name_cache_index+1) %
1713 dirp->name_cache_size;
1714 e = &dirp->name_cache[dirp->name_cache_index];
1715 TALLOC_FREE(e->name);
1716 e->name = talloc_strdup(dirp, name);
1717 e->offset = offset;
1720 /*******************************************************************
1721 Find an entry by name. Leave us at the offset after it.
1722 Don't check for veto or invisible files.
1723 ********************************************************************/
1725 bool SearchDir(struct smb_Dir *dirp, const char *name, long *poffset)
1727 int i;
1728 const char *entry = NULL;
1729 char *talloced = NULL;
1730 connection_struct *conn = dirp->conn;
1732 /* Search back in the name cache. */
1733 if (dirp->name_cache_size && dirp->name_cache) {
1734 for (i = dirp->name_cache_index; i >= 0; i--) {
1735 struct name_cache_entry *e = &dirp->name_cache[i];
1736 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1737 *poffset = e->offset;
1738 SeekDir(dirp, e->offset);
1739 return True;
1742 for (i = dirp->name_cache_size - 1; i > dirp->name_cache_index; i--) {
1743 struct name_cache_entry *e = &dirp->name_cache[i];
1744 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1745 *poffset = e->offset;
1746 SeekDir(dirp, e->offset);
1747 return True;
1752 /* Not found in the name cache. Rewind directory and start from scratch. */
1753 SMB_VFS_REWINDDIR(conn, dirp->dir);
1754 dirp->file_number = 0;
1755 *poffset = START_OF_DIRECTORY_OFFSET;
1756 while ((entry = ReadDirName(dirp, poffset, NULL, &talloced))) {
1757 if (conn->case_sensitive ? (strcmp(entry, name) == 0) : strequal(entry, name)) {
1758 TALLOC_FREE(talloced);
1759 return True;
1761 TALLOC_FREE(talloced);
1763 return False;
1766 /*****************************************************************
1767 Is this directory empty ?
1768 *****************************************************************/
1770 NTSTATUS can_delete_directory_fsp(files_struct *fsp)
1772 NTSTATUS status = NT_STATUS_OK;
1773 long dirpos = 0;
1774 const char *dname = NULL;
1775 const char *dirname = fsp->fsp_name->base_name;
1776 char *talloced = NULL;
1777 SMB_STRUCT_STAT st;
1778 struct connection_struct *conn = fsp->conn;
1779 struct smb_Dir *dir_hnd = OpenDir_fsp(talloc_tos(),
1780 conn,
1781 fsp,
1782 NULL,
1785 if (!dir_hnd) {
1786 return map_nt_error_from_unix(errno);
1789 while ((dname = ReadDirName(dir_hnd, &dirpos, &st, &talloced))) {
1790 /* Quick check for "." and ".." */
1791 if (dname[0] == '.') {
1792 if (!dname[1] || (dname[1] == '.' && !dname[2])) {
1793 TALLOC_FREE(talloced);
1794 continue;
1798 if (!is_visible_file(conn, dirname, dname, &st, True)) {
1799 TALLOC_FREE(talloced);
1800 continue;
1803 DEBUG(10,("got name %s - can't delete\n",
1804 dname ));
1805 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
1806 break;
1808 TALLOC_FREE(talloced);
1809 TALLOC_FREE(dir_hnd);
1811 return status;