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