1c84decbde1d88f1cbe6694318d836a5e0301bcd
[samba.git] / source3 / smbd / dir.c
1 /*
2    Unix SMB/CIFS implementation.
3    Directory handling routines
4    Copyright (C) Andrew Tridgell 1992-1998
5    Copyright (C) Jeremy Allison 2007
6
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.
11
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.
16
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/>.
19 */
20
21 #include "includes.h"
22 #include "smbd/globals.h"
23
24 /*
25    This module implements directory related functions for Samba.
26 */
27
28 /* "Special" directory offsets. */
29 #define END_OF_DIRECTORY_OFFSET ((long)-1)
30 #define START_OF_DIRECTORY_OFFSET ((long)0)
31 #define DOT_DOT_DIRECTORY_OFFSET ((long)0x80000000)
32
33 /* Make directory handle internals available. */
34
35 struct name_cache_entry {
36         char *name;
37         long offset;
38 };
39
40 struct smb_Dir {
41         connection_struct *conn;
42         SMB_STRUCT_DIR *dir;
43         long offset;
44         char *dir_path;
45         size_t name_cache_size;
46         struct name_cache_entry *name_cache;
47         unsigned int name_cache_index;
48         unsigned int file_number;
49 };
50
51 struct dptr_struct {
52         struct dptr_struct *next, *prev;
53         int dnum;
54         uint16 spid;
55         struct connection_struct *conn;
56         struct smb_Dir *dir_hnd;
57         bool expect_close;
58         char *wcard;
59         uint32 attr;
60         char *path;
61         bool has_wild; /* Set to true if the wcard entry has MS wildcard characters in it. */
62         bool did_stat; /* Optimisation for non-wcard searches. */
63 };
64
65
66 #define INVALID_DPTR_KEY (-3)
67
68 /****************************************************************************
69  Make a dir struct.
70 ****************************************************************************/
71
72 bool make_dir_struct(TALLOC_CTX *ctx,
73                         char *buf,
74                         const char *mask,
75                         const char *fname,
76                         SMB_OFF_T size,
77                         uint32 mode,
78                         time_t date,
79                         bool uc)
80 {
81         char *p;
82         char *mask2 = talloc_strdup(ctx, mask);
83
84         if (!mask2) {
85                 return False;
86         }
87
88         if ((mode & aDIR) != 0) {
89                 size = 0;
90         }
91
92         memset(buf+1,' ',11);
93         if ((p = strchr_m(mask2,'.')) != NULL) {
94                 *p = 0;
95                 push_ascii(buf+1,mask2,8, 0);
96                 push_ascii(buf+9,p+1,3, 0);
97                 *p = '.';
98         } else {
99                 push_ascii(buf+1,mask2,11, 0);
100         }
101
102         memset(buf+21,'\0',DIR_STRUCT_SIZE-21);
103         SCVAL(buf,21,mode);
104         srv_put_dos_date(buf,22,date);
105         SSVAL(buf,26,size & 0xFFFF);
106         SSVAL(buf,28,(size >> 16)&0xFFFF);
107         /* We only uppercase if FLAGS2_LONG_PATH_COMPONENTS is zero in the input buf.
108            Strange, but verified on W2K3. Needed for OS/2. JRA. */
109         push_ascii(buf+30,fname,12, uc ? STR_UPPER : 0);
110         DEBUG(8,("put name [%s] from [%s] into dir struct\n",buf+30, fname));
111         return True;
112 }
113
114 /****************************************************************************
115  Initialise the dir bitmap.
116 ****************************************************************************/
117
118 void init_dptrs(void)
119 {
120         if (dptr_bmap)
121                 return;
122
123         dptr_bmap = bitmap_allocate(MAX_DIRECTORY_HANDLES);
124
125         if (!dptr_bmap)
126                 exit_server("out of memory in init_dptrs");
127 }
128
129 /****************************************************************************
130  Idle a dptr - the directory is closed but the control info is kept.
131 ****************************************************************************/
132
133 static void dptr_idle(struct dptr_struct *dptr)
134 {
135         if (dptr->dir_hnd) {
136                 DEBUG(4,("Idling dptr dnum %d\n",dptr->dnum));
137                 TALLOC_FREE(dptr->dir_hnd);
138         }
139 }
140
141 /****************************************************************************
142  Idle the oldest dptr.
143 ****************************************************************************/
144
145 static void dptr_idleoldest(void)
146 {
147         struct dptr_struct *dptr;
148
149         /*
150          * Go to the end of the list.
151          */
152         for(dptr = dirptrs; dptr && dptr->next; dptr = dptr->next)
153                 ;
154
155         if(!dptr) {
156                 DEBUG(0,("No dptrs available to idle ?\n"));
157                 return;
158         }
159
160         /*
161          * Idle the oldest pointer.
162          */
163
164         for(; dptr; dptr = dptr->prev) {
165                 if (dptr->dir_hnd) {
166                         dptr_idle(dptr);
167                         return;
168                 }
169         }
170 }
171
172 /****************************************************************************
173  Get the struct dptr_struct for a dir index.
174 ****************************************************************************/
175
176 static struct dptr_struct *dptr_get(int key, bool forclose)
177 {
178         struct dptr_struct *dptr;
179
180         for(dptr = dirptrs; dptr; dptr = dptr->next) {
181                 if(dptr->dnum == key) {
182                         if (!forclose && !dptr->dir_hnd) {
183                                 if (dirhandles_open >= MAX_OPEN_DIRECTORIES)
184                                         dptr_idleoldest();
185                                 DEBUG(4,("dptr_get: Reopening dptr key %d\n",key));
186                                 if (!(dptr->dir_hnd = OpenDir(
187                                               NULL, dptr->conn, dptr->path,
188                                               dptr->wcard, dptr->attr))) {
189                                         DEBUG(4,("dptr_get: Failed to open %s (%s)\n",dptr->path,
190                                                 strerror(errno)));
191                                         return False;
192                                 }
193                         }
194                         DLIST_PROMOTE(dirptrs,dptr);
195                         return dptr;
196                 }
197         }
198         return(NULL);
199 }
200
201 /****************************************************************************
202  Get the dir path for a dir index.
203 ****************************************************************************/
204
205 char *dptr_path(int key)
206 {
207         struct dptr_struct *dptr = dptr_get(key, False);
208         if (dptr)
209                 return(dptr->path);
210         return(NULL);
211 }
212
213 /****************************************************************************
214  Get the dir wcard for a dir index.
215 ****************************************************************************/
216
217 char *dptr_wcard(int key)
218 {
219         struct dptr_struct *dptr = dptr_get(key, False);
220         if (dptr)
221                 return(dptr->wcard);
222         return(NULL);
223 }
224
225 /****************************************************************************
226  Get the dir attrib for a dir index.
227 ****************************************************************************/
228
229 uint16 dptr_attr(int key)
230 {
231         struct dptr_struct *dptr = dptr_get(key, False);
232         if (dptr)
233                 return(dptr->attr);
234         return(0);
235 }
236
237 /****************************************************************************
238  Close a dptr (internal func).
239 ****************************************************************************/
240
241 static void dptr_close_internal(struct dptr_struct *dptr)
242 {
243         DEBUG(4,("closing dptr key %d\n",dptr->dnum));
244
245         DLIST_REMOVE(dirptrs, dptr);
246
247         /*
248          * Free the dnum in the bitmap. Remember the dnum value is always 
249          * biased by one with respect to the bitmap.
250          */
251
252         if(bitmap_query( dptr_bmap, dptr->dnum - 1) != True) {
253                 DEBUG(0,("dptr_close_internal : Error - closing dnum = %d and bitmap not set !\n",
254                         dptr->dnum ));
255         }
256
257         bitmap_clear(dptr_bmap, dptr->dnum - 1);
258
259         TALLOC_FREE(dptr->dir_hnd);
260
261         /* Lanman 2 specific code */
262         SAFE_FREE(dptr->wcard);
263         string_set(&dptr->path,"");
264         SAFE_FREE(dptr);
265 }
266
267 /****************************************************************************
268  Close a dptr given a key.
269 ****************************************************************************/
270
271 void dptr_close(int *key)
272 {
273         struct dptr_struct *dptr;
274
275         if(*key == INVALID_DPTR_KEY)
276                 return;
277
278         /* OS/2 seems to use -1 to indicate "close all directories" */
279         if (*key == -1) {
280                 struct dptr_struct *next;
281                 for(dptr = dirptrs; dptr; dptr = next) {
282                         next = dptr->next;
283                         dptr_close_internal(dptr);
284                 }
285                 *key = INVALID_DPTR_KEY;
286                 return;
287         }
288
289         dptr = dptr_get(*key, True);
290
291         if (!dptr) {
292                 DEBUG(0,("Invalid key %d given to dptr_close\n", *key));
293                 return;
294         }
295
296         dptr_close_internal(dptr);
297
298         *key = INVALID_DPTR_KEY;
299 }
300
301 /****************************************************************************
302  Close all dptrs for a cnum.
303 ****************************************************************************/
304
305 void dptr_closecnum(connection_struct *conn)
306 {
307         struct dptr_struct *dptr, *next;
308         for(dptr = dirptrs; dptr; dptr = next) {
309                 next = dptr->next;
310                 if (dptr->conn == conn)
311                         dptr_close_internal(dptr);
312         }
313 }
314
315 /****************************************************************************
316  Idle all dptrs for a cnum.
317 ****************************************************************************/
318
319 void dptr_idlecnum(connection_struct *conn)
320 {
321         struct dptr_struct *dptr;
322         for(dptr = dirptrs; dptr; dptr = dptr->next) {
323                 if (dptr->conn == conn && dptr->dir_hnd)
324                         dptr_idle(dptr);
325         }
326 }
327
328 /****************************************************************************
329  Close a dptr that matches a given path, only if it matches the spid also.
330 ****************************************************************************/
331
332 void dptr_closepath(char *path,uint16 spid)
333 {
334         struct dptr_struct *dptr, *next;
335         for(dptr = dirptrs; dptr; dptr = next) {
336                 next = dptr->next;
337                 if (spid == dptr->spid && strequal(dptr->path,path))
338                         dptr_close_internal(dptr);
339         }
340 }
341
342 /****************************************************************************
343  Try and close the oldest handle not marked for
344  expect close in the hope that the client has
345  finished with that one.
346 ****************************************************************************/
347
348 static void dptr_close_oldest(bool old)
349 {
350         struct dptr_struct *dptr;
351
352         /*
353          * Go to the end of the list.
354          */
355         for(dptr = dirptrs; dptr && dptr->next; dptr = dptr->next)
356                 ;
357
358         if(!dptr) {
359                 DEBUG(0,("No old dptrs available to close oldest ?\n"));
360                 return;
361         }
362
363         /*
364          * If 'old' is true, close the oldest oldhandle dnum (ie. 1 < dnum < 256) that
365          * does not have expect_close set. If 'old' is false, close
366          * one of the new dnum handles.
367          */
368
369         for(; dptr; dptr = dptr->prev) {
370                 if ((old && (dptr->dnum < 256) && !dptr->expect_close) ||
371                         (!old && (dptr->dnum > 255))) {
372                                 dptr_close_internal(dptr);
373                                 return;
374                 }
375         }
376 }
377
378 /****************************************************************************
379  Create a new dir ptr. If the flag old_handle is true then we must allocate
380  from the bitmap range 0 - 255 as old SMBsearch directory handles are only
381  one byte long. If old_handle is false we allocate from the range
382  256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
383  a directory handle is never zero.
384  wcard must not be zero.
385 ****************************************************************************/
386
387 NTSTATUS dptr_create(connection_struct *conn, const char *path, bool old_handle, bool expect_close,uint16 spid,
388                 const char *wcard, bool wcard_has_wild, uint32 attr, struct dptr_struct **dptr_ret)
389 {
390         struct dptr_struct *dptr = NULL;
391         struct smb_Dir *dir_hnd;
392         NTSTATUS status;
393
394         DEBUG(5,("dptr_create dir=%s\n", path));
395
396         if (!wcard) {
397                 return NT_STATUS_INVALID_PARAMETER;
398         }
399
400         status = check_name(conn,path);
401         if (!NT_STATUS_IS_OK(status)) {
402                 return status;
403         }
404
405         dir_hnd = OpenDir(NULL, conn, path, wcard, attr);
406         if (!dir_hnd) {
407                 return map_nt_error_from_unix(errno);
408         }
409
410         if (dirhandles_open >= MAX_OPEN_DIRECTORIES) {
411                 dptr_idleoldest();
412         }
413
414         dptr = SMB_MALLOC_P(struct dptr_struct);
415         if(!dptr) {
416                 DEBUG(0,("malloc fail in dptr_create.\n"));
417                 TALLOC_FREE(dir_hnd);
418                 return NT_STATUS_NO_MEMORY;
419         }
420
421         ZERO_STRUCTP(dptr);
422
423         if(old_handle) {
424
425                 /*
426                  * This is an old-style SMBsearch request. Ensure the
427                  * value we return will fit in the range 1-255.
428                  */
429
430                 dptr->dnum = bitmap_find(dptr_bmap, 0);
431
432                 if(dptr->dnum == -1 || dptr->dnum > 254) {
433
434                         /*
435                          * Try and close the oldest handle not marked for
436                          * expect close in the hope that the client has
437                          * finished with that one.
438                          */
439
440                         dptr_close_oldest(True);
441
442                         /* Now try again... */
443                         dptr->dnum = bitmap_find(dptr_bmap, 0);
444                         if(dptr->dnum == -1 || dptr->dnum > 254) {
445                                 DEBUG(0,("dptr_create: returned %d: Error - all old dirptrs in use ?\n", dptr->dnum));
446                                 SAFE_FREE(dptr);
447                                 TALLOC_FREE(dir_hnd);
448                                 return NT_STATUS_TOO_MANY_OPENED_FILES;
449                         }
450                 }
451         } else {
452
453                 /*
454                  * This is a new-style trans2 request. Allocate from
455                  * a range that will return 256 - MAX_DIRECTORY_HANDLES.
456                  */
457
458                 dptr->dnum = bitmap_find(dptr_bmap, 255);
459
460                 if(dptr->dnum == -1 || dptr->dnum < 255) {
461
462                         /*
463                          * Try and close the oldest handle close in the hope that
464                          * the client has finished with that one. This will only
465                          * happen in the case of the Win98 client bug where it leaks
466                          * directory handles.
467                          */
468
469                         dptr_close_oldest(False);
470
471                         /* Now try again... */
472                         dptr->dnum = bitmap_find(dptr_bmap, 255);
473
474                         if(dptr->dnum == -1 || dptr->dnum < 255) {
475                                 DEBUG(0,("dptr_create: returned %d: Error - all new dirptrs in use ?\n", dptr->dnum));
476                                 SAFE_FREE(dptr);
477                                 TALLOC_FREE(dir_hnd);
478                                 return NT_STATUS_TOO_MANY_OPENED_FILES;
479                         }
480                 }
481         }
482
483         bitmap_set(dptr_bmap, dptr->dnum);
484
485         dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
486
487         string_set(&dptr->path,path);
488         dptr->conn = conn;
489         dptr->dir_hnd = dir_hnd;
490         dptr->spid = spid;
491         dptr->expect_close = expect_close;
492         dptr->wcard = SMB_STRDUP(wcard);
493         if (!dptr->wcard) {
494                 bitmap_clear(dptr_bmap, dptr->dnum - 1);
495                 SAFE_FREE(dptr);
496                 TALLOC_FREE(dir_hnd);
497                 return NT_STATUS_NO_MEMORY;
498         }
499         if (lp_posix_pathnames() || (wcard[0] == '.' && wcard[1] == 0)) {
500                 dptr->has_wild = True;
501         } else {
502                 dptr->has_wild = wcard_has_wild;
503         }
504
505         dptr->attr = attr;
506
507         DLIST_ADD(dirptrs, dptr);
508
509         DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
510                 dptr->dnum,path,expect_close));  
511
512         *dptr_ret = dptr;
513
514         return NT_STATUS_OK;
515 }
516
517
518 /****************************************************************************
519  Wrapper functions to access the lower level directory handles.
520 ****************************************************************************/
521
522 int dptr_CloseDir(struct dptr_struct *dptr)
523 {
524         DLIST_REMOVE(dirptrs, dptr);
525         TALLOC_FREE(dptr->dir_hnd);
526         return 0;
527 }
528
529 void dptr_SeekDir(struct dptr_struct *dptr, long offset)
530 {
531         SeekDir(dptr->dir_hnd, offset);
532 }
533
534 long dptr_TellDir(struct dptr_struct *dptr)
535 {
536         return TellDir(dptr->dir_hnd);
537 }
538
539 bool dptr_has_wild(struct dptr_struct *dptr)
540 {
541         return dptr->has_wild;
542 }
543
544 int dptr_dnum(struct dptr_struct *dptr)
545 {
546         return dptr->dnum;
547 }
548
549 /****************************************************************************
550  Return the next visible file name, skipping veto'd and invisible files.
551 ****************************************************************************/
552
553 static const char *dptr_normal_ReadDirName(struct dptr_struct *dptr,
554                                            long *poffset, SMB_STRUCT_STAT *pst)
555 {
556         /* Normal search for the next file. */
557         const char *name;
558         while ((name = ReadDirName(dptr->dir_hnd, poffset, pst)) != NULL) {
559                 if (is_visible_file(dptr->conn, dptr->path, name, pst, True)) {
560                         return name;
561                 }
562         }
563         return NULL;
564 }
565
566 /****************************************************************************
567  Return the next visible file name, skipping veto'd and invisible files.
568 ****************************************************************************/
569
570 char *dptr_ReadDirName(TALLOC_CTX *ctx,
571                         struct dptr_struct *dptr,
572                         long *poffset,
573                         SMB_STRUCT_STAT *pst)
574 {
575         struct smb_filename *smb_fname_base = NULL;
576         char *name = NULL;
577         char *pathreal = NULL;
578         char *found_name = NULL;
579         int ret;
580         const char *name_temp = NULL;
581         NTSTATUS status;
582
583         SET_STAT_INVALID(*pst);
584
585         if (dptr->has_wild || dptr->did_stat) {
586                 name_temp = dptr_normal_ReadDirName(dptr, poffset, pst);
587                 name = talloc_strdup(ctx, name_temp);
588                 return name;
589         }
590
591         /* If poffset is -1 then we know we returned this name before and we
592          * have no wildcards. We're at the end of the directory. */
593         if (*poffset == END_OF_DIRECTORY_OFFSET) {
594                 return NULL;
595         }
596
597         /* We know the stored wcard contains no wildcard characters.
598          * See if we can match with a stat call. If we can't, then set
599          * did_stat to true to ensure we only do this once and keep
600          * searching. */
601
602         dptr->did_stat = true;
603
604         /* First check if it should be visible. */
605         if (!is_visible_file(dptr->conn, dptr->path, dptr->wcard,
606             pst, true))
607         {
608                 /* This only returns false if the file was found, but
609                    is explicitly not visible. Set us to end of
610                    directory, but return NULL as we know we can't ever
611                    find it. */
612                 goto ret;
613         }
614
615         if (VALID_STAT(*pst)) {
616                 name = talloc_strdup(ctx, dptr->wcard);
617                 goto ret;
618         }
619
620         pathreal = talloc_asprintf(ctx,
621                                 "%s/%s",
622                                 dptr->path,
623                                 dptr->wcard);
624         if (!pathreal)
625                 return NULL;
626
627         /* Create an smb_filename with stream_name == NULL. */
628         status = create_synthetic_smb_fname(ctx, pathreal, NULL, NULL,
629                                             &smb_fname_base);
630         if (!NT_STATUS_IS_OK(status)) {
631                 return NULL;
632         }
633
634         if (SMB_VFS_STAT(dptr->conn, smb_fname_base) == 0) {
635                 *pst = smb_fname_base->st;
636                 TALLOC_FREE(smb_fname_base);
637                 name = talloc_strdup(ctx, dptr->wcard);
638                 goto clean;
639         } else {
640                 TALLOC_FREE(smb_fname_base);
641                 /* If we get any other error than ENOENT or ENOTDIR
642                    then the file exists we just can't stat it. */
643                 if (errno != ENOENT && errno != ENOTDIR) {
644                         name = talloc_strdup(ctx, dptr->wcard);
645                         goto clean;
646                 }
647         }
648
649         /* Stat failed. We know this is authoratiative if we are
650          * providing case sensitive semantics or the underlying
651          * filesystem is case sensitive.
652          */
653         if (dptr->conn->case_sensitive ||
654             !(dptr->conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH))
655         {
656                 goto clean;
657         }
658
659         /*
660          * Try case-insensitive stat if the fs has the ability. This avoids
661          * scanning the whole directory.
662          */
663         ret = SMB_VFS_GET_REAL_FILENAME(dptr->conn, dptr->path, dptr->wcard,
664                                         ctx, &found_name);
665         if (ret == 0) {
666                 name = found_name;
667                 goto clean;
668         } else if (errno == ENOENT) {
669                 /* The case-insensitive lookup was authoritative. */
670                 goto clean;
671         }
672
673         TALLOC_FREE(pathreal);
674
675         name_temp = dptr_normal_ReadDirName(dptr, poffset, pst);
676         name = talloc_strdup(ctx, name_temp);
677         return name;
678
679 clean:
680         TALLOC_FREE(pathreal);
681 ret:
682         /* We need to set the underlying dir_hnd offset to -1
683          * also as this function is usually called with the
684          * output from TellDir. */
685         dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
686         return name;
687 }
688
689 /****************************************************************************
690  Search for a file by name, skipping veto'ed and not visible files.
691 ****************************************************************************/
692
693 bool dptr_SearchDir(struct dptr_struct *dptr, const char *name, long *poffset, SMB_STRUCT_STAT *pst)
694 {
695         SET_STAT_INVALID(*pst);
696
697         if (!dptr->has_wild && (dptr->dir_hnd->offset == END_OF_DIRECTORY_OFFSET)) {
698                 /* This is a singleton directory and we're already at the end. */
699                 *poffset = END_OF_DIRECTORY_OFFSET;
700                 return False;
701         }
702
703         return SearchDir(dptr->dir_hnd, name, poffset);
704 }
705
706 /****************************************************************************
707  Add the name we're returning into the underlying cache.
708 ****************************************************************************/
709
710 void dptr_DirCacheAdd(struct dptr_struct *dptr, const char *name, long offset)
711 {
712         DirCacheAdd(dptr->dir_hnd, name, offset);
713 }
714
715 /****************************************************************************
716  Initialize variables & state data at the beginning of all search SMB requests.
717 ****************************************************************************/
718 void dptr_init_search_op(struct dptr_struct *dptr)
719 {
720         SMB_VFS_INIT_SEARCH_OP(dptr->conn, dptr->dir_hnd->dir);
721 }
722
723 /****************************************************************************
724  Fill the 5 byte server reserved dptr field.
725 ****************************************************************************/
726
727 bool dptr_fill(char *buf1,unsigned int key)
728 {
729         unsigned char *buf = (unsigned char *)buf1;
730         struct dptr_struct *dptr = dptr_get(key, False);
731         uint32 offset;
732         if (!dptr) {
733                 DEBUG(1,("filling null dirptr %d\n",key));
734                 return(False);
735         }
736         offset = (uint32)TellDir(dptr->dir_hnd);
737         DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key,
738                 (long)dptr->dir_hnd,(int)offset));
739         buf[0] = key;
740         SIVAL(buf,1,offset);
741         return(True);
742 }
743
744 /****************************************************************************
745  Fetch the dir ptr and seek it given the 5 byte server field.
746 ****************************************************************************/
747
748 struct dptr_struct *dptr_fetch(char *buf,int *num)
749 {
750         unsigned int key = *(unsigned char *)buf;
751         struct dptr_struct *dptr = dptr_get(key, False);
752         uint32 offset;
753         long seekoff;
754
755         if (!dptr) {
756                 DEBUG(3,("fetched null dirptr %d\n",key));
757                 return(NULL);
758         }
759         *num = key;
760         offset = IVAL(buf,1);
761         if (offset == (uint32)-1) {
762                 seekoff = END_OF_DIRECTORY_OFFSET;
763         } else {
764                 seekoff = (long)offset;
765         }
766         SeekDir(dptr->dir_hnd,seekoff);
767         DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
768                 key,dptr_path(key),(int)seekoff));
769         return(dptr);
770 }
771
772 /****************************************************************************
773  Fetch the dir ptr.
774 ****************************************************************************/
775
776 struct dptr_struct *dptr_fetch_lanman2(int dptr_num)
777 {
778         struct dptr_struct *dptr  = dptr_get(dptr_num, False);
779
780         if (!dptr) {
781                 DEBUG(3,("fetched null dirptr %d\n",dptr_num));
782                 return(NULL);
783         }
784         DEBUG(3,("fetching dirptr %d for path %s\n",dptr_num,dptr_path(dptr_num)));
785         return(dptr);
786 }
787
788 /****************************************************************************
789  Check that a file matches a particular file type.
790 ****************************************************************************/
791
792 bool dir_check_ftype(connection_struct *conn, uint32 mode, uint32 dirtype)
793 {
794         uint32 mask;
795
796         /* Check the "may have" search bits. */
797         if (((mode & ~dirtype) & (aHIDDEN | aSYSTEM | aDIR)) != 0)
798                 return False;
799
800         /* Check the "must have" bits, which are the may have bits shifted eight */
801         /* If must have bit is set, the file/dir can not be returned in search unless the matching
802                 file attribute is set */
803         mask = ((dirtype >> 8) & (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM)); /* & 0x37 */
804         if(mask) {
805                 if((mask & (mode & (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM))) == mask)   /* check if matching attribute present */
806                         return True;
807                 else
808                         return False;
809         }
810
811         return True;
812 }
813
814 static bool mangle_mask_match(connection_struct *conn,
815                 const char *filename,
816                 const char *mask)
817 {
818         char mname[13];
819
820         if (!name_to_8_3(filename,mname,False,conn->params)) {
821                 return False;
822         }
823         return mask_match_search(mname,mask,False);
824 }
825
826 bool smbd_dirptr_get_entry(TALLOC_CTX *ctx,
827                            struct dptr_struct *dirptr,
828                            const char *mask,
829                            uint32_t dirtype,
830                            bool dont_descend,
831                            bool ask_sharemode,
832                            bool (*match_fn)(TALLOC_CTX *ctx,
833                                             void *private_data,
834                                             const char *dname,
835                                             const char *mask,
836                                             char **_fname),
837                            bool (*mode_fn)(TALLOC_CTX *ctx,
838                                            void *private_data,
839                                            struct smb_filename *smb_fname,
840                                            uint32_t *_mode),
841                            void *private_data,
842                            char **_fname,
843                            struct smb_filename **_smb_fname,
844                            uint32_t *_mode,
845                            long *_prev_offset)
846 {
847         connection_struct *conn = dirptr->conn;
848         bool needslash;
849
850         *_smb_fname = NULL;
851         *_mode = 0;
852
853         needslash = ( dirptr->path[strlen(dirptr->path) -1] != '/');
854
855         while (true) {
856                 long cur_offset;
857                 long prev_offset;
858                 SMB_STRUCT_STAT sbuf;
859                 char *dname = NULL;
860                 bool isdots;
861                 char *fname = NULL;
862                 char *pathreal = NULL;
863                 struct smb_filename *smb_fname = NULL;
864                 uint32_t mode = 0;
865                 bool ok;
866                 NTSTATUS status;
867
868                 cur_offset = dptr_TellDir(dirptr);
869                 prev_offset = cur_offset;
870                 dname = dptr_ReadDirName(ctx, dirptr, &cur_offset, &sbuf);
871
872                 DEBUG(6,("smbd_dirptr_get_entry: dirptr 0x%lx now at offset %ld\n",
873                         (long)dirptr, cur_offset));
874
875                 if (dname == NULL) {
876                         return false;
877                 }
878
879                 isdots = (ISDOT(dname) || ISDOTDOT(dname));
880                 if (dont_descend && !isdots) {
881                         TALLOC_FREE(dname);
882                         continue;
883                 }
884
885                 /*
886                  * fname may get mangled, dname is never mangled.
887                  * Whenever we're accessing the filesystem we use
888                  * pathreal which is composed from dname.
889                  */
890
891                 ok = match_fn(ctx, private_data, dname, mask, &fname);
892                 if (!ok) {
893                         TALLOC_FREE(dname);
894                         continue;
895                 }
896
897                 pathreal = talloc_asprintf(ctx, "%s%s%s",
898                                            dirptr->path,
899                                            needslash?"/":"",
900                                            dname);
901                 if (!pathreal) {
902                         TALLOC_FREE(dname);
903                         TALLOC_FREE(fname);
904                         return false;
905                 }
906
907                 /* Create smb_fname with NULL stream_name. */
908                 status = create_synthetic_smb_fname(ctx, pathreal,
909                                                     NULL, &sbuf,
910                                                     &smb_fname);
911                 TALLOC_FREE(pathreal);
912                 if (!NT_STATUS_IS_OK(status)) {
913                         TALLOC_FREE(dname);
914                         TALLOC_FREE(fname);
915                         return false;
916                 }
917
918                 ok = mode_fn(ctx, private_data, smb_fname, &mode);
919                 if (!ok) {
920                         TALLOC_FREE(dname);
921                         TALLOC_FREE(fname);
922                         TALLOC_FREE(smb_fname);
923                         continue;
924                 }
925
926                 if (!dir_check_ftype(conn, mode, dirtype)) {
927                         DEBUG(5,("[%s] attribs 0x%x didn't match 0x%x\n",
928                                 fname, (unsigned int)mode, (unsigned int)dirtype));
929                         TALLOC_FREE(dname);
930                         TALLOC_FREE(fname);
931                         TALLOC_FREE(smb_fname);
932                         continue;
933                 }
934
935                 if (ask_sharemode) {
936                         struct timespec write_time_ts;
937                         struct file_id fileid;
938
939                         fileid = vfs_file_id_from_sbuf(conn,
940                                                        &smb_fname->st);
941                         get_file_infos(fileid, NULL, &write_time_ts);
942                         if (!null_timespec(write_time_ts)) {
943                                 update_stat_ex_mtime(&smb_fname->st,
944                                                      write_time_ts);
945                         }
946                 }
947
948                 DEBUG(3,("smbd_dirptr_get_entry mask=[%s] found %s "
949                         "fname=%s (%s)\n",
950                         mask, smb_fname_str_dbg(smb_fname),
951                         dname, fname));
952
953                 DirCacheAdd(dirptr->dir_hnd, dname, cur_offset);
954
955                 TALLOC_FREE(dname);
956
957                 *_fname = fname;
958                 *_smb_fname = smb_fname;
959                 *_mode = mode;
960                 *_prev_offset = prev_offset;
961
962                 return true;
963         }
964
965         return false;
966 }
967
968 /****************************************************************************
969  Get an 8.3 directory entry.
970 ****************************************************************************/
971
972 static bool smbd_dirptr_8_3_match_fn(TALLOC_CTX *ctx,
973                                      void *private_data,
974                                      const char *dname,
975                                      const char *mask,
976                                      char **_fname)
977 {
978         connection_struct *conn = (connection_struct *)private_data;
979
980         if ((strcmp(mask,"*.*") == 0) ||
981             mask_match_search(dname, mask, false) ||
982             mangle_mask_match(conn, dname, mask)) {
983                 char mname[13];
984                 const char *fname;
985
986                 if (!mangle_is_8_3(dname, false, conn->params)) {
987                         bool ok = name_to_8_3(dname, mname, false,
988                                               conn->params);
989                         if (!ok) {
990                                 return false;
991                         }
992                         fname = mname;
993                 } else {
994                         fname = dname;
995                 }
996
997                 *_fname = talloc_strdup(ctx, fname);
998                 if (*_fname == NULL) {
999                         return false;
1000                 }
1001
1002                 return true;
1003         }
1004
1005         return false;
1006 }
1007
1008 static bool smbd_dirptr_8_3_mode_fn(TALLOC_CTX *ctx,
1009                                     void *private_data,
1010                                     struct smb_filename *smb_fname,
1011                                     uint32_t *_mode)
1012 {
1013         connection_struct *conn = (connection_struct *)private_data;
1014
1015         if (!VALID_STAT(smb_fname->st)) {
1016                 if ((SMB_VFS_STAT(conn, smb_fname)) != 0) {
1017                         DEBUG(5,("smbd_dirptr_8_3_mode_fn: "
1018                                  "Couldn't stat [%s]. Error "
1019                                  "= %s\n",
1020                                  smb_fname_str_dbg(smb_fname),
1021                                  strerror(errno)));
1022                         return false;
1023                 }
1024         }
1025
1026         *_mode = dos_mode(conn, smb_fname);
1027         return true;
1028 }
1029
1030 bool get_dir_entry(TALLOC_CTX *ctx,
1031                 struct dptr_struct *dirptr,
1032                 const char *mask,
1033                 uint32_t dirtype,
1034                 char **_fname,
1035                 SMB_OFF_T *_size,
1036                 uint32_t *_mode,
1037                 struct timespec *_date,
1038                 bool check_descend,
1039                 bool ask_sharemode)
1040 {
1041         connection_struct *conn = dirptr->conn;
1042         char *fname = NULL;
1043         struct smb_filename *smb_fname = NULL;
1044         uint32_t mode = 0;
1045         long prev_offset;
1046         bool ok;
1047
1048         ok = smbd_dirptr_get_entry(ctx,
1049                                    dirptr,
1050                                    mask,
1051                                    dirtype,
1052                                    check_descend,
1053                                    ask_sharemode,
1054                                    smbd_dirptr_8_3_match_fn,
1055                                    smbd_dirptr_8_3_mode_fn,
1056                                    conn,
1057                                    &fname,
1058                                    &smb_fname,
1059                                    &mode,
1060                                    &prev_offset);
1061         if (!ok) {
1062                 return false;
1063         }
1064
1065         *_fname = talloc_move(ctx, &fname);
1066         *_size = smb_fname->st.st_ex_size;
1067         *_mode = mode;
1068         *_date = smb_fname->st.st_ex_mtime;
1069         TALLOC_FREE(smb_fname);
1070         return true;
1071 }
1072
1073 /*******************************************************************
1074  Check to see if a user can read a file. This is only approximate,
1075  it is used as part of the "hide unreadable" option. Don't
1076  use it for anything security sensitive.
1077 ********************************************************************/
1078
1079 static bool user_can_read_file(connection_struct *conn,
1080                                struct smb_filename *smb_fname)
1081 {
1082         /*
1083          * If user is a member of the Admin group
1084          * we never hide files from them.
1085          */
1086
1087         if (conn->admin_user) {
1088                 return True;
1089         }
1090
1091         return can_access_file_acl(conn, smb_fname, FILE_READ_DATA);
1092 }
1093
1094 /*******************************************************************
1095  Check to see if a user can write a file (and only files, we do not
1096  check dirs on this one). This is only approximate,
1097  it is used as part of the "hide unwriteable" option. Don't
1098  use it for anything security sensitive.
1099 ********************************************************************/
1100
1101 static bool user_can_write_file(connection_struct *conn,
1102                                 const struct smb_filename *smb_fname)
1103 {
1104         /*
1105          * If user is a member of the Admin group
1106          * we never hide files from them.
1107          */
1108
1109         if (conn->admin_user) {
1110                 return True;
1111         }
1112
1113         SMB_ASSERT(VALID_STAT(smb_fname->st));
1114
1115         /* Pseudo-open the file */
1116
1117         if(S_ISDIR(smb_fname->st.st_ex_mode)) {
1118                 return True;
1119         }
1120
1121         return can_write_to_file(conn, smb_fname);
1122 }
1123
1124 /*******************************************************************
1125   Is a file a "special" type ?
1126 ********************************************************************/
1127
1128 static bool file_is_special(connection_struct *conn,
1129                             const struct smb_filename *smb_fname)
1130 {
1131         /*
1132          * If user is a member of the Admin group
1133          * we never hide files from them.
1134          */
1135
1136         if (conn->admin_user)
1137                 return False;
1138
1139         SMB_ASSERT(VALID_STAT(smb_fname->st));
1140
1141         if (S_ISREG(smb_fname->st.st_ex_mode) ||
1142             S_ISDIR(smb_fname->st.st_ex_mode) ||
1143             S_ISLNK(smb_fname->st.st_ex_mode))
1144                 return False;
1145
1146         return True;
1147 }
1148
1149 /*******************************************************************
1150  Should the file be seen by the client?
1151  NOTE: A successful return is no guarantee of the file's existence.
1152 ********************************************************************/
1153
1154 bool is_visible_file(connection_struct *conn, const char *dir_path,
1155                      const char *name, SMB_STRUCT_STAT *pst, bool use_veto)
1156 {
1157         bool hide_unreadable = lp_hideunreadable(SNUM(conn));
1158         bool hide_unwriteable = lp_hideunwriteable_files(SNUM(conn));
1159         bool hide_special = lp_hide_special_files(SNUM(conn));
1160         char *entry = NULL;
1161         struct smb_filename *smb_fname_base = NULL;
1162         NTSTATUS status;
1163         bool ret = false;
1164
1165         if ((strcmp(".",name) == 0) || (strcmp("..",name) == 0)) {
1166                 return True; /* . and .. are always visible. */
1167         }
1168
1169         /* If it's a vetoed file, pretend it doesn't even exist */
1170         if (use_veto && IS_VETO_PATH(conn, name)) {
1171                 DEBUG(10,("is_visible_file: file %s is vetoed.\n", name ));
1172                 return False;
1173         }
1174
1175         if (hide_unreadable || hide_unwriteable || hide_special) {
1176                 entry = talloc_asprintf(talloc_tos(), "%s/%s", dir_path, name);
1177                 if (!entry) {
1178                         ret = false;
1179                         goto out;
1180                 }
1181
1182                 /* If it's a dfs symlink, ignore _hide xxxx_ options */
1183                 if (lp_host_msdfs() &&
1184                                 lp_msdfs_root(SNUM(conn)) &&
1185                                 is_msdfs_link(conn, entry, NULL)) {
1186                         ret = true;
1187                         goto out;
1188                 }
1189
1190                 /* Create an smb_filename with stream_name == NULL. */
1191                 status = create_synthetic_smb_fname(talloc_tos(), entry, NULL,
1192                                                     pst, &smb_fname_base);
1193                 if (!NT_STATUS_IS_OK(status)) {
1194                         ret = false;
1195                         goto out;
1196                 }
1197
1198                 /* If the file name does not exist, there's no point checking
1199                  * the configuration options. We succeed, on the basis that the
1200                  * checks *might* have passed if the file was present.
1201                  */
1202                 if (!VALID_STAT(*pst)) {
1203                         if (SMB_VFS_STAT(conn, smb_fname_base) != 0) {
1204                                 ret = true;
1205                                 goto out;
1206                         } else {
1207                                 *pst = smb_fname_base->st;
1208                         }
1209                 }
1210
1211                 /* Honour _hide unreadable_ option */
1212                 if (hide_unreadable &&
1213                     !user_can_read_file(conn, smb_fname_base)) {
1214                         DEBUG(10,("is_visible_file: file %s is unreadable.\n",
1215                                  entry ));
1216                         ret = false;
1217                         goto out;
1218                 }
1219                 /* Honour _hide unwriteable_ option */
1220                 if (hide_unwriteable && !user_can_write_file(conn,
1221                                                              smb_fname_base)) {
1222                         DEBUG(10,("is_visible_file: file %s is unwritable.\n",
1223                                  entry ));
1224                         ret = false;
1225                         goto out;
1226                 }
1227                 /* Honour _hide_special_ option */
1228                 if (hide_special && file_is_special(conn, smb_fname_base)) {
1229                         DEBUG(10,("is_visible_file: file %s is special.\n",
1230                                  entry ));
1231                         ret = false;
1232                         goto out;
1233                 }
1234         }
1235
1236         ret = true;
1237  out:
1238         TALLOC_FREE(smb_fname_base);
1239         TALLOC_FREE(entry);
1240         return ret;
1241 }
1242
1243 static int smb_Dir_destructor(struct smb_Dir *dirp)
1244 {
1245         if (dirp->dir) {
1246                 SMB_VFS_CLOSEDIR(dirp->conn,dirp->dir);
1247         }
1248         dirhandles_open--;
1249         return 0;
1250 }
1251
1252 /*******************************************************************
1253  Open a directory.
1254 ********************************************************************/
1255
1256 struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn,
1257                         const char *name, const char *mask, uint32 attr)
1258 {
1259         struct smb_Dir *dirp = TALLOC_ZERO_P(mem_ctx, struct smb_Dir);
1260
1261         if (!dirp) {
1262                 return NULL;
1263         }
1264
1265         dirp->conn = conn;
1266         dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
1267
1268         dirp->dir_path = talloc_strdup(dirp, name);
1269         if (!dirp->dir_path) {
1270                 errno = ENOMEM;
1271                 goto fail;
1272         }
1273
1274         dirhandles_open++;
1275         talloc_set_destructor(dirp, smb_Dir_destructor);
1276
1277         dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path, mask, attr);
1278         if (!dirp->dir) {
1279                 DEBUG(5,("OpenDir: Can't open %s. %s\n", dirp->dir_path,
1280                          strerror(errno) ));
1281                 goto fail;
1282         }
1283
1284         return dirp;
1285
1286   fail:
1287         TALLOC_FREE(dirp);
1288         return NULL;
1289 }
1290
1291 /*******************************************************************
1292  Read from a directory.
1293  Return directory entry, current offset, and optional stat information.
1294  Don't check for veto or invisible files.
1295 ********************************************************************/
1296
1297 const char *ReadDirName(struct smb_Dir *dirp, long *poffset,
1298                         SMB_STRUCT_STAT *sbuf)
1299 {
1300         const char *n;
1301         connection_struct *conn = dirp->conn;
1302
1303         /* Cheat to allow . and .. to be the first entries returned. */
1304         if (((*poffset == START_OF_DIRECTORY_OFFSET) ||
1305              (*poffset == DOT_DOT_DIRECTORY_OFFSET)) && (dirp->file_number < 2))
1306         {
1307                 if (dirp->file_number == 0) {
1308                         n = ".";
1309                         *poffset = dirp->offset = START_OF_DIRECTORY_OFFSET;
1310                 } else {
1311                         *poffset = dirp->offset = DOT_DOT_DIRECTORY_OFFSET;
1312                         n = "..";
1313                 }
1314                 dirp->file_number++;
1315                 return n;
1316         } else if (*poffset == END_OF_DIRECTORY_OFFSET) {
1317                 *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1318                 return NULL;
1319         } else {
1320                 /* A real offset, seek to it. */
1321                 SeekDir(dirp, *poffset);
1322         }
1323
1324         while ((n = vfs_readdirname(conn, dirp->dir, sbuf))) {
1325                 /* Ignore . and .. - we've already returned them. */
1326                 if (*n == '.') {
1327                         if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) {
1328                                 continue;
1329                         }
1330                 }
1331                 *poffset = dirp->offset = SMB_VFS_TELLDIR(conn, dirp->dir);
1332                 dirp->file_number++;
1333                 return n;
1334         }
1335         *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1336         return NULL;
1337 }
1338
1339 /*******************************************************************
1340  Rewind to the start.
1341 ********************************************************************/
1342
1343 void RewindDir(struct smb_Dir *dirp, long *poffset)
1344 {
1345         SMB_VFS_REWINDDIR(dirp->conn, dirp->dir);
1346         dirp->file_number = 0;
1347         dirp->offset = START_OF_DIRECTORY_OFFSET;
1348         *poffset = START_OF_DIRECTORY_OFFSET;
1349 }
1350
1351 /*******************************************************************
1352  Seek a dir.
1353 ********************************************************************/
1354
1355 void SeekDir(struct smb_Dir *dirp, long offset)
1356 {
1357         if (offset != dirp->offset) {
1358                 if (offset == START_OF_DIRECTORY_OFFSET) {
1359                         RewindDir(dirp, &offset);
1360                         /*
1361                          * Ok we should really set the file number here
1362                          * to 1 to enable ".." to be returned next. Trouble
1363                          * is I'm worried about callers using SeekDir(dirp,0)
1364                          * as equivalent to RewindDir(). So leave this alone
1365                          * for now.
1366                          */
1367                 } else if  (offset == DOT_DOT_DIRECTORY_OFFSET) {
1368                         RewindDir(dirp, &offset);
1369                         /*
1370                          * Set the file number to 2 - we want to get the first
1371                          * real file entry (the one we return after "..")
1372                          * on the next ReadDir.
1373                          */
1374                         dirp->file_number = 2;
1375                 } else if (offset == END_OF_DIRECTORY_OFFSET) {
1376                         ; /* Don't seek in this case. */
1377                 } else {
1378                         SMB_VFS_SEEKDIR(dirp->conn, dirp->dir, offset);
1379                 }
1380                 dirp->offset = offset;
1381         }
1382 }
1383
1384 /*******************************************************************
1385  Tell a dir position.
1386 ********************************************************************/
1387
1388 long TellDir(struct smb_Dir *dirp)
1389 {
1390         return(dirp->offset);
1391 }
1392
1393 /*******************************************************************
1394  Add an entry into the dcache.
1395 ********************************************************************/
1396
1397 void DirCacheAdd(struct smb_Dir *dirp, const char *name, long offset)
1398 {
1399         struct name_cache_entry *e;
1400
1401         if (dirp->name_cache_size == 0) {
1402                 return;
1403         }
1404
1405         if (dirp->name_cache == NULL) {
1406                 dirp->name_cache = TALLOC_ZERO_ARRAY(
1407                         dirp, struct name_cache_entry, dirp->name_cache_size);
1408
1409                 if (dirp->name_cache == NULL) {
1410                         return;
1411                 }
1412         }
1413
1414         dirp->name_cache_index = (dirp->name_cache_index+1) %
1415                                         dirp->name_cache_size;
1416         e = &dirp->name_cache[dirp->name_cache_index];
1417         TALLOC_FREE(e->name);
1418         e->name = talloc_strdup(dirp, name);
1419         e->offset = offset;
1420 }
1421
1422 /*******************************************************************
1423  Find an entry by name. Leave us at the offset after it.
1424  Don't check for veto or invisible files.
1425 ********************************************************************/
1426
1427 bool SearchDir(struct smb_Dir *dirp, const char *name, long *poffset)
1428 {
1429         int i;
1430         const char *entry;
1431         connection_struct *conn = dirp->conn;
1432
1433         /* Search back in the name cache. */
1434         if (dirp->name_cache_size && dirp->name_cache) {
1435                 for (i = dirp->name_cache_index; i >= 0; i--) {
1436                         struct name_cache_entry *e = &dirp->name_cache[i];
1437                         if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1438                                 *poffset = e->offset;
1439                                 SeekDir(dirp, e->offset);
1440                                 return True;
1441                         }
1442                 }
1443                 for (i = dirp->name_cache_size - 1; i > dirp->name_cache_index; i--) {
1444                         struct name_cache_entry *e = &dirp->name_cache[i];
1445                         if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1446                                 *poffset = e->offset;
1447                                 SeekDir(dirp, e->offset);
1448                                 return True;
1449                         }
1450                 }
1451         }
1452
1453         /* Not found in the name cache. Rewind directory and start from scratch. */
1454         SMB_VFS_REWINDDIR(conn, dirp->dir);
1455         dirp->file_number = 0;
1456         *poffset = START_OF_DIRECTORY_OFFSET;
1457         while ((entry = ReadDirName(dirp, poffset, NULL))) {
1458                 if (conn->case_sensitive ? (strcmp(entry, name) == 0) : strequal(entry, name)) {
1459                         return True;
1460                 }
1461         }
1462         return False;
1463 }
1464
1465 /*****************************************************************
1466  Is this directory empty ?
1467 *****************************************************************/
1468
1469 NTSTATUS can_delete_directory(struct connection_struct *conn,
1470                                 const char *dirname)
1471 {
1472         NTSTATUS status = NT_STATUS_OK;
1473         long dirpos = 0;
1474         const char *dname;
1475         SMB_STRUCT_STAT st;
1476         struct smb_Dir *dir_hnd = OpenDir(talloc_tos(), conn, dirname,
1477                                           NULL, 0);
1478
1479         if (!dir_hnd) {
1480                 return map_nt_error_from_unix(errno);
1481         }
1482
1483         while ((dname = ReadDirName(dir_hnd, &dirpos, &st))) {
1484                 /* Quick check for "." and ".." */
1485                 if (dname[0] == '.') {
1486                         if (!dname[1] || (dname[1] == '.' && !dname[2])) {
1487                                 continue;
1488                         }
1489                 }
1490
1491                 if (!is_visible_file(conn, dirname, dname, &st, True)) {
1492                         continue;
1493                 }
1494
1495                 DEBUG(10,("can_delete_directory: got name %s - can't delete\n",
1496                          dname ));
1497                 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
1498                 break;
1499         }
1500         TALLOC_FREE(dir_hnd);
1501
1502         return status;
1503 }