s3:smbd: avoid string_set() in dir.c
[Samba.git] / source3 / smbd / dir.c
blobe6f431eb33ed8da4f2a57906e4d439f6ea487f2a
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"
28 This module implements directory related functions for Samba.
31 /* "Special" directory offsets. */
32 #define END_OF_DIRECTORY_OFFSET ((long)-1)
33 #define START_OF_DIRECTORY_OFFSET ((long)0)
34 #define DOT_DOT_DIRECTORY_OFFSET ((long)0x80000000)
36 /* Make directory handle internals available. */
38 struct name_cache_entry {
39 char *name;
40 long offset;
43 struct smb_Dir {
44 connection_struct *conn;
45 SMB_STRUCT_DIR *dir;
46 long offset;
47 char *dir_path;
48 size_t name_cache_size;
49 struct name_cache_entry *name_cache;
50 unsigned int name_cache_index;
51 unsigned int file_number;
54 struct dptr_struct {
55 struct dptr_struct *next, *prev;
56 int dnum;
57 uint16 spid;
58 struct connection_struct *conn;
59 struct smb_Dir *dir_hnd;
60 bool expect_close;
61 char *wcard;
62 uint32 attr;
63 char *path;
64 bool has_wild; /* Set to true if the wcard entry has MS wildcard characters in it. */
65 bool did_stat; /* Optimisation for non-wcard searches. */
68 static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn,
69 files_struct *fsp,
70 const char *mask,
71 uint32 attr);
73 #define INVALID_DPTR_KEY (-3)
75 /****************************************************************************
76 Make a dir struct.
77 ****************************************************************************/
79 bool make_dir_struct(TALLOC_CTX *ctx,
80 char *buf,
81 const char *mask,
82 const char *fname,
83 SMB_OFF_T size,
84 uint32 mode,
85 time_t date,
86 bool uc)
88 char *p;
89 char *mask2 = talloc_strdup(ctx, mask);
91 if (!mask2) {
92 return False;
95 if ((mode & FILE_ATTRIBUTE_DIRECTORY) != 0) {
96 size = 0;
99 memset(buf+1,' ',11);
100 if ((p = strchr_m(mask2,'.')) != NULL) {
101 *p = 0;
102 push_ascii(buf+1,mask2,8, 0);
103 push_ascii(buf+9,p+1,3, 0);
104 *p = '.';
105 } else {
106 push_ascii(buf+1,mask2,11, 0);
109 memset(buf+21,'\0',DIR_STRUCT_SIZE-21);
110 SCVAL(buf,21,mode);
111 srv_put_dos_date(buf,22,date);
112 SSVAL(buf,26,size & 0xFFFF);
113 SSVAL(buf,28,(size >> 16)&0xFFFF);
114 /* We only uppercase if FLAGS2_LONG_PATH_COMPONENTS is zero in the input buf.
115 Strange, but verified on W2K3. Needed for OS/2. JRA. */
116 push_ascii(buf+30,fname,12, uc ? STR_UPPER : 0);
117 DEBUG(8,("put name [%s] from [%s] into dir struct\n",buf+30, fname));
118 return True;
121 /****************************************************************************
122 Initialise the dir bitmap.
123 ****************************************************************************/
125 bool init_dptrs(struct smbd_server_connection *sconn)
127 if (sconn->searches.dptr_bmap) {
128 return true;
131 sconn->searches.dptr_bmap = bitmap_talloc(
132 sconn, MAX_DIRECTORY_HANDLES);
134 if (sconn->searches.dptr_bmap == NULL) {
135 return false;
138 return true;
141 /****************************************************************************
142 Idle a dptr - the directory is closed but the control info is kept.
143 ****************************************************************************/
145 static void dptr_idle(struct dptr_struct *dptr)
147 if (dptr->dir_hnd) {
148 DEBUG(4,("Idling dptr dnum %d\n",dptr->dnum));
149 TALLOC_FREE(dptr->dir_hnd);
153 /****************************************************************************
154 Idle the oldest dptr.
155 ****************************************************************************/
157 static void dptr_idleoldest(struct smbd_server_connection *sconn)
159 struct dptr_struct *dptr;
162 * Go to the end of the list.
164 dptr = DLIST_TAIL(sconn->searches.dirptrs);
166 if(!dptr) {
167 DEBUG(0,("No dptrs available to idle ?\n"));
168 return;
172 * Idle the oldest pointer.
175 for(; dptr; dptr = DLIST_PREV(dptr)) {
176 if (dptr->dir_hnd) {
177 dptr_idle(dptr);
178 return;
183 /****************************************************************************
184 Get the struct dptr_struct for a dir index.
185 ****************************************************************************/
187 static struct dptr_struct *dptr_get(struct smbd_server_connection *sconn,
188 int key, bool forclose)
190 struct dptr_struct *dptr;
192 for(dptr = sconn->searches.dirptrs; dptr; dptr = dptr->next) {
193 if(dptr->dnum == key) {
194 if (!forclose && !dptr->dir_hnd) {
195 if (sconn->searches.dirhandles_open >= MAX_OPEN_DIRECTORIES)
196 dptr_idleoldest(sconn);
197 DEBUG(4,("dptr_get: Reopening dptr key %d\n",key));
198 if (!(dptr->dir_hnd = OpenDir(
199 NULL, dptr->conn, dptr->path,
200 dptr->wcard, dptr->attr))) {
201 DEBUG(4,("dptr_get: Failed to open %s (%s)\n",dptr->path,
202 strerror(errno)));
203 return False;
206 DLIST_PROMOTE(sconn->searches.dirptrs,dptr);
207 return dptr;
210 return(NULL);
213 /****************************************************************************
214 Get the dir path for a dir index.
215 ****************************************************************************/
217 char *dptr_path(struct smbd_server_connection *sconn, int key)
219 struct dptr_struct *dptr = dptr_get(sconn, key, false);
220 if (dptr)
221 return(dptr->path);
222 return(NULL);
225 /****************************************************************************
226 Get the dir wcard for a dir index.
227 ****************************************************************************/
229 char *dptr_wcard(struct smbd_server_connection *sconn, int key)
231 struct dptr_struct *dptr = dptr_get(sconn, key, false);
232 if (dptr)
233 return(dptr->wcard);
234 return(NULL);
237 /****************************************************************************
238 Get the dir attrib for a dir index.
239 ****************************************************************************/
241 uint16 dptr_attr(struct smbd_server_connection *sconn, int key)
243 struct dptr_struct *dptr = dptr_get(sconn, key, false);
244 if (dptr)
245 return(dptr->attr);
246 return(0);
249 /****************************************************************************
250 Close a dptr (internal func).
251 ****************************************************************************/
253 static void dptr_close_internal(struct dptr_struct *dptr)
255 struct smbd_server_connection *sconn = dptr->conn->sconn;
257 DEBUG(4,("closing dptr key %d\n",dptr->dnum));
259 if (sconn == NULL) {
260 goto done;
263 DLIST_REMOVE(sconn->searches.dirptrs, dptr);
266 * Free the dnum in the bitmap. Remember the dnum value is always
267 * biased by one with respect to the bitmap.
270 if (!bitmap_query(sconn->searches.dptr_bmap, dptr->dnum - 1)) {
271 DEBUG(0,("dptr_close_internal : Error - closing dnum = %d and bitmap not set !\n",
272 dptr->dnum ));
275 bitmap_clear(sconn->searches.dptr_bmap, dptr->dnum - 1);
277 done:
278 TALLOC_FREE(dptr->dir_hnd);
280 /* Lanman 2 specific code */
281 SAFE_FREE(dptr->wcard);
282 SAFE_FREE(dptr->path);
283 SAFE_FREE(dptr);
286 /****************************************************************************
287 Close a dptr given a key.
288 ****************************************************************************/
290 void dptr_close(struct smbd_server_connection *sconn, int *key)
292 struct dptr_struct *dptr;
294 if(*key == INVALID_DPTR_KEY)
295 return;
297 /* OS/2 seems to use -1 to indicate "close all directories" */
298 if (*key == -1) {
299 struct dptr_struct *next;
300 for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
301 next = dptr->next;
302 dptr_close_internal(dptr);
304 *key = INVALID_DPTR_KEY;
305 return;
308 dptr = dptr_get(sconn, *key, true);
310 if (!dptr) {
311 DEBUG(0,("Invalid key %d given to dptr_close\n", *key));
312 return;
315 dptr_close_internal(dptr);
317 *key = INVALID_DPTR_KEY;
320 /****************************************************************************
321 Close all dptrs for a cnum.
322 ****************************************************************************/
324 void dptr_closecnum(connection_struct *conn)
326 struct dptr_struct *dptr, *next;
327 struct smbd_server_connection *sconn = conn->sconn;
329 if (sconn == NULL) {
330 return;
333 for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
334 next = dptr->next;
335 if (dptr->conn == conn) {
336 dptr_close_internal(dptr);
341 /****************************************************************************
342 Idle all dptrs for a cnum.
343 ****************************************************************************/
345 void dptr_idlecnum(connection_struct *conn)
347 struct dptr_struct *dptr;
348 struct smbd_server_connection *sconn = conn->sconn;
350 if (sconn == NULL) {
351 return;
354 for(dptr = sconn->searches.dirptrs; dptr; dptr = dptr->next) {
355 if (dptr->conn == conn && dptr->dir_hnd) {
356 dptr_idle(dptr);
361 /****************************************************************************
362 Close a dptr that matches a given path, only if it matches the spid also.
363 ****************************************************************************/
365 void dptr_closepath(struct smbd_server_connection *sconn,
366 char *path,uint16 spid)
368 struct dptr_struct *dptr, *next;
369 for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
370 next = dptr->next;
371 if (spid == dptr->spid && strequal(dptr->path,path))
372 dptr_close_internal(dptr);
376 /****************************************************************************
377 Try and close the oldest handle not marked for
378 expect close in the hope that the client has
379 finished with that one.
380 ****************************************************************************/
382 static void dptr_close_oldest(struct smbd_server_connection *sconn,
383 bool old)
385 struct dptr_struct *dptr;
388 * Go to the end of the list.
390 for(dptr = sconn->searches.dirptrs; dptr && dptr->next; dptr = dptr->next)
393 if(!dptr) {
394 DEBUG(0,("No old dptrs available to close oldest ?\n"));
395 return;
399 * If 'old' is true, close the oldest oldhandle dnum (ie. 1 < dnum < 256) that
400 * does not have expect_close set. If 'old' is false, close
401 * one of the new dnum handles.
404 for(; dptr; dptr = DLIST_PREV(dptr)) {
405 if ((old && (dptr->dnum < 256) && !dptr->expect_close) ||
406 (!old && (dptr->dnum > 255))) {
407 dptr_close_internal(dptr);
408 return;
413 /****************************************************************************
414 Create a new dir ptr. If the flag old_handle is true then we must allocate
415 from the bitmap range 0 - 255 as old SMBsearch directory handles are only
416 one byte long. If old_handle is false we allocate from the range
417 256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
418 a directory handle is never zero.
419 wcard must not be zero.
420 ****************************************************************************/
422 NTSTATUS dptr_create(connection_struct *conn, files_struct *fsp,
423 const char *path, bool old_handle, bool expect_close,uint16 spid,
424 const char *wcard, bool wcard_has_wild, uint32 attr, struct dptr_struct **dptr_ret)
426 struct smbd_server_connection *sconn = conn->sconn;
427 struct dptr_struct *dptr = NULL;
428 struct smb_Dir *dir_hnd;
429 NTSTATUS status;
431 if (fsp && fsp->is_directory && fsp->fh->fd != -1) {
432 path = fsp->fsp_name->base_name;
435 DEBUG(5,("dptr_create dir=%s\n", path));
437 if (sconn == NULL) {
438 DEBUG(0,("dptr_create: called with fake connection_struct\n"));
439 return NT_STATUS_INTERNAL_ERROR;
442 if (!wcard) {
443 return NT_STATUS_INVALID_PARAMETER;
446 if (fsp) {
447 dir_hnd = OpenDir_fsp(NULL, conn, fsp, wcard, attr);
448 } else {
449 status = check_name(conn,path);
450 if (!NT_STATUS_IS_OK(status)) {
451 return status;
453 dir_hnd = OpenDir(NULL, conn, path, wcard, attr);
456 if (!dir_hnd) {
457 return map_nt_error_from_unix(errno);
460 if (sconn->searches.dirhandles_open >= MAX_OPEN_DIRECTORIES) {
461 dptr_idleoldest(sconn);
464 dptr = SMB_MALLOC_P(struct dptr_struct);
465 if(!dptr) {
466 DEBUG(0,("malloc fail in dptr_create.\n"));
467 TALLOC_FREE(dir_hnd);
468 return NT_STATUS_NO_MEMORY;
471 ZERO_STRUCTP(dptr);
473 if(old_handle) {
476 * This is an old-style SMBsearch request. Ensure the
477 * value we return will fit in the range 1-255.
480 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 0);
482 if(dptr->dnum == -1 || dptr->dnum > 254) {
485 * Try and close the oldest handle not marked for
486 * expect close in the hope that the client has
487 * finished with that one.
490 dptr_close_oldest(sconn, true);
492 /* Now try again... */
493 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 0);
494 if(dptr->dnum == -1 || dptr->dnum > 254) {
495 DEBUG(0,("dptr_create: returned %d: Error - all old dirptrs in use ?\n", dptr->dnum));
496 SAFE_FREE(dptr);
497 TALLOC_FREE(dir_hnd);
498 return NT_STATUS_TOO_MANY_OPENED_FILES;
501 } else {
504 * This is a new-style trans2 request. Allocate from
505 * a range that will return 256 - MAX_DIRECTORY_HANDLES.
508 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 255);
510 if(dptr->dnum == -1 || dptr->dnum < 255) {
513 * Try and close the oldest handle close in the hope that
514 * the client has finished with that one. This will only
515 * happen in the case of the Win98 client bug where it leaks
516 * directory handles.
519 dptr_close_oldest(sconn, false);
521 /* Now try again... */
522 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 255);
524 if(dptr->dnum == -1 || dptr->dnum < 255) {
525 DEBUG(0,("dptr_create: returned %d: Error - all new dirptrs in use ?\n", dptr->dnum));
526 SAFE_FREE(dptr);
527 TALLOC_FREE(dir_hnd);
528 return NT_STATUS_TOO_MANY_OPENED_FILES;
533 bitmap_set(sconn->searches.dptr_bmap, dptr->dnum);
535 dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
537 dptr->path = SMB_STRDUP(path);
538 if (!dptr->path) {
539 bitmap_clear(sconn->searches.dptr_bmap, dptr->dnum - 1);
540 SAFE_FREE(dptr);
541 TALLOC_FREE(dir_hnd);
542 return NT_STATUS_NO_MEMORY;
544 dptr->conn = conn;
545 dptr->dir_hnd = dir_hnd;
546 dptr->spid = spid;
547 dptr->expect_close = expect_close;
548 dptr->wcard = SMB_STRDUP(wcard);
549 if (!dptr->wcard) {
550 bitmap_clear(sconn->searches.dptr_bmap, dptr->dnum - 1);
551 SAFE_FREE(dptr->path);
552 SAFE_FREE(dptr);
553 TALLOC_FREE(dir_hnd);
554 return NT_STATUS_NO_MEMORY;
556 if (lp_posix_pathnames() || (wcard[0] == '.' && wcard[1] == 0)) {
557 dptr->has_wild = True;
558 } else {
559 dptr->has_wild = wcard_has_wild;
562 dptr->attr = attr;
564 DLIST_ADD(sconn->searches.dirptrs, dptr);
566 DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
567 dptr->dnum,path,expect_close));
569 *dptr_ret = dptr;
571 return NT_STATUS_OK;
575 /****************************************************************************
576 Wrapper functions to access the lower level directory handles.
577 ****************************************************************************/
579 void dptr_CloseDir(files_struct *fsp)
581 if (fsp->dptr) {
583 * Ugly hack. We have defined fdopendir to return ENOSYS if dirfd also isn't
584 * present. I hate Solaris. JRA.
586 #ifdef HAVE_DIRFD
587 if (fsp->fh->fd != -1 &&
588 fsp->dptr->dir_hnd &&
589 dirfd(fsp->dptr->dir_hnd->dir)) {
590 /* The call below closes the underlying fd. */
591 fsp->fh->fd = -1;
593 #endif
594 dptr_close_internal(fsp->dptr);
595 fsp->dptr = NULL;
599 void dptr_SeekDir(struct dptr_struct *dptr, long offset)
601 SeekDir(dptr->dir_hnd, offset);
604 long dptr_TellDir(struct dptr_struct *dptr)
606 return TellDir(dptr->dir_hnd);
609 bool dptr_has_wild(struct dptr_struct *dptr)
611 return dptr->has_wild;
614 int dptr_dnum(struct dptr_struct *dptr)
616 return dptr->dnum;
619 /****************************************************************************
620 Return the next visible file name, skipping veto'd and invisible files.
621 ****************************************************************************/
623 static const char *dptr_normal_ReadDirName(struct dptr_struct *dptr,
624 long *poffset, SMB_STRUCT_STAT *pst,
625 char **ptalloced)
627 /* Normal search for the next file. */
628 const char *name;
629 char *talloced = NULL;
631 while ((name = ReadDirName(dptr->dir_hnd, poffset, pst, &talloced))
632 != NULL) {
633 if (is_visible_file(dptr->conn, dptr->path, name, pst, True)) {
634 *ptalloced = talloced;
635 return name;
637 TALLOC_FREE(talloced);
639 return NULL;
642 /****************************************************************************
643 Return the next visible file name, skipping veto'd and invisible files.
644 ****************************************************************************/
646 char *dptr_ReadDirName(TALLOC_CTX *ctx,
647 struct dptr_struct *dptr,
648 long *poffset,
649 SMB_STRUCT_STAT *pst)
651 struct smb_filename smb_fname_base;
652 char *name = NULL;
653 const char *name_temp = NULL;
654 char *talloced = NULL;
655 char *pathreal = NULL;
656 char *found_name = NULL;
657 int ret;
659 SET_STAT_INVALID(*pst);
661 if (dptr->has_wild || dptr->did_stat) {
662 name_temp = dptr_normal_ReadDirName(dptr, poffset, pst,
663 &talloced);
664 if (name_temp == NULL) {
665 return NULL;
667 if (talloced != NULL) {
668 return talloc_move(ctx, &talloced);
670 return talloc_strdup(ctx, name_temp);
673 /* If poffset is -1 then we know we returned this name before and we
674 * have no wildcards. We're at the end of the directory. */
675 if (*poffset == END_OF_DIRECTORY_OFFSET) {
676 return NULL;
679 /* We know the stored wcard contains no wildcard characters.
680 * See if we can match with a stat call. If we can't, then set
681 * did_stat to true to ensure we only do this once and keep
682 * searching. */
684 dptr->did_stat = true;
686 /* First check if it should be visible. */
687 if (!is_visible_file(dptr->conn, dptr->path, dptr->wcard,
688 pst, true))
690 /* This only returns false if the file was found, but
691 is explicitly not visible. Set us to end of
692 directory, but return NULL as we know we can't ever
693 find it. */
694 goto ret;
697 if (VALID_STAT(*pst)) {
698 name = talloc_strdup(ctx, dptr->wcard);
699 goto ret;
702 pathreal = talloc_asprintf(ctx,
703 "%s/%s",
704 dptr->path,
705 dptr->wcard);
706 if (!pathreal)
707 return NULL;
709 /* Create an smb_filename with stream_name == NULL. */
710 ZERO_STRUCT(smb_fname_base);
711 smb_fname_base.base_name = pathreal;
713 if (SMB_VFS_STAT(dptr->conn, &smb_fname_base) == 0) {
714 *pst = smb_fname_base.st;
715 name = talloc_strdup(ctx, dptr->wcard);
716 goto clean;
717 } else {
718 /* If we get any other error than ENOENT or ENOTDIR
719 then the file exists we just can't stat it. */
720 if (errno != ENOENT && errno != ENOTDIR) {
721 name = talloc_strdup(ctx, dptr->wcard);
722 goto clean;
726 /* Stat failed. We know this is authoratiative if we are
727 * providing case sensitive semantics or the underlying
728 * filesystem is case sensitive.
730 if (dptr->conn->case_sensitive ||
731 !(dptr->conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH))
733 goto clean;
737 * Try case-insensitive stat if the fs has the ability. This avoids
738 * scanning the whole directory.
740 ret = SMB_VFS_GET_REAL_FILENAME(dptr->conn, dptr->path, dptr->wcard,
741 ctx, &found_name);
742 if (ret == 0) {
743 name = found_name;
744 goto clean;
745 } else if (errno == ENOENT) {
746 /* The case-insensitive lookup was authoritative. */
747 goto clean;
750 TALLOC_FREE(pathreal);
752 name_temp = dptr_normal_ReadDirName(dptr, poffset, pst, &talloced);
753 if (name_temp == NULL) {
754 return NULL;
756 if (talloced != NULL) {
757 return talloc_move(ctx, &talloced);
759 return talloc_strdup(ctx, name_temp);
761 clean:
762 TALLOC_FREE(pathreal);
763 ret:
764 /* We need to set the underlying dir_hnd offset to -1
765 * also as this function is usually called with the
766 * output from TellDir. */
767 dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
768 return name;
771 /****************************************************************************
772 Search for a file by name, skipping veto'ed and not visible files.
773 ****************************************************************************/
775 bool dptr_SearchDir(struct dptr_struct *dptr, const char *name, long *poffset, SMB_STRUCT_STAT *pst)
777 SET_STAT_INVALID(*pst);
779 if (!dptr->has_wild && (dptr->dir_hnd->offset == END_OF_DIRECTORY_OFFSET)) {
780 /* This is a singleton directory and we're already at the end. */
781 *poffset = END_OF_DIRECTORY_OFFSET;
782 return False;
785 return SearchDir(dptr->dir_hnd, name, poffset);
788 /****************************************************************************
789 Add the name we're returning into the underlying cache.
790 ****************************************************************************/
792 void dptr_DirCacheAdd(struct dptr_struct *dptr, const char *name, long offset)
794 DirCacheAdd(dptr->dir_hnd, name, offset);
797 /****************************************************************************
798 Initialize variables & state data at the beginning of all search SMB requests.
799 ****************************************************************************/
800 void dptr_init_search_op(struct dptr_struct *dptr)
802 SMB_VFS_INIT_SEARCH_OP(dptr->conn, dptr->dir_hnd->dir);
805 /****************************************************************************
806 Fill the 5 byte server reserved dptr field.
807 ****************************************************************************/
809 bool dptr_fill(struct smbd_server_connection *sconn,
810 char *buf1,unsigned int key)
812 unsigned char *buf = (unsigned char *)buf1;
813 struct dptr_struct *dptr = dptr_get(sconn, key, false);
814 uint32 offset;
815 if (!dptr) {
816 DEBUG(1,("filling null dirptr %d\n",key));
817 return(False);
819 offset = (uint32)TellDir(dptr->dir_hnd);
820 DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key,
821 (long)dptr->dir_hnd,(int)offset));
822 buf[0] = key;
823 SIVAL(buf,1,offset);
824 return(True);
827 /****************************************************************************
828 Fetch the dir ptr and seek it given the 5 byte server field.
829 ****************************************************************************/
831 struct dptr_struct *dptr_fetch(struct smbd_server_connection *sconn,
832 char *buf, int *num)
834 unsigned int key = *(unsigned char *)buf;
835 struct dptr_struct *dptr = dptr_get(sconn, key, false);
836 uint32 offset;
837 long seekoff;
839 if (!dptr) {
840 DEBUG(3,("fetched null dirptr %d\n",key));
841 return(NULL);
843 *num = key;
844 offset = IVAL(buf,1);
845 if (offset == (uint32)-1) {
846 seekoff = END_OF_DIRECTORY_OFFSET;
847 } else {
848 seekoff = (long)offset;
850 SeekDir(dptr->dir_hnd,seekoff);
851 DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
852 key, dptr->path, (int)seekoff));
853 return(dptr);
856 /****************************************************************************
857 Fetch the dir ptr.
858 ****************************************************************************/
860 struct dptr_struct *dptr_fetch_lanman2(struct smbd_server_connection *sconn,
861 int dptr_num)
863 struct dptr_struct *dptr = dptr_get(sconn, dptr_num, false);
865 if (!dptr) {
866 DEBUG(3,("fetched null dirptr %d\n",dptr_num));
867 return(NULL);
869 DEBUG(3,("fetching dirptr %d for path %s\n",dptr_num,dptr->path));
870 return(dptr);
873 /****************************************************************************
874 Check that a file matches a particular file type.
875 ****************************************************************************/
877 bool dir_check_ftype(connection_struct *conn, uint32 mode, uint32 dirtype)
879 uint32 mask;
881 /* Check the "may have" search bits. */
882 if (((mode & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY)) != 0)
883 return False;
885 /* Check the "must have" bits, which are the may have bits shifted eight */
886 /* If must have bit is set, the file/dir can not be returned in search unless the matching
887 file attribute is set */
888 mask = ((dirtype >> 8) & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)); /* & 0x37 */
889 if(mask) {
890 if((mask & (mode & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM))) == mask) /* check if matching attribute present */
891 return True;
892 else
893 return False;
896 return True;
899 static bool mangle_mask_match(connection_struct *conn,
900 const char *filename,
901 const char *mask)
903 char mname[13];
905 if (!name_to_8_3(filename,mname,False,conn->params)) {
906 return False;
908 return mask_match_search(mname,mask,False);
911 bool smbd_dirptr_get_entry(TALLOC_CTX *ctx,
912 struct dptr_struct *dirptr,
913 const char *mask,
914 uint32_t dirtype,
915 bool dont_descend,
916 bool ask_sharemode,
917 bool (*match_fn)(TALLOC_CTX *ctx,
918 void *private_data,
919 const char *dname,
920 const char *mask,
921 char **_fname),
922 bool (*mode_fn)(TALLOC_CTX *ctx,
923 void *private_data,
924 struct smb_filename *smb_fname,
925 uint32_t *_mode),
926 void *private_data,
927 char **_fname,
928 struct smb_filename **_smb_fname,
929 uint32_t *_mode,
930 long *_prev_offset)
932 connection_struct *conn = dirptr->conn;
933 bool needslash;
935 *_smb_fname = NULL;
936 *_mode = 0;
938 needslash = ( dirptr->path[strlen(dirptr->path) -1] != '/');
940 while (true) {
941 long cur_offset;
942 long prev_offset;
943 SMB_STRUCT_STAT sbuf;
944 char *dname = NULL;
945 bool isdots;
946 char *fname = NULL;
947 char *pathreal = NULL;
948 struct smb_filename smb_fname;
949 uint32_t mode = 0;
950 bool ok;
951 NTSTATUS status;
953 cur_offset = dptr_TellDir(dirptr);
954 prev_offset = cur_offset;
955 dname = dptr_ReadDirName(ctx, dirptr, &cur_offset, &sbuf);
957 DEBUG(6,("smbd_dirptr_get_entry: dirptr 0x%lx now at offset %ld\n",
958 (long)dirptr, cur_offset));
960 if (dname == NULL) {
961 return false;
964 isdots = (ISDOT(dname) || ISDOTDOT(dname));
965 if (dont_descend && !isdots) {
966 TALLOC_FREE(dname);
967 continue;
971 * fname may get mangled, dname is never mangled.
972 * Whenever we're accessing the filesystem we use
973 * pathreal which is composed from dname.
976 ok = match_fn(ctx, private_data, dname, mask, &fname);
977 if (!ok) {
978 TALLOC_FREE(dname);
979 continue;
982 pathreal = talloc_asprintf(ctx, "%s%s%s",
983 dirptr->path,
984 needslash?"/":"",
985 dname);
986 if (!pathreal) {
987 TALLOC_FREE(dname);
988 TALLOC_FREE(fname);
989 return false;
992 /* Create smb_fname with NULL stream_name. */
993 ZERO_STRUCT(smb_fname);
994 smb_fname.base_name = pathreal;
995 smb_fname.st = sbuf;
997 ok = mode_fn(ctx, private_data, &smb_fname, &mode);
998 if (!ok) {
999 TALLOC_FREE(dname);
1000 TALLOC_FREE(fname);
1001 TALLOC_FREE(pathreal);
1002 continue;
1005 if (!dir_check_ftype(conn, mode, dirtype)) {
1006 DEBUG(5,("[%s] attribs 0x%x didn't match 0x%x\n",
1007 fname, (unsigned int)mode, (unsigned int)dirtype));
1008 TALLOC_FREE(dname);
1009 TALLOC_FREE(fname);
1010 TALLOC_FREE(pathreal);
1011 continue;
1014 if (ask_sharemode) {
1015 struct timespec write_time_ts;
1016 struct file_id fileid;
1018 fileid = vfs_file_id_from_sbuf(conn,
1019 &smb_fname.st);
1020 get_file_infos(fileid, 0, NULL, &write_time_ts);
1021 if (!null_timespec(write_time_ts)) {
1022 update_stat_ex_mtime(&smb_fname.st,
1023 write_time_ts);
1027 DEBUG(3,("smbd_dirptr_get_entry mask=[%s] found %s "
1028 "fname=%s (%s)\n",
1029 mask, smb_fname_str_dbg(&smb_fname),
1030 dname, fname));
1032 DirCacheAdd(dirptr->dir_hnd, dname, cur_offset);
1034 TALLOC_FREE(dname);
1036 status = copy_smb_filename(ctx, &smb_fname, _smb_fname);
1037 TALLOC_FREE(pathreal);
1038 if (!NT_STATUS_IS_OK(status)) {
1039 return false;
1041 *_fname = fname;
1042 *_mode = mode;
1043 *_prev_offset = prev_offset;
1045 return true;
1048 return false;
1051 /****************************************************************************
1052 Get an 8.3 directory entry.
1053 ****************************************************************************/
1055 static bool smbd_dirptr_8_3_match_fn(TALLOC_CTX *ctx,
1056 void *private_data,
1057 const char *dname,
1058 const char *mask,
1059 char **_fname)
1061 connection_struct *conn = (connection_struct *)private_data;
1063 if ((strcmp(mask,"*.*") == 0) ||
1064 mask_match_search(dname, mask, false) ||
1065 mangle_mask_match(conn, dname, mask)) {
1066 char mname[13];
1067 const char *fname;
1069 if (!mangle_is_8_3(dname, false, conn->params)) {
1070 bool ok = name_to_8_3(dname, mname, false,
1071 conn->params);
1072 if (!ok) {
1073 return false;
1075 fname = mname;
1076 } else {
1077 fname = dname;
1080 *_fname = talloc_strdup(ctx, fname);
1081 if (*_fname == NULL) {
1082 return false;
1085 return true;
1088 return false;
1091 static bool smbd_dirptr_8_3_mode_fn(TALLOC_CTX *ctx,
1092 void *private_data,
1093 struct smb_filename *smb_fname,
1094 uint32_t *_mode)
1096 connection_struct *conn = (connection_struct *)private_data;
1098 if (!VALID_STAT(smb_fname->st)) {
1099 if ((SMB_VFS_STAT(conn, smb_fname)) != 0) {
1100 DEBUG(5,("smbd_dirptr_8_3_mode_fn: "
1101 "Couldn't stat [%s]. Error "
1102 "= %s\n",
1103 smb_fname_str_dbg(smb_fname),
1104 strerror(errno)));
1105 return false;
1109 *_mode = dos_mode(conn, smb_fname);
1110 return true;
1113 bool get_dir_entry(TALLOC_CTX *ctx,
1114 struct dptr_struct *dirptr,
1115 const char *mask,
1116 uint32_t dirtype,
1117 char **_fname,
1118 SMB_OFF_T *_size,
1119 uint32_t *_mode,
1120 struct timespec *_date,
1121 bool check_descend,
1122 bool ask_sharemode)
1124 connection_struct *conn = dirptr->conn;
1125 char *fname = NULL;
1126 struct smb_filename *smb_fname = NULL;
1127 uint32_t mode = 0;
1128 long prev_offset;
1129 bool ok;
1131 ok = smbd_dirptr_get_entry(ctx,
1132 dirptr,
1133 mask,
1134 dirtype,
1135 check_descend,
1136 ask_sharemode,
1137 smbd_dirptr_8_3_match_fn,
1138 smbd_dirptr_8_3_mode_fn,
1139 conn,
1140 &fname,
1141 &smb_fname,
1142 &mode,
1143 &prev_offset);
1144 if (!ok) {
1145 return false;
1148 *_fname = talloc_move(ctx, &fname);
1149 *_size = smb_fname->st.st_ex_size;
1150 *_mode = mode;
1151 *_date = smb_fname->st.st_ex_mtime;
1152 TALLOC_FREE(smb_fname);
1153 return true;
1156 /*******************************************************************
1157 Check to see if a user can read a file. This is only approximate,
1158 it is used as part of the "hide unreadable" option. Don't
1159 use it for anything security sensitive.
1160 ********************************************************************/
1162 static bool user_can_read_file(connection_struct *conn,
1163 struct smb_filename *smb_fname)
1166 * Never hide files from the root user.
1167 * We use (uid_t)0 here not sec_initial_uid()
1168 * as make test uses a single user context.
1171 if (get_current_uid(conn) == (uid_t)0) {
1172 return True;
1175 return can_access_file_acl(conn, smb_fname, FILE_READ_DATA);
1178 /*******************************************************************
1179 Check to see if a user can write a file (and only files, we do not
1180 check dirs on this one). This is only approximate,
1181 it is used as part of the "hide unwriteable" option. Don't
1182 use it for anything security sensitive.
1183 ********************************************************************/
1185 static bool user_can_write_file(connection_struct *conn,
1186 const struct smb_filename *smb_fname)
1189 * Never hide files from the root user.
1190 * We use (uid_t)0 here not sec_initial_uid()
1191 * as make test uses a single user context.
1194 if (get_current_uid(conn) == (uid_t)0) {
1195 return True;
1198 SMB_ASSERT(VALID_STAT(smb_fname->st));
1200 /* Pseudo-open the file */
1202 if(S_ISDIR(smb_fname->st.st_ex_mode)) {
1203 return True;
1206 return can_write_to_file(conn, smb_fname);
1209 /*******************************************************************
1210 Is a file a "special" type ?
1211 ********************************************************************/
1213 static bool file_is_special(connection_struct *conn,
1214 const struct smb_filename *smb_fname)
1217 * Never hide files from the root user.
1218 * We use (uid_t)0 here not sec_initial_uid()
1219 * as make test uses a single user context.
1222 if (get_current_uid(conn) == (uid_t)0) {
1223 return False;
1226 SMB_ASSERT(VALID_STAT(smb_fname->st));
1228 if (S_ISREG(smb_fname->st.st_ex_mode) ||
1229 S_ISDIR(smb_fname->st.st_ex_mode) ||
1230 S_ISLNK(smb_fname->st.st_ex_mode))
1231 return False;
1233 return True;
1236 /*******************************************************************
1237 Should the file be seen by the client?
1238 NOTE: A successful return is no guarantee of the file's existence.
1239 ********************************************************************/
1241 bool is_visible_file(connection_struct *conn, const char *dir_path,
1242 const char *name, SMB_STRUCT_STAT *pst, bool use_veto)
1244 bool hide_unreadable = lp_hideunreadable(SNUM(conn));
1245 bool hide_unwriteable = lp_hideunwriteable_files(SNUM(conn));
1246 bool hide_special = lp_hide_special_files(SNUM(conn));
1247 char *entry = NULL;
1248 struct smb_filename *smb_fname_base = NULL;
1249 NTSTATUS status;
1250 bool ret = false;
1252 if ((strcmp(".",name) == 0) || (strcmp("..",name) == 0)) {
1253 return True; /* . and .. are always visible. */
1256 /* If it's a vetoed file, pretend it doesn't even exist */
1257 if (use_veto && IS_VETO_PATH(conn, name)) {
1258 DEBUG(10,("is_visible_file: file %s is vetoed.\n", name ));
1259 return False;
1262 if (hide_unreadable || hide_unwriteable || hide_special) {
1263 entry = talloc_asprintf(talloc_tos(), "%s/%s", dir_path, name);
1264 if (!entry) {
1265 ret = false;
1266 goto out;
1269 /* Create an smb_filename with stream_name == NULL. */
1270 status = create_synthetic_smb_fname(talloc_tos(), entry, NULL,
1271 pst, &smb_fname_base);
1272 if (!NT_STATUS_IS_OK(status)) {
1273 ret = false;
1274 goto out;
1277 /* If the file name does not exist, there's no point checking
1278 * the configuration options. We succeed, on the basis that the
1279 * checks *might* have passed if the file was present.
1281 if (!VALID_STAT(*pst)) {
1282 if (SMB_VFS_STAT(conn, smb_fname_base) != 0) {
1283 ret = true;
1284 goto out;
1285 } else {
1286 *pst = smb_fname_base->st;
1290 /* Honour _hide unreadable_ option */
1291 if (hide_unreadable &&
1292 !user_can_read_file(conn, smb_fname_base)) {
1293 DEBUG(10,("is_visible_file: file %s is unreadable.\n",
1294 entry ));
1295 ret = false;
1296 goto out;
1298 /* Honour _hide unwriteable_ option */
1299 if (hide_unwriteable && !user_can_write_file(conn,
1300 smb_fname_base)) {
1301 DEBUG(10,("is_visible_file: file %s is unwritable.\n",
1302 entry ));
1303 ret = false;
1304 goto out;
1306 /* Honour _hide_special_ option */
1307 if (hide_special && file_is_special(conn, smb_fname_base)) {
1308 DEBUG(10,("is_visible_file: file %s is special.\n",
1309 entry ));
1310 ret = false;
1311 goto out;
1315 ret = true;
1316 out:
1317 TALLOC_FREE(smb_fname_base);
1318 TALLOC_FREE(entry);
1319 return ret;
1322 static int smb_Dir_destructor(struct smb_Dir *dirp)
1324 if (dirp->dir) {
1325 #ifdef HAVE_DIRFD
1326 if (dirp->conn->sconn) {
1327 files_struct *fsp = file_find_fd(dirp->conn->sconn,
1328 dirfd(dirp->dir));
1329 if (fsp) {
1330 /* The call below closes the underlying fd. */
1331 fsp->fh->fd = -1;
1334 #endif
1335 SMB_VFS_CLOSEDIR(dirp->conn,dirp->dir);
1337 if (dirp->conn->sconn) {
1338 dirp->conn->sconn->searches.dirhandles_open--;
1340 return 0;
1343 /*******************************************************************
1344 Open a directory.
1345 ********************************************************************/
1347 struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn,
1348 const char *name,
1349 const char *mask,
1350 uint32 attr)
1352 struct smb_Dir *dirp = TALLOC_ZERO_P(mem_ctx, struct smb_Dir);
1353 struct smbd_server_connection *sconn = conn->sconn;
1355 if (!dirp) {
1356 return NULL;
1359 dirp->conn = conn;
1360 dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
1362 dirp->dir_path = talloc_strdup(dirp, name);
1363 if (!dirp->dir_path) {
1364 errno = ENOMEM;
1365 goto fail;
1368 if (sconn) {
1369 sconn->searches.dirhandles_open++;
1371 talloc_set_destructor(dirp, smb_Dir_destructor);
1373 dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path, mask, attr);
1374 if (!dirp->dir) {
1375 DEBUG(5,("OpenDir: Can't open %s. %s\n", dirp->dir_path,
1376 strerror(errno) ));
1377 goto fail;
1380 return dirp;
1382 fail:
1383 TALLOC_FREE(dirp);
1384 return NULL;
1387 /*******************************************************************
1388 Open a directory from an fsp.
1389 ********************************************************************/
1391 static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn,
1392 files_struct *fsp,
1393 const char *mask,
1394 uint32 attr)
1396 struct smb_Dir *dirp = TALLOC_ZERO_P(mem_ctx, struct smb_Dir);
1397 struct smbd_server_connection *sconn = conn->sconn;
1399 if (!dirp) {
1400 return NULL;
1403 dirp->conn = conn;
1404 dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
1406 dirp->dir_path = talloc_strdup(dirp, fsp->fsp_name->base_name);
1407 if (!dirp->dir_path) {
1408 errno = ENOMEM;
1409 goto fail;
1412 if (sconn) {
1413 sconn->searches.dirhandles_open++;
1415 talloc_set_destructor(dirp, smb_Dir_destructor);
1417 if (fsp->is_directory && fsp->fh->fd != -1) {
1418 dirp->dir = SMB_VFS_FDOPENDIR(fsp, mask, attr);
1419 if (dirp->dir == NULL) {
1420 DEBUG(10,("OpenDir_fsp: SMB_VFS_FDOPENDIR on %s returned "
1421 "NULL (%s)\n",
1422 dirp->dir_path,
1423 strerror(errno)));
1424 if (errno != ENOSYS) {
1425 return NULL;
1430 if (dirp->dir == NULL) {
1431 /* FDOPENDIR didn't work. Use OPENDIR instead. */
1432 dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path, mask, attr);
1435 if (!dirp->dir) {
1436 DEBUG(5,("OpenDir_fsp: Can't open %s. %s\n", dirp->dir_path,
1437 strerror(errno) ));
1438 goto fail;
1441 return dirp;
1443 fail:
1444 TALLOC_FREE(dirp);
1445 return NULL;
1449 /*******************************************************************
1450 Read from a directory.
1451 Return directory entry, current offset, and optional stat information.
1452 Don't check for veto or invisible files.
1453 ********************************************************************/
1455 const char *ReadDirName(struct smb_Dir *dirp, long *poffset,
1456 SMB_STRUCT_STAT *sbuf, char **ptalloced)
1458 const char *n;
1459 char *talloced = NULL;
1460 connection_struct *conn = dirp->conn;
1462 /* Cheat to allow . and .. to be the first entries returned. */
1463 if (((*poffset == START_OF_DIRECTORY_OFFSET) ||
1464 (*poffset == DOT_DOT_DIRECTORY_OFFSET)) && (dirp->file_number < 2))
1466 if (dirp->file_number == 0) {
1467 n = ".";
1468 *poffset = dirp->offset = START_OF_DIRECTORY_OFFSET;
1469 } else {
1470 n = "..";
1471 *poffset = dirp->offset = DOT_DOT_DIRECTORY_OFFSET;
1473 dirp->file_number++;
1474 *ptalloced = NULL;
1475 return n;
1476 } else if (*poffset == END_OF_DIRECTORY_OFFSET) {
1477 *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1478 return NULL;
1479 } else {
1480 /* A real offset, seek to it. */
1481 SeekDir(dirp, *poffset);
1484 while ((n = vfs_readdirname(conn, dirp->dir, sbuf, &talloced))) {
1485 /* Ignore . and .. - we've already returned them. */
1486 if (*n == '.') {
1487 if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) {
1488 TALLOC_FREE(talloced);
1489 continue;
1492 *poffset = dirp->offset = SMB_VFS_TELLDIR(conn, dirp->dir);
1493 *ptalloced = talloced;
1494 dirp->file_number++;
1495 return n;
1497 *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1498 *ptalloced = NULL;
1499 return NULL;
1502 /*******************************************************************
1503 Rewind to the start.
1504 ********************************************************************/
1506 void RewindDir(struct smb_Dir *dirp, long *poffset)
1508 SMB_VFS_REWINDDIR(dirp->conn, dirp->dir);
1509 dirp->file_number = 0;
1510 dirp->offset = START_OF_DIRECTORY_OFFSET;
1511 *poffset = START_OF_DIRECTORY_OFFSET;
1514 /*******************************************************************
1515 Seek a dir.
1516 ********************************************************************/
1518 void SeekDir(struct smb_Dir *dirp, long offset)
1520 if (offset != dirp->offset) {
1521 if (offset == START_OF_DIRECTORY_OFFSET) {
1522 RewindDir(dirp, &offset);
1524 * Ok we should really set the file number here
1525 * to 1 to enable ".." to be returned next. Trouble
1526 * is I'm worried about callers using SeekDir(dirp,0)
1527 * as equivalent to RewindDir(). So leave this alone
1528 * for now.
1530 } else if (offset == DOT_DOT_DIRECTORY_OFFSET) {
1531 RewindDir(dirp, &offset);
1533 * Set the file number to 2 - we want to get the first
1534 * real file entry (the one we return after "..")
1535 * on the next ReadDir.
1537 dirp->file_number = 2;
1538 } else if (offset == END_OF_DIRECTORY_OFFSET) {
1539 ; /* Don't seek in this case. */
1540 } else {
1541 SMB_VFS_SEEKDIR(dirp->conn, dirp->dir, offset);
1543 dirp->offset = offset;
1547 /*******************************************************************
1548 Tell a dir position.
1549 ********************************************************************/
1551 long TellDir(struct smb_Dir *dirp)
1553 return(dirp->offset);
1556 /*******************************************************************
1557 Add an entry into the dcache.
1558 ********************************************************************/
1560 void DirCacheAdd(struct smb_Dir *dirp, const char *name, long offset)
1562 struct name_cache_entry *e;
1564 if (dirp->name_cache_size == 0) {
1565 return;
1568 if (dirp->name_cache == NULL) {
1569 dirp->name_cache = TALLOC_ZERO_ARRAY(
1570 dirp, struct name_cache_entry, dirp->name_cache_size);
1572 if (dirp->name_cache == NULL) {
1573 return;
1577 dirp->name_cache_index = (dirp->name_cache_index+1) %
1578 dirp->name_cache_size;
1579 e = &dirp->name_cache[dirp->name_cache_index];
1580 TALLOC_FREE(e->name);
1581 e->name = talloc_strdup(dirp, name);
1582 e->offset = offset;
1585 /*******************************************************************
1586 Find an entry by name. Leave us at the offset after it.
1587 Don't check for veto or invisible files.
1588 ********************************************************************/
1590 bool SearchDir(struct smb_Dir *dirp, const char *name, long *poffset)
1592 int i;
1593 const char *entry = NULL;
1594 char *talloced = NULL;
1595 connection_struct *conn = dirp->conn;
1597 /* Search back in the name cache. */
1598 if (dirp->name_cache_size && dirp->name_cache) {
1599 for (i = dirp->name_cache_index; i >= 0; i--) {
1600 struct name_cache_entry *e = &dirp->name_cache[i];
1601 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1602 *poffset = e->offset;
1603 SeekDir(dirp, e->offset);
1604 return True;
1607 for (i = dirp->name_cache_size - 1; i > dirp->name_cache_index; i--) {
1608 struct name_cache_entry *e = &dirp->name_cache[i];
1609 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1610 *poffset = e->offset;
1611 SeekDir(dirp, e->offset);
1612 return True;
1617 /* Not found in the name cache. Rewind directory and start from scratch. */
1618 SMB_VFS_REWINDDIR(conn, dirp->dir);
1619 dirp->file_number = 0;
1620 *poffset = START_OF_DIRECTORY_OFFSET;
1621 while ((entry = ReadDirName(dirp, poffset, NULL, &talloced))) {
1622 if (conn->case_sensitive ? (strcmp(entry, name) == 0) : strequal(entry, name)) {
1623 TALLOC_FREE(talloced);
1624 return True;
1626 TALLOC_FREE(talloced);
1628 return False;
1631 /*****************************************************************
1632 Is this directory empty ?
1633 *****************************************************************/
1635 NTSTATUS can_delete_directory(struct connection_struct *conn,
1636 const char *dirname)
1638 NTSTATUS status = NT_STATUS_OK;
1639 long dirpos = 0;
1640 const char *dname = NULL;
1641 char *talloced = NULL;
1642 SMB_STRUCT_STAT st;
1643 struct smb_Dir *dir_hnd = OpenDir(talloc_tos(), conn,
1644 dirname, NULL, 0);
1646 if (!dir_hnd) {
1647 return map_nt_error_from_unix(errno);
1650 while ((dname = ReadDirName(dir_hnd, &dirpos, &st, &talloced))) {
1651 /* Quick check for "." and ".." */
1652 if (dname[0] == '.') {
1653 if (!dname[1] || (dname[1] == '.' && !dname[2])) {
1654 TALLOC_FREE(talloced);
1655 continue;
1659 if (!is_visible_file(conn, dirname, dname, &st, True)) {
1660 TALLOC_FREE(talloced);
1661 continue;
1664 DEBUG(10,("can_delete_directory: got name %s - can't delete\n",
1665 dname ));
1666 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
1667 break;
1669 TALLOC_FREE(talloced);
1670 TALLOC_FREE(dir_hnd);
1672 return status;