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