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