s3:dir - Introduce a function to map a directory cookie to a 32-bit wire cookie.
[kai/samba-autobuild/.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         struct smb_Dir *dir_hnd = NULL;
430         struct smb_filename *smb_fname_cwd;
431         char *saved_dir = vfs_GetWd(talloc_tos(), conn);
432         struct privilege_paths *priv_paths = req->priv_paths;
433         int ret;
434
435         if (saved_dir == NULL) {
436                 return NULL;
437         }
438
439         if (vfs_ChDir(conn, path) == -1) {
440                 return NULL;
441         }
442
443         /* Now check the stat value is the same. */
444         smb_fname_cwd = synthetic_smb_fname(talloc_tos(), ".", NULL, NULL);
445
446         if (smb_fname_cwd == NULL) {
447                 goto out;
448         }
449         ret = SMB_VFS_STAT(conn, smb_fname_cwd);
450         if (ret != 0) {
451                 goto out;
452         }
453
454         if (!check_same_stat(&smb_fname_cwd->st, &priv_paths->parent_name.st)) {
455                 DEBUG(0,("open_dir_with_privilege: stat mismatch between %s "
456                         "and %s\n",
457                         path,
458                         smb_fname_str_dbg(&priv_paths->parent_name)));
459                 goto out;
460         }
461
462         dir_hnd = OpenDir(NULL, conn, ".", wcard, attr);
463
464   out:
465
466         vfs_ChDir(conn, saved_dir);
467         return dir_hnd;
468 }
469
470 /****************************************************************************
471  Create a new dir ptr. If the flag old_handle is true then we must allocate
472  from the bitmap range 0 - 255 as old SMBsearch directory handles are only
473  one byte long. If old_handle is false we allocate from the range
474  256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
475  a directory handle is never zero.
476  wcard must not be zero.
477 ****************************************************************************/
478
479 NTSTATUS dptr_create(connection_struct *conn,
480                 struct smb_request *req,
481                 files_struct *fsp,
482                 const char *path, bool old_handle, bool expect_close,uint16 spid,
483                 const char *wcard, bool wcard_has_wild, uint32 attr, struct dptr_struct **dptr_ret)
484 {
485         struct smbd_server_connection *sconn = conn->sconn;
486         struct dptr_struct *dptr = NULL;
487         struct smb_Dir *dir_hnd;
488
489         if (fsp && fsp->is_directory && fsp->fh->fd != -1) {
490                 path = fsp->fsp_name->base_name;
491         }
492
493         DEBUG(5,("dptr_create dir=%s\n", path));
494
495         if (sconn == NULL) {
496                 DEBUG(0,("dptr_create: called with fake connection_struct\n"));
497                 return NT_STATUS_INTERNAL_ERROR;
498         }
499
500         if (!wcard) {
501                 return NT_STATUS_INVALID_PARAMETER;
502         }
503
504         if (fsp) {
505                 if (!(fsp->access_mask & SEC_DIR_LIST)) {
506                         DEBUG(5,("dptr_create: directory %s "
507                                 "not open for LIST access\n",
508                                 path));
509                         return NT_STATUS_ACCESS_DENIED;
510                 }
511                 dir_hnd = OpenDir_fsp(NULL, conn, fsp, wcard, attr);
512         } else {
513                 int ret;
514                 bool backup_intent = (req && req->priv_paths);
515                 struct smb_filename *smb_dname;
516                 NTSTATUS status;
517
518                 smb_dname = synthetic_smb_fname(talloc_tos(), path,
519                                                 NULL, NULL);
520                 if (smb_dname == NULL) {
521                         return NT_STATUS_NO_MEMORY;
522                 }
523                 if (lp_posix_pathnames()) {
524                         ret = SMB_VFS_LSTAT(conn, smb_dname);
525                 } else {
526                         ret = SMB_VFS_STAT(conn, smb_dname);
527                 }
528                 if (ret == -1) {
529                         return map_nt_error_from_unix(errno);
530                 }
531                 if (!S_ISDIR(smb_dname->st.st_ex_mode)) {
532                         return NT_STATUS_NOT_A_DIRECTORY;
533                 }
534                 status = smbd_check_access_rights(conn,
535                                                 smb_dname,
536                                                 backup_intent,
537                                                 SEC_DIR_LIST);
538                 if (!NT_STATUS_IS_OK(status)) {
539                         return status;
540                 }
541                 if (backup_intent) {
542                         dir_hnd = open_dir_with_privilege(conn,
543                                                 req,
544                                                 path,
545                                                 wcard,
546                                                 attr);
547                 } else {
548                         dir_hnd = OpenDir(NULL, conn, path, wcard, attr);
549                 }
550         }
551
552         if (!dir_hnd) {
553                 return map_nt_error_from_unix(errno);
554         }
555
556         if (sconn->searches.dirhandles_open >= MAX_OPEN_DIRECTORIES) {
557                 dptr_idleoldest(sconn);
558         }
559
560         dptr = talloc(NULL, struct dptr_struct);
561         if(!dptr) {
562                 DEBUG(0,("talloc fail in dptr_create.\n"));
563                 TALLOC_FREE(dir_hnd);
564                 return NT_STATUS_NO_MEMORY;
565         }
566
567         ZERO_STRUCTP(dptr);
568
569         dptr->path = talloc_strdup(dptr, path);
570         if (!dptr->path) {
571                 TALLOC_FREE(dptr);
572                 TALLOC_FREE(dir_hnd);
573                 return NT_STATUS_NO_MEMORY;
574         }
575         dptr->conn = conn;
576         dptr->dir_hnd = dir_hnd;
577         dptr->spid = spid;
578         dptr->expect_close = expect_close;
579         dptr->wcard = talloc_strdup(dptr, wcard);
580         if (!dptr->wcard) {
581                 TALLOC_FREE(dptr);
582                 TALLOC_FREE(dir_hnd);
583                 return NT_STATUS_NO_MEMORY;
584         }
585         if (lp_posix_pathnames() || (wcard[0] == '.' && wcard[1] == 0)) {
586                 dptr->has_wild = True;
587         } else {
588                 dptr->has_wild = wcard_has_wild;
589         }
590
591         dptr->attr = attr;
592
593         if (sconn->using_smb2) {
594                 goto done;
595         }
596
597         if(old_handle) {
598
599                 /*
600                  * This is an old-style SMBsearch request. Ensure the
601                  * value we return will fit in the range 1-255.
602                  */
603
604                 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 0);
605
606                 if(dptr->dnum == -1 || dptr->dnum > 254) {
607
608                         /*
609                          * Try and close the oldest handle not marked for
610                          * expect close in the hope that the client has
611                          * finished with that one.
612                          */
613
614                         dptr_close_oldest(sconn, true);
615
616                         /* Now try again... */
617                         dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 0);
618                         if(dptr->dnum == -1 || dptr->dnum > 254) {
619                                 DEBUG(0,("dptr_create: returned %d: Error - all old dirptrs in use ?\n", dptr->dnum));
620                                 TALLOC_FREE(dptr);
621                                 TALLOC_FREE(dir_hnd);
622                                 return NT_STATUS_TOO_MANY_OPENED_FILES;
623                         }
624                 }
625         } else {
626
627                 /*
628                  * This is a new-style trans2 request. Allocate from
629                  * a range that will return 256 - MAX_DIRECTORY_HANDLES.
630                  */
631
632                 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 255);
633
634                 if(dptr->dnum == -1 || dptr->dnum < 255) {
635
636                         /*
637                          * Try and close the oldest handle close in the hope that
638                          * the client has finished with that one. This will only
639                          * happen in the case of the Win98 client bug where it leaks
640                          * directory handles.
641                          */
642
643                         dptr_close_oldest(sconn, false);
644
645                         /* Now try again... */
646                         dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 255);
647
648                         if(dptr->dnum == -1 || dptr->dnum < 255) {
649                                 DEBUG(0,("dptr_create: returned %d: Error - all new dirptrs in use ?\n", dptr->dnum));
650                                 TALLOC_FREE(dptr);
651                                 TALLOC_FREE(dir_hnd);
652                                 return NT_STATUS_TOO_MANY_OPENED_FILES;
653                         }
654                 }
655         }
656
657         bitmap_set(sconn->searches.dptr_bmap, dptr->dnum);
658
659         dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
660
661         DLIST_ADD(sconn->searches.dirptrs, dptr);
662
663 done:
664         DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
665                 dptr->dnum,path,expect_close));  
666
667         *dptr_ret = dptr;
668
669         return NT_STATUS_OK;
670 }
671
672
673 /****************************************************************************
674  Wrapper functions to access the lower level directory handles.
675 ****************************************************************************/
676
677 void dptr_CloseDir(files_struct *fsp)
678 {
679         if (fsp->dptr) {
680                 /*
681                  * The destructor for the struct smb_Dir
682                  * (fsp->dptr->dir_hnd) now handles
683                  * all resource deallocation.
684                  */
685                 dptr_close_internal(fsp->dptr);
686                 fsp->dptr = NULL;
687         }
688 }
689
690 void dptr_SeekDir(struct dptr_struct *dptr, long offset)
691 {
692         SeekDir(dptr->dir_hnd, offset);
693 }
694
695 long dptr_TellDir(struct dptr_struct *dptr)
696 {
697         return TellDir(dptr->dir_hnd);
698 }
699
700 bool dptr_has_wild(struct dptr_struct *dptr)
701 {
702         return dptr->has_wild;
703 }
704
705 int dptr_dnum(struct dptr_struct *dptr)
706 {
707         return dptr->dnum;
708 }
709
710 bool dptr_get_priv(struct dptr_struct *dptr)
711 {
712         return dptr->priv;
713 }
714
715 void dptr_set_priv(struct dptr_struct *dptr)
716 {
717         dptr->priv = true;
718 }
719
720 /****************************************************************************
721  Return the next visible file name, skipping veto'd and invisible files.
722 ****************************************************************************/
723
724 static const char *dptr_normal_ReadDirName(struct dptr_struct *dptr,
725                                            long *poffset, SMB_STRUCT_STAT *pst,
726                                            char **ptalloced)
727 {
728         /* Normal search for the next file. */
729         const char *name;
730         char *talloced = NULL;
731
732         while ((name = ReadDirName(dptr->dir_hnd, poffset, pst, &talloced))
733                != NULL) {
734                 if (is_visible_file(dptr->conn, dptr->path, name, pst, True)) {
735                         *ptalloced = talloced;
736                         return name;
737                 }
738                 TALLOC_FREE(talloced);
739         }
740         return NULL;
741 }
742
743 /****************************************************************************
744  Return the next visible file name, skipping veto'd and invisible files.
745 ****************************************************************************/
746
747 char *dptr_ReadDirName(TALLOC_CTX *ctx,
748                         struct dptr_struct *dptr,
749                         long *poffset,
750                         SMB_STRUCT_STAT *pst)
751 {
752         struct smb_filename smb_fname_base;
753         char *name = NULL;
754         const char *name_temp = NULL;
755         char *talloced = NULL;
756         char *pathreal = NULL;
757         char *found_name = NULL;
758         int ret;
759
760         SET_STAT_INVALID(*pst);
761
762         if (dptr->has_wild || dptr->did_stat) {
763                 name_temp = dptr_normal_ReadDirName(dptr, poffset, pst,
764                                                     &talloced);
765                 if (name_temp == NULL) {
766                         return NULL;
767                 }
768                 if (talloced != NULL) {
769                         return talloc_move(ctx, &talloced);
770                 }
771                 return talloc_strdup(ctx, name_temp);
772         }
773
774         /* If poffset is -1 then we know we returned this name before and we
775          * have no wildcards. We're at the end of the directory. */
776         if (*poffset == END_OF_DIRECTORY_OFFSET) {
777                 return NULL;
778         }
779
780         /* We know the stored wcard contains no wildcard characters.
781          * See if we can match with a stat call. If we can't, then set
782          * did_stat to true to ensure we only do this once and keep
783          * searching. */
784
785         dptr->did_stat = true;
786
787         /* First check if it should be visible. */
788         if (!is_visible_file(dptr->conn, dptr->path, dptr->wcard,
789             pst, true))
790         {
791                 /* This only returns false if the file was found, but
792                    is explicitly not visible. Set us to end of
793                    directory, but return NULL as we know we can't ever
794                    find it. */
795                 goto ret;
796         }
797
798         if (VALID_STAT(*pst)) {
799                 name = talloc_strdup(ctx, dptr->wcard);
800                 goto ret;
801         }
802
803         pathreal = talloc_asprintf(ctx,
804                                 "%s/%s",
805                                 dptr->path,
806                                 dptr->wcard);
807         if (!pathreal)
808                 return NULL;
809
810         /* Create an smb_filename with stream_name == NULL. */
811         ZERO_STRUCT(smb_fname_base);
812         smb_fname_base.base_name = pathreal;
813
814         if (SMB_VFS_STAT(dptr->conn, &smb_fname_base) == 0) {
815                 *pst = smb_fname_base.st;
816                 name = talloc_strdup(ctx, dptr->wcard);
817                 goto clean;
818         } else {
819                 /* If we get any other error than ENOENT or ENOTDIR
820                    then the file exists we just can't stat it. */
821                 if (errno != ENOENT && errno != ENOTDIR) {
822                         name = talloc_strdup(ctx, dptr->wcard);
823                         goto clean;
824                 }
825         }
826
827         /* Stat failed. We know this is authoratiative if we are
828          * providing case sensitive semantics or the underlying
829          * filesystem is case sensitive.
830          */
831         if (dptr->conn->case_sensitive ||
832             !(dptr->conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH))
833         {
834                 goto clean;
835         }
836
837         /*
838          * Try case-insensitive stat if the fs has the ability. This avoids
839          * scanning the whole directory.
840          */
841         ret = SMB_VFS_GET_REAL_FILENAME(dptr->conn, dptr->path, dptr->wcard,
842                                         ctx, &found_name);
843         if (ret == 0) {
844                 name = found_name;
845                 goto clean;
846         } else if (errno == ENOENT) {
847                 /* The case-insensitive lookup was authoritative. */
848                 goto clean;
849         }
850
851         TALLOC_FREE(pathreal);
852
853         name_temp = dptr_normal_ReadDirName(dptr, poffset, pst, &talloced);
854         if (name_temp == NULL) {
855                 return NULL;
856         }
857         if (talloced != NULL) {
858                 return talloc_move(ctx, &talloced);
859         }
860         return talloc_strdup(ctx, name_temp);
861
862 clean:
863         TALLOC_FREE(pathreal);
864 ret:
865         /* We need to set the underlying dir_hnd offset to -1
866          * also as this function is usually called with the
867          * output from TellDir. */
868         dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
869         return name;
870 }
871
872 /****************************************************************************
873  Search for a file by name, skipping veto'ed and not visible files.
874 ****************************************************************************/
875
876 bool dptr_SearchDir(struct dptr_struct *dptr, const char *name, long *poffset, SMB_STRUCT_STAT *pst)
877 {
878         SET_STAT_INVALID(*pst);
879
880         if (!dptr->has_wild && (dptr->dir_hnd->offset == END_OF_DIRECTORY_OFFSET)) {
881                 /* This is a singleton directory and we're already at the end. */
882                 *poffset = END_OF_DIRECTORY_OFFSET;
883                 return False;
884         }
885
886         return SearchDir(dptr->dir_hnd, name, poffset);
887 }
888
889 /****************************************************************************
890  Initialize variables & state data at the beginning of all search SMB requests.
891 ****************************************************************************/
892 void dptr_init_search_op(struct dptr_struct *dptr)
893 {
894         SMB_VFS_INIT_SEARCH_OP(dptr->conn, dptr->dir_hnd->dir);
895 }
896
897 /****************************************************************************
898  Map a native directory offset to a 32-bit cookie.
899 ****************************************************************************/
900
901 static uint32_t map_dir_offset_to_wire(struct dptr_struct *dptr, long offset)
902 {
903         return (uint32_t)offset;
904 }
905
906 /****************************************************************************
907  Fill the 5 byte server reserved dptr field.
908 ****************************************************************************/
909
910 bool dptr_fill(struct smbd_server_connection *sconn,
911                char *buf1,unsigned int key)
912 {
913         unsigned char *buf = (unsigned char *)buf1;
914         struct dptr_struct *dptr = dptr_get(sconn, key, false);
915         uint32_t wire_offset;
916         if (!dptr) {
917                 DEBUG(1,("filling null dirptr %d\n",key));
918                 return(False);
919         }
920         wire_offset = map_dir_offset_to_wire(dptr,TellDir(dptr->dir_hnd));
921         DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key,
922                 (long)dptr->dir_hnd,(int)wire_offset));
923         buf[0] = key;
924         SIVAL(buf,1,wire_offset);
925         return(True);
926 }
927
928 /****************************************************************************
929  Fetch the dir ptr and seek it given the 5 byte server field.
930 ****************************************************************************/
931
932 struct dptr_struct *dptr_fetch(struct smbd_server_connection *sconn,
933                                char *buf, int *num)
934 {
935         unsigned int key = *(unsigned char *)buf;
936         struct dptr_struct *dptr = dptr_get(sconn, key, false);
937         uint32_t wire_offset;
938         long seekoff;
939
940         if (!dptr) {
941                 DEBUG(3,("fetched null dirptr %d\n",key));
942                 return(NULL);
943         }
944         *num = key;
945         wire_offset = IVAL(buf,1);
946         if (wire_offset == (uint32_t)-1) {
947                 seekoff = END_OF_DIRECTORY_OFFSET;
948         } else {
949                 seekoff = (long)wire_offset;
950         }
951         SeekDir(dptr->dir_hnd,seekoff);
952         DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
953                 key, dptr->path, (int)seekoff));
954         return(dptr);
955 }
956
957 /****************************************************************************
958  Fetch the dir ptr.
959 ****************************************************************************/
960
961 struct dptr_struct *dptr_fetch_lanman2(struct smbd_server_connection *sconn,
962                                        int dptr_num)
963 {
964         struct dptr_struct *dptr  = dptr_get(sconn, dptr_num, false);
965
966         if (!dptr) {
967                 DEBUG(3,("fetched null dirptr %d\n",dptr_num));
968                 return(NULL);
969         }
970         DEBUG(3,("fetching dirptr %d for path %s\n",dptr_num,dptr->path));
971         return(dptr);
972 }
973
974 static bool mangle_mask_match(connection_struct *conn,
975                 const char *filename,
976                 const char *mask)
977 {
978         char mname[13];
979
980         if (!name_to_8_3(filename,mname,False,conn->params)) {
981                 return False;
982         }
983         return mask_match_search(mname,mask,False);
984 }
985
986 bool smbd_dirptr_get_entry(TALLOC_CTX *ctx,
987                            struct dptr_struct *dirptr,
988                            const char *mask,
989                            uint32_t dirtype,
990                            bool dont_descend,
991                            bool ask_sharemode,
992                            bool (*match_fn)(TALLOC_CTX *ctx,
993                                             void *private_data,
994                                             const char *dname,
995                                             const char *mask,
996                                             char **_fname),
997                            bool (*mode_fn)(TALLOC_CTX *ctx,
998                                            void *private_data,
999                                            struct smb_filename *smb_fname,
1000                                            uint32_t *_mode),
1001                            void *private_data,
1002                            char **_fname,
1003                            struct smb_filename **_smb_fname,
1004                            uint32_t *_mode,
1005                            long *_prev_offset)
1006 {
1007         connection_struct *conn = dirptr->conn;
1008         size_t slashlen;
1009         size_t pathlen;
1010
1011         *_smb_fname = NULL;
1012         *_mode = 0;
1013
1014         pathlen = strlen(dirptr->path);
1015         slashlen = ( dirptr->path[pathlen-1] != '/') ? 1 : 0;
1016
1017         while (true) {
1018                 long cur_offset;
1019                 long prev_offset;
1020                 SMB_STRUCT_STAT sbuf;
1021                 char *dname = NULL;
1022                 bool isdots;
1023                 char *fname = NULL;
1024                 char *pathreal = NULL;
1025                 struct smb_filename smb_fname;
1026                 uint32_t mode = 0;
1027                 bool ok;
1028
1029                 cur_offset = dptr_TellDir(dirptr);
1030                 prev_offset = cur_offset;
1031                 dname = dptr_ReadDirName(ctx, dirptr, &cur_offset, &sbuf);
1032
1033                 DEBUG(6,("smbd_dirptr_get_entry: dirptr 0x%lx now at offset %ld\n",
1034                         (long)dirptr, cur_offset));
1035
1036                 if (dname == NULL) {
1037                         return false;
1038                 }
1039
1040                 isdots = (ISDOT(dname) || ISDOTDOT(dname));
1041                 if (dont_descend && !isdots) {
1042                         TALLOC_FREE(dname);
1043                         continue;
1044                 }
1045
1046                 /*
1047                  * fname may get mangled, dname is never mangled.
1048                  * Whenever we're accessing the filesystem we use
1049                  * pathreal which is composed from dname.
1050                  */
1051
1052                 ok = match_fn(ctx, private_data, dname, mask, &fname);
1053                 if (!ok) {
1054                         TALLOC_FREE(dname);
1055                         continue;
1056                 }
1057
1058                 /*
1059                  * This used to be
1060                  * pathreal = talloc_asprintf(ctx, "%s%s%s", dirptr->path,
1061                  *                            needslash?"/":"", dname);
1062                  * but this was measurably slower than doing the memcpy.
1063                  */
1064
1065                 pathreal = talloc_array(
1066                         ctx, char,
1067                         pathlen + slashlen + talloc_get_size(dname));
1068                 if (!pathreal) {
1069                         TALLOC_FREE(dname);
1070                         TALLOC_FREE(fname);
1071                         return false;
1072                 }
1073
1074                 memcpy(pathreal, dirptr->path, pathlen);
1075                 pathreal[pathlen] = '/';
1076                 memcpy(pathreal + slashlen + pathlen, dname,
1077                        talloc_get_size(dname));
1078
1079                 /* Create smb_fname with NULL stream_name. */
1080                 ZERO_STRUCT(smb_fname);
1081                 smb_fname.base_name = pathreal;
1082                 smb_fname.st = sbuf;
1083
1084                 ok = mode_fn(ctx, private_data, &smb_fname, &mode);
1085                 if (!ok) {
1086                         TALLOC_FREE(dname);
1087                         TALLOC_FREE(fname);
1088                         TALLOC_FREE(pathreal);
1089                         continue;
1090                 }
1091
1092                 if (!dir_check_ftype(mode, dirtype)) {
1093                         DEBUG(5,("[%s] attribs 0x%x didn't match 0x%x\n",
1094                                 fname, (unsigned int)mode, (unsigned int)dirtype));
1095                         TALLOC_FREE(dname);
1096                         TALLOC_FREE(fname);
1097                         TALLOC_FREE(pathreal);
1098                         continue;
1099                 }
1100
1101                 if (ask_sharemode) {
1102                         struct timespec write_time_ts;
1103                         struct file_id fileid;
1104
1105                         fileid = vfs_file_id_from_sbuf(conn,
1106                                                        &smb_fname.st);
1107                         get_file_infos(fileid, 0, NULL, &write_time_ts);
1108                         if (!null_timespec(write_time_ts)) {
1109                                 update_stat_ex_mtime(&smb_fname.st,
1110                                                      write_time_ts);
1111                         }
1112                 }
1113
1114                 DEBUG(3,("smbd_dirptr_get_entry mask=[%s] found %s "
1115                         "fname=%s (%s)\n",
1116                         mask, smb_fname_str_dbg(&smb_fname),
1117                         dname, fname));
1118
1119                 DirCacheAdd(dirptr->dir_hnd, dname, cur_offset);
1120
1121                 TALLOC_FREE(dname);
1122
1123                 *_smb_fname = cp_smb_filename(ctx, &smb_fname);
1124                 TALLOC_FREE(pathreal);
1125                 if (*_smb_fname == NULL) {
1126                         return false;
1127                 }
1128                 *_fname = fname;
1129                 *_mode = mode;
1130                 *_prev_offset = prev_offset;
1131
1132                 return true;
1133         }
1134
1135         return false;
1136 }
1137
1138 /****************************************************************************
1139  Get an 8.3 directory entry.
1140 ****************************************************************************/
1141
1142 static bool smbd_dirptr_8_3_match_fn(TALLOC_CTX *ctx,
1143                                      void *private_data,
1144                                      const char *dname,
1145                                      const char *mask,
1146                                      char **_fname)
1147 {
1148         connection_struct *conn = (connection_struct *)private_data;
1149
1150         if ((strcmp(mask,"*.*") == 0) ||
1151             mask_match_search(dname, mask, false) ||
1152             mangle_mask_match(conn, dname, mask)) {
1153                 char mname[13];
1154                 const char *fname;
1155
1156                 if (!mangle_is_8_3(dname, false, conn->params)) {
1157                         bool ok = name_to_8_3(dname, mname, false,
1158                                               conn->params);
1159                         if (!ok) {
1160                                 return false;
1161                         }
1162                         fname = mname;
1163                 } else {
1164                         fname = dname;
1165                 }
1166
1167                 *_fname = talloc_strdup(ctx, fname);
1168                 if (*_fname == NULL) {
1169                         return false;
1170                 }
1171
1172                 return true;
1173         }
1174
1175         return false;
1176 }
1177
1178 static bool smbd_dirptr_8_3_mode_fn(TALLOC_CTX *ctx,
1179                                     void *private_data,
1180                                     struct smb_filename *smb_fname,
1181                                     uint32_t *_mode)
1182 {
1183         connection_struct *conn = (connection_struct *)private_data;
1184
1185         if (!VALID_STAT(smb_fname->st)) {
1186                 if ((SMB_VFS_STAT(conn, smb_fname)) != 0) {
1187                         DEBUG(5,("smbd_dirptr_8_3_mode_fn: "
1188                                  "Couldn't stat [%s]. Error "
1189                                  "= %s\n",
1190                                  smb_fname_str_dbg(smb_fname),
1191                                  strerror(errno)));
1192                         return false;
1193                 }
1194         }
1195
1196         *_mode = dos_mode(conn, smb_fname);
1197         return true;
1198 }
1199
1200 bool get_dir_entry(TALLOC_CTX *ctx,
1201                 struct dptr_struct *dirptr,
1202                 const char *mask,
1203                 uint32_t dirtype,
1204                 char **_fname,
1205                 off_t *_size,
1206                 uint32_t *_mode,
1207                 struct timespec *_date,
1208                 bool check_descend,
1209                 bool ask_sharemode)
1210 {
1211         connection_struct *conn = dirptr->conn;
1212         char *fname = NULL;
1213         struct smb_filename *smb_fname = NULL;
1214         uint32_t mode = 0;
1215         long prev_offset;
1216         bool ok;
1217
1218         ok = smbd_dirptr_get_entry(ctx,
1219                                    dirptr,
1220                                    mask,
1221                                    dirtype,
1222                                    check_descend,
1223                                    ask_sharemode,
1224                                    smbd_dirptr_8_3_match_fn,
1225                                    smbd_dirptr_8_3_mode_fn,
1226                                    conn,
1227                                    &fname,
1228                                    &smb_fname,
1229                                    &mode,
1230                                    &prev_offset);
1231         if (!ok) {
1232                 return false;
1233         }
1234
1235         *_fname = talloc_move(ctx, &fname);
1236         *_size = smb_fname->st.st_ex_size;
1237         *_mode = mode;
1238         *_date = smb_fname->st.st_ex_mtime;
1239         TALLOC_FREE(smb_fname);
1240         return true;
1241 }
1242
1243 /*******************************************************************
1244  Check to see if a user can read a file. This is only approximate,
1245  it is used as part of the "hide unreadable" option. Don't
1246  use it for anything security sensitive.
1247 ********************************************************************/
1248
1249 static bool user_can_read_file(connection_struct *conn,
1250                                struct smb_filename *smb_fname)
1251 {
1252         /*
1253          * Never hide files from the root user.
1254          * We use (uid_t)0 here not sec_initial_uid()
1255          * as make test uses a single user context.
1256          */
1257
1258         if (get_current_uid(conn) == (uid_t)0) {
1259                 return True;
1260         }
1261
1262         return NT_STATUS_IS_OK(smbd_check_access_rights(conn,
1263                                 smb_fname,
1264                                 false,
1265                                 FILE_READ_DATA));
1266 }
1267
1268 /*******************************************************************
1269  Check to see if a user can write a file (and only files, we do not
1270  check dirs on this one). This is only approximate,
1271  it is used as part of the "hide unwriteable" option. Don't
1272  use it for anything security sensitive.
1273 ********************************************************************/
1274
1275 static bool user_can_write_file(connection_struct *conn,
1276                                 const struct smb_filename *smb_fname)
1277 {
1278         /*
1279          * Never hide files from the root user.
1280          * We use (uid_t)0 here not sec_initial_uid()
1281          * as make test uses a single user context.
1282          */
1283
1284         if (get_current_uid(conn) == (uid_t)0) {
1285                 return True;
1286         }
1287
1288         SMB_ASSERT(VALID_STAT(smb_fname->st));
1289
1290         /* Pseudo-open the file */
1291
1292         if(S_ISDIR(smb_fname->st.st_ex_mode)) {
1293                 return True;
1294         }
1295
1296         return can_write_to_file(conn, smb_fname);
1297 }
1298
1299 /*******************************************************************
1300   Is a file a "special" type ?
1301 ********************************************************************/
1302
1303 static bool file_is_special(connection_struct *conn,
1304                             const struct smb_filename *smb_fname)
1305 {
1306         /*
1307          * Never hide files from the root user.
1308          * We use (uid_t)0 here not sec_initial_uid()
1309          * as make test uses a single user context.
1310          */
1311
1312         if (get_current_uid(conn) == (uid_t)0) {
1313                 return False;
1314         }
1315
1316         SMB_ASSERT(VALID_STAT(smb_fname->st));
1317
1318         if (S_ISREG(smb_fname->st.st_ex_mode) ||
1319             S_ISDIR(smb_fname->st.st_ex_mode) ||
1320             S_ISLNK(smb_fname->st.st_ex_mode))
1321                 return False;
1322
1323         return True;
1324 }
1325
1326 /*******************************************************************
1327  Should the file be seen by the client?
1328  NOTE: A successful return is no guarantee of the file's existence.
1329 ********************************************************************/
1330
1331 bool is_visible_file(connection_struct *conn, const char *dir_path,
1332                      const char *name, SMB_STRUCT_STAT *pst, bool use_veto)
1333 {
1334         bool hide_unreadable = lp_hideunreadable(SNUM(conn));
1335         bool hide_unwriteable = lp_hideunwriteable_files(SNUM(conn));
1336         bool hide_special = lp_hide_special_files(SNUM(conn));
1337         char *entry = NULL;
1338         struct smb_filename *smb_fname_base = NULL;
1339         bool ret = false;
1340
1341         if ((strcmp(".",name) == 0) || (strcmp("..",name) == 0)) {
1342                 return True; /* . and .. are always visible. */
1343         }
1344
1345         /* If it's a vetoed file, pretend it doesn't even exist */
1346         if (use_veto && IS_VETO_PATH(conn, name)) {
1347                 DEBUG(10,("is_visible_file: file %s is vetoed.\n", name ));
1348                 return False;
1349         }
1350
1351         if (hide_unreadable || hide_unwriteable || hide_special) {
1352                 entry = talloc_asprintf(talloc_tos(), "%s/%s", dir_path, name);
1353                 if (!entry) {
1354                         ret = false;
1355                         goto out;
1356                 }
1357
1358                 /* Create an smb_filename with stream_name == NULL. */
1359                 smb_fname_base = synthetic_smb_fname(talloc_tos(), entry, NULL,
1360                                                      pst);
1361                 if (smb_fname_base == NULL) {
1362                         ret = false;
1363                         goto out;
1364                 }
1365
1366                 /* If the file name does not exist, there's no point checking
1367                  * the configuration options. We succeed, on the basis that the
1368                  * checks *might* have passed if the file was present.
1369                  */
1370                 if (!VALID_STAT(*pst)) {
1371                         if (SMB_VFS_STAT(conn, smb_fname_base) != 0) {
1372                                 ret = true;
1373                                 goto out;
1374                         } else {
1375                                 *pst = smb_fname_base->st;
1376                         }
1377                 }
1378
1379                 /* Honour _hide unreadable_ option */
1380                 if (hide_unreadable &&
1381                     !user_can_read_file(conn, smb_fname_base)) {
1382                         DEBUG(10,("is_visible_file: file %s is unreadable.\n",
1383                                  entry ));
1384                         ret = false;
1385                         goto out;
1386                 }
1387                 /* Honour _hide unwriteable_ option */
1388                 if (hide_unwriteable && !user_can_write_file(conn,
1389                                                              smb_fname_base)) {
1390                         DEBUG(10,("is_visible_file: file %s is unwritable.\n",
1391                                  entry ));
1392                         ret = false;
1393                         goto out;
1394                 }
1395                 /* Honour _hide_special_ option */
1396                 if (hide_special && file_is_special(conn, smb_fname_base)) {
1397                         DEBUG(10,("is_visible_file: file %s is special.\n",
1398                                  entry ));
1399                         ret = false;
1400                         goto out;
1401                 }
1402         }
1403
1404         ret = true;
1405  out:
1406         TALLOC_FREE(smb_fname_base);
1407         TALLOC_FREE(entry);
1408         return ret;
1409 }
1410
1411 static int smb_Dir_destructor(struct smb_Dir *dirp)
1412 {
1413         if (dirp->dir != NULL) {
1414                 SMB_VFS_CLOSEDIR(dirp->conn,dirp->dir);
1415                 if (dirp->fsp != NULL) {
1416                         /*
1417                          * The SMB_VFS_CLOSEDIR above
1418                          * closes the underlying fd inside
1419                          * dirp->fsp.
1420                          */
1421                         dirp->fsp->fh->fd = -1;
1422                         if (dirp->fsp->dptr != NULL) {
1423                                 SMB_ASSERT(dirp->fsp->dptr->dir_hnd == dirp);
1424                                 dirp->fsp->dptr->dir_hnd = NULL;
1425                         }
1426                         dirp->fsp = NULL;
1427                 }
1428         }
1429         if (dirp->conn->sconn && !dirp->conn->sconn->using_smb2) {
1430                 dirp->conn->sconn->searches.dirhandles_open--;
1431         }
1432         return 0;
1433 }
1434
1435 /*******************************************************************
1436  Open a directory.
1437 ********************************************************************/
1438
1439 struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn,
1440                         const char *name,
1441                         const char *mask,
1442                         uint32 attr)
1443 {
1444         struct smb_Dir *dirp = talloc_zero(mem_ctx, struct smb_Dir);
1445         struct smbd_server_connection *sconn = conn->sconn;
1446
1447         if (!dirp) {
1448                 return NULL;
1449         }
1450
1451         dirp->conn = conn;
1452         dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
1453
1454         dirp->dir_path = talloc_strdup(dirp, name);
1455         if (!dirp->dir_path) {
1456                 errno = ENOMEM;
1457                 goto fail;
1458         }
1459
1460         if (sconn && !sconn->using_smb2) {
1461                 sconn->searches.dirhandles_open++;
1462         }
1463         talloc_set_destructor(dirp, smb_Dir_destructor);
1464
1465         dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path, mask, attr);
1466         if (!dirp->dir) {
1467                 DEBUG(5,("OpenDir: Can't open %s. %s\n", dirp->dir_path,
1468                          strerror(errno) ));
1469                 goto fail;
1470         }
1471
1472         return dirp;
1473
1474   fail:
1475         TALLOC_FREE(dirp);
1476         return NULL;
1477 }
1478
1479 /*******************************************************************
1480  Open a directory from an fsp.
1481 ********************************************************************/
1482
1483 static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn,
1484                         files_struct *fsp,
1485                         const char *mask,
1486                         uint32 attr)
1487 {
1488         struct smb_Dir *dirp = talloc_zero(mem_ctx, struct smb_Dir);
1489         struct smbd_server_connection *sconn = conn->sconn;
1490
1491         if (!dirp) {
1492                 return NULL;
1493         }
1494
1495         dirp->conn = conn;
1496         dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
1497
1498         dirp->dir_path = talloc_strdup(dirp, fsp->fsp_name->base_name);
1499         if (!dirp->dir_path) {
1500                 errno = ENOMEM;
1501                 goto fail;
1502         }
1503
1504         if (sconn && !sconn->using_smb2) {
1505                 sconn->searches.dirhandles_open++;
1506         }
1507         talloc_set_destructor(dirp, smb_Dir_destructor);
1508
1509         if (fsp->is_directory && fsp->fh->fd != -1) {
1510                 dirp->dir = SMB_VFS_FDOPENDIR(fsp, mask, attr);
1511                 if (dirp->dir != NULL) {
1512                         dirp->fsp = fsp;
1513                 } else {
1514                         DEBUG(10,("OpenDir_fsp: SMB_VFS_FDOPENDIR on %s returned "
1515                                 "NULL (%s)\n",
1516                                 dirp->dir_path,
1517                                 strerror(errno)));
1518                         if (errno != ENOSYS) {
1519                                 return NULL;
1520                         }
1521                 }
1522         }
1523
1524         if (dirp->dir == NULL) {
1525                 /* FDOPENDIR didn't work. Use OPENDIR instead. */
1526                 dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path, mask, attr);
1527         }
1528
1529         if (!dirp->dir) {
1530                 DEBUG(5,("OpenDir_fsp: Can't open %s. %s\n", dirp->dir_path,
1531                          strerror(errno) ));
1532                 goto fail;
1533         }
1534
1535         return dirp;
1536
1537   fail:
1538         TALLOC_FREE(dirp);
1539         return NULL;
1540 }
1541
1542
1543 /*******************************************************************
1544  Read from a directory.
1545  Return directory entry, current offset, and optional stat information.
1546  Don't check for veto or invisible files.
1547 ********************************************************************/
1548
1549 const char *ReadDirName(struct smb_Dir *dirp, long *poffset,
1550                         SMB_STRUCT_STAT *sbuf, char **ptalloced)
1551 {
1552         const char *n;
1553         char *talloced = NULL;
1554         connection_struct *conn = dirp->conn;
1555
1556         /* Cheat to allow . and .. to be the first entries returned. */
1557         if (((*poffset == START_OF_DIRECTORY_OFFSET) ||
1558              (*poffset == DOT_DOT_DIRECTORY_OFFSET)) && (dirp->file_number < 2))
1559         {
1560                 if (dirp->file_number == 0) {
1561                         n = ".";
1562                         *poffset = dirp->offset = START_OF_DIRECTORY_OFFSET;
1563                 } else {
1564                         n = "..";
1565                         *poffset = dirp->offset = DOT_DOT_DIRECTORY_OFFSET;
1566                 }
1567                 dirp->file_number++;
1568                 *ptalloced = NULL;
1569                 return n;
1570         } else if (*poffset == END_OF_DIRECTORY_OFFSET) {
1571                 *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1572                 return NULL;
1573         } else {
1574                 /* A real offset, seek to it. */
1575                 SeekDir(dirp, *poffset);
1576         }
1577
1578         while ((n = vfs_readdirname(conn, dirp->dir, sbuf, &talloced))) {
1579                 /* Ignore . and .. - we've already returned them. */
1580                 if (*n == '.') {
1581                         if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) {
1582                                 TALLOC_FREE(talloced);
1583                                 continue;
1584                         }
1585                 }
1586                 *poffset = dirp->offset = SMB_VFS_TELLDIR(conn, dirp->dir);
1587                 *ptalloced = talloced;
1588                 dirp->file_number++;
1589                 return n;
1590         }
1591         *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1592         *ptalloced = NULL;
1593         return NULL;
1594 }
1595
1596 /*******************************************************************
1597  Rewind to the start.
1598 ********************************************************************/
1599
1600 void RewindDir(struct smb_Dir *dirp, long *poffset)
1601 {
1602         SMB_VFS_REWINDDIR(dirp->conn, dirp->dir);
1603         dirp->file_number = 0;
1604         dirp->offset = START_OF_DIRECTORY_OFFSET;
1605         *poffset = START_OF_DIRECTORY_OFFSET;
1606 }
1607
1608 /*******************************************************************
1609  Seek a dir.
1610 ********************************************************************/
1611
1612 void SeekDir(struct smb_Dir *dirp, long offset)
1613 {
1614         if (offset != dirp->offset) {
1615                 if (offset == START_OF_DIRECTORY_OFFSET) {
1616                         RewindDir(dirp, &offset);
1617                         /*
1618                          * Ok we should really set the file number here
1619                          * to 1 to enable ".." to be returned next. Trouble
1620                          * is I'm worried about callers using SeekDir(dirp,0)
1621                          * as equivalent to RewindDir(). So leave this alone
1622                          * for now.
1623                          */
1624                 } else if  (offset == DOT_DOT_DIRECTORY_OFFSET) {
1625                         RewindDir(dirp, &offset);
1626                         /*
1627                          * Set the file number to 2 - we want to get the first
1628                          * real file entry (the one we return after "..")
1629                          * on the next ReadDir.
1630                          */
1631                         dirp->file_number = 2;
1632                 } else if (offset == END_OF_DIRECTORY_OFFSET) {
1633                         ; /* Don't seek in this case. */
1634                 } else {
1635                         SMB_VFS_SEEKDIR(dirp->conn, dirp->dir, offset);
1636                 }
1637                 dirp->offset = offset;
1638         }
1639 }
1640
1641 /*******************************************************************
1642  Tell a dir position.
1643 ********************************************************************/
1644
1645 long TellDir(struct smb_Dir *dirp)
1646 {
1647         return(dirp->offset);
1648 }
1649
1650 /*******************************************************************
1651  Add an entry into the dcache.
1652 ********************************************************************/
1653
1654 static void DirCacheAdd(struct smb_Dir *dirp, const char *name, long offset)
1655 {
1656         struct name_cache_entry *e;
1657
1658         if (dirp->name_cache_size == 0) {
1659                 return;
1660         }
1661
1662         if (dirp->name_cache == NULL) {
1663                 dirp->name_cache = talloc_zero_array(
1664                         dirp, struct name_cache_entry, dirp->name_cache_size);
1665
1666                 if (dirp->name_cache == NULL) {
1667                         return;
1668                 }
1669         }
1670
1671         dirp->name_cache_index = (dirp->name_cache_index+1) %
1672                                         dirp->name_cache_size;
1673         e = &dirp->name_cache[dirp->name_cache_index];
1674         TALLOC_FREE(e->name);
1675         e->name = talloc_strdup(dirp, name);
1676         e->offset = offset;
1677 }
1678
1679 /*******************************************************************
1680  Find an entry by name. Leave us at the offset after it.
1681  Don't check for veto or invisible files.
1682 ********************************************************************/
1683
1684 bool SearchDir(struct smb_Dir *dirp, const char *name, long *poffset)
1685 {
1686         int i;
1687         const char *entry = NULL;
1688         char *talloced = NULL;
1689         connection_struct *conn = dirp->conn;
1690
1691         /* Search back in the name cache. */
1692         if (dirp->name_cache_size && dirp->name_cache) {
1693                 for (i = dirp->name_cache_index; i >= 0; i--) {
1694                         struct name_cache_entry *e = &dirp->name_cache[i];
1695                         if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1696                                 *poffset = e->offset;
1697                                 SeekDir(dirp, e->offset);
1698                                 return True;
1699                         }
1700                 }
1701                 for (i = dirp->name_cache_size - 1; i > dirp->name_cache_index; i--) {
1702                         struct name_cache_entry *e = &dirp->name_cache[i];
1703                         if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1704                                 *poffset = e->offset;
1705                                 SeekDir(dirp, e->offset);
1706                                 return True;
1707                         }
1708                 }
1709         }
1710
1711         /* Not found in the name cache. Rewind directory and start from scratch. */
1712         SMB_VFS_REWINDDIR(conn, dirp->dir);
1713         dirp->file_number = 0;
1714         *poffset = START_OF_DIRECTORY_OFFSET;
1715         while ((entry = ReadDirName(dirp, poffset, NULL, &talloced))) {
1716                 if (conn->case_sensitive ? (strcmp(entry, name) == 0) : strequal(entry, name)) {
1717                         TALLOC_FREE(talloced);
1718                         return True;
1719                 }
1720                 TALLOC_FREE(talloced);
1721         }
1722         return False;
1723 }
1724
1725 /*****************************************************************
1726  Is this directory empty ?
1727 *****************************************************************/
1728
1729 NTSTATUS can_delete_directory_fsp(files_struct *fsp)
1730 {
1731         NTSTATUS status = NT_STATUS_OK;
1732         long dirpos = 0;
1733         const char *dname = NULL;
1734         const char *dirname = fsp->fsp_name->base_name;
1735         char *talloced = NULL;
1736         SMB_STRUCT_STAT st;
1737         struct connection_struct *conn = fsp->conn;
1738         struct smb_Dir *dir_hnd = OpenDir_fsp(talloc_tos(),
1739                                         conn,
1740                                         fsp,
1741                                         NULL,
1742                                         0);
1743
1744         if (!dir_hnd) {
1745                 return map_nt_error_from_unix(errno);
1746         }
1747
1748         while ((dname = ReadDirName(dir_hnd, &dirpos, &st, &talloced))) {
1749                 /* Quick check for "." and ".." */
1750                 if (dname[0] == '.') {
1751                         if (!dname[1] || (dname[1] == '.' && !dname[2])) {
1752                                 TALLOC_FREE(talloced);
1753                                 continue;
1754                         }
1755                 }
1756
1757                 if (!is_visible_file(conn, dirname, dname, &st, True)) {
1758                         TALLOC_FREE(talloced);
1759                         continue;
1760                 }
1761
1762                 DEBUG(10,("got name %s - can't delete\n",
1763                          dname ));
1764                 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
1765                 break;
1766         }
1767         TALLOC_FREE(talloced);
1768         TALLOC_FREE(dir_hnd);
1769
1770         return status;
1771 }