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