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