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