935810bf3e0a12759254d9bce08b25b5184f90b9
[kamenim/samba.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_talloc(
125                 sconn, MAX_DIRECTORY_HANDLES);
126
127         if (sconn->smb1.searches.dptr_bmap == NULL) {
128                 return false;
129         }
130
131         return true;
132 }
133
134 /****************************************************************************
135  Idle a dptr - the directory is closed but the control info is kept.
136 ****************************************************************************/
137
138 static void dptr_idle(struct dptr_struct *dptr)
139 {
140         if (dptr->dir_hnd) {
141                 DEBUG(4,("Idling dptr dnum %d\n",dptr->dnum));
142                 TALLOC_FREE(dptr->dir_hnd);
143         }
144 }
145
146 /****************************************************************************
147  Idle the oldest dptr.
148 ****************************************************************************/
149
150 static void dptr_idleoldest(struct smbd_server_connection *sconn)
151 {
152         struct dptr_struct *dptr;
153
154         /*
155          * Go to the end of the list.
156          */
157         dptr = DLIST_TAIL(sconn->smb1.searches.dirptrs);
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 = DLIST_PREV(dptr)) {
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 = DLIST_PREV(dptr)) {
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         dptr_close_internal(dptr);
559         return 0;
560 }
561
562 void dptr_SeekDir(struct dptr_struct *dptr, long offset)
563 {
564         SeekDir(dptr->dir_hnd, offset);
565 }
566
567 long dptr_TellDir(struct dptr_struct *dptr)
568 {
569         return TellDir(dptr->dir_hnd);
570 }
571
572 bool dptr_has_wild(struct dptr_struct *dptr)
573 {
574         return dptr->has_wild;
575 }
576
577 int dptr_dnum(struct dptr_struct *dptr)
578 {
579         return dptr->dnum;
580 }
581
582 /****************************************************************************
583  Return the next visible file name, skipping veto'd and invisible files.
584 ****************************************************************************/
585
586 static const char *dptr_normal_ReadDirName(struct dptr_struct *dptr,
587                                            long *poffset, SMB_STRUCT_STAT *pst,
588                                            char **ptalloced)
589 {
590         /* Normal search for the next file. */
591         const char *name;
592         char *talloced = NULL;
593
594         while ((name = ReadDirName(dptr->dir_hnd, poffset, pst, &talloced))
595                != NULL) {
596                 if (is_visible_file(dptr->conn, dptr->path, name, pst, True)) {
597                         *ptalloced = talloced;
598                         return name;
599                 }
600                 TALLOC_FREE(talloced);
601         }
602         return NULL;
603 }
604
605 /****************************************************************************
606  Return the next visible file name, skipping veto'd and invisible files.
607 ****************************************************************************/
608
609 char *dptr_ReadDirName(TALLOC_CTX *ctx,
610                         struct dptr_struct *dptr,
611                         long *poffset,
612                         SMB_STRUCT_STAT *pst)
613 {
614         struct smb_filename smb_fname_base;
615         char *name = NULL;
616         const char *name_temp = NULL;
617         char *talloced = NULL;
618         char *pathreal = NULL;
619         char *found_name = NULL;
620         int ret;
621
622         SET_STAT_INVALID(*pst);
623
624         if (dptr->has_wild || dptr->did_stat) {
625                 name_temp = dptr_normal_ReadDirName(dptr, poffset, pst,
626                                                     &talloced);
627                 if (name_temp == NULL) {
628                         return NULL;
629                 }
630                 if (talloced != NULL) {
631                         return talloc_move(ctx, &talloced);
632                 }
633                 return talloc_strdup(ctx, name_temp);
634         }
635
636         /* If poffset is -1 then we know we returned this name before and we
637          * have no wildcards. We're at the end of the directory. */
638         if (*poffset == END_OF_DIRECTORY_OFFSET) {
639                 return NULL;
640         }
641
642         /* We know the stored wcard contains no wildcard characters.
643          * See if we can match with a stat call. If we can't, then set
644          * did_stat to true to ensure we only do this once and keep
645          * searching. */
646
647         dptr->did_stat = true;
648
649         /* First check if it should be visible. */
650         if (!is_visible_file(dptr->conn, dptr->path, dptr->wcard,
651             pst, true))
652         {
653                 /* This only returns false if the file was found, but
654                    is explicitly not visible. Set us to end of
655                    directory, but return NULL as we know we can't ever
656                    find it. */
657                 goto ret;
658         }
659
660         if (VALID_STAT(*pst)) {
661                 name = talloc_strdup(ctx, dptr->wcard);
662                 goto ret;
663         }
664
665         pathreal = talloc_asprintf(ctx,
666                                 "%s/%s",
667                                 dptr->path,
668                                 dptr->wcard);
669         if (!pathreal)
670                 return NULL;
671
672         /* Create an smb_filename with stream_name == NULL. */
673         ZERO_STRUCT(smb_fname_base);
674         smb_fname_base.base_name = pathreal;
675
676         if (SMB_VFS_STAT(dptr->conn, &smb_fname_base) == 0) {
677                 *pst = smb_fname_base.st;
678                 name = talloc_strdup(ctx, dptr->wcard);
679                 goto clean;
680         } else {
681                 /* If we get any other error than ENOENT or ENOTDIR
682                    then the file exists we just can't stat it. */
683                 if (errno != ENOENT && errno != ENOTDIR) {
684                         name = talloc_strdup(ctx, dptr->wcard);
685                         goto clean;
686                 }
687         }
688
689         /* Stat failed. We know this is authoratiative if we are
690          * providing case sensitive semantics or the underlying
691          * filesystem is case sensitive.
692          */
693         if (dptr->conn->case_sensitive ||
694             !(dptr->conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH))
695         {
696                 goto clean;
697         }
698
699         /*
700          * Try case-insensitive stat if the fs has the ability. This avoids
701          * scanning the whole directory.
702          */
703         ret = SMB_VFS_GET_REAL_FILENAME(dptr->conn, dptr->path, dptr->wcard,
704                                         ctx, &found_name);
705         if (ret == 0) {
706                 name = found_name;
707                 goto clean;
708         } else if (errno == ENOENT) {
709                 /* The case-insensitive lookup was authoritative. */
710                 goto clean;
711         }
712
713         TALLOC_FREE(pathreal);
714
715         name_temp = dptr_normal_ReadDirName(dptr, poffset, pst, &talloced);
716         if (name_temp == NULL) {
717                 return NULL;
718         }
719         if (talloced != NULL) {
720                 return talloc_move(ctx, &talloced);
721         }
722         return talloc_strdup(ctx, name_temp);
723
724 clean:
725         TALLOC_FREE(pathreal);
726 ret:
727         /* We need to set the underlying dir_hnd offset to -1
728          * also as this function is usually called with the
729          * output from TellDir. */
730         dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
731         return name;
732 }
733
734 /****************************************************************************
735  Search for a file by name, skipping veto'ed and not visible files.
736 ****************************************************************************/
737
738 bool dptr_SearchDir(struct dptr_struct *dptr, const char *name, long *poffset, SMB_STRUCT_STAT *pst)
739 {
740         SET_STAT_INVALID(*pst);
741
742         if (!dptr->has_wild && (dptr->dir_hnd->offset == END_OF_DIRECTORY_OFFSET)) {
743                 /* This is a singleton directory and we're already at the end. */
744                 *poffset = END_OF_DIRECTORY_OFFSET;
745                 return False;
746         }
747
748         return SearchDir(dptr->dir_hnd, name, poffset);
749 }
750
751 /****************************************************************************
752  Add the name we're returning into the underlying cache.
753 ****************************************************************************/
754
755 void dptr_DirCacheAdd(struct dptr_struct *dptr, const char *name, long offset)
756 {
757         DirCacheAdd(dptr->dir_hnd, name, offset);
758 }
759
760 /****************************************************************************
761  Initialize variables & state data at the beginning of all search SMB requests.
762 ****************************************************************************/
763 void dptr_init_search_op(struct dptr_struct *dptr)
764 {
765         SMB_VFS_INIT_SEARCH_OP(dptr->conn, dptr->dir_hnd->dir);
766 }
767
768 /****************************************************************************
769  Fill the 5 byte server reserved dptr field.
770 ****************************************************************************/
771
772 bool dptr_fill(struct smbd_server_connection *sconn,
773                char *buf1,unsigned int key)
774 {
775         unsigned char *buf = (unsigned char *)buf1;
776         struct dptr_struct *dptr = dptr_get(sconn, key, false);
777         uint32 offset;
778         if (!dptr) {
779                 DEBUG(1,("filling null dirptr %d\n",key));
780                 return(False);
781         }
782         offset = (uint32)TellDir(dptr->dir_hnd);
783         DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key,
784                 (long)dptr->dir_hnd,(int)offset));
785         buf[0] = key;
786         SIVAL(buf,1,offset);
787         return(True);
788 }
789
790 /****************************************************************************
791  Fetch the dir ptr and seek it given the 5 byte server field.
792 ****************************************************************************/
793
794 struct dptr_struct *dptr_fetch(struct smbd_server_connection *sconn,
795                                char *buf, int *num)
796 {
797         unsigned int key = *(unsigned char *)buf;
798         struct dptr_struct *dptr = dptr_get(sconn, key, false);
799         uint32 offset;
800         long seekoff;
801
802         if (!dptr) {
803                 DEBUG(3,("fetched null dirptr %d\n",key));
804                 return(NULL);
805         }
806         *num = key;
807         offset = IVAL(buf,1);
808         if (offset == (uint32)-1) {
809                 seekoff = END_OF_DIRECTORY_OFFSET;
810         } else {
811                 seekoff = (long)offset;
812         }
813         SeekDir(dptr->dir_hnd,seekoff);
814         DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
815                 key, dptr->path, (int)seekoff));
816         return(dptr);
817 }
818
819 /****************************************************************************
820  Fetch the dir ptr.
821 ****************************************************************************/
822
823 struct dptr_struct *dptr_fetch_lanman2(struct smbd_server_connection *sconn,
824                                        int dptr_num)
825 {
826         struct dptr_struct *dptr  = dptr_get(sconn, dptr_num, false);
827
828         if (!dptr) {
829                 DEBUG(3,("fetched null dirptr %d\n",dptr_num));
830                 return(NULL);
831         }
832         DEBUG(3,("fetching dirptr %d for path %s\n",dptr_num,dptr->path));
833         return(dptr);
834 }
835
836 /****************************************************************************
837  Check that a file matches a particular file type.
838 ****************************************************************************/
839
840 bool dir_check_ftype(connection_struct *conn, uint32 mode, uint32 dirtype)
841 {
842         uint32 mask;
843
844         /* Check the "may have" search bits. */
845         if (((mode & ~dirtype) & (aHIDDEN | aSYSTEM | aDIR)) != 0)
846                 return False;
847
848         /* Check the "must have" bits, which are the may have bits shifted eight */
849         /* If must have bit is set, the file/dir can not be returned in search unless the matching
850                 file attribute is set */
851         mask = ((dirtype >> 8) & (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM)); /* & 0x37 */
852         if(mask) {
853                 if((mask & (mode & (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM))) == mask)   /* check if matching attribute present */
854                         return True;
855                 else
856                         return False;
857         }
858
859         return True;
860 }
861
862 static bool mangle_mask_match(connection_struct *conn,
863                 const char *filename,
864                 const char *mask)
865 {
866         char mname[13];
867
868         if (!name_to_8_3(filename,mname,False,conn->params)) {
869                 return False;
870         }
871         return mask_match_search(mname,mask,False);
872 }
873
874 bool smbd_dirptr_get_entry(TALLOC_CTX *ctx,
875                            struct dptr_struct *dirptr,
876                            const char *mask,
877                            uint32_t dirtype,
878                            bool dont_descend,
879                            bool ask_sharemode,
880                            bool (*match_fn)(TALLOC_CTX *ctx,
881                                             void *private_data,
882                                             const char *dname,
883                                             const char *mask,
884                                             char **_fname),
885                            bool (*mode_fn)(TALLOC_CTX *ctx,
886                                            void *private_data,
887                                            struct smb_filename *smb_fname,
888                                            uint32_t *_mode),
889                            void *private_data,
890                            char **_fname,
891                            struct smb_filename **_smb_fname,
892                            uint32_t *_mode,
893                            long *_prev_offset)
894 {
895         connection_struct *conn = dirptr->conn;
896         bool needslash;
897
898         *_smb_fname = NULL;
899         *_mode = 0;
900
901         needslash = ( dirptr->path[strlen(dirptr->path) -1] != '/');
902
903         while (true) {
904                 long cur_offset;
905                 long prev_offset;
906                 SMB_STRUCT_STAT sbuf;
907                 char *dname = NULL;
908                 bool isdots;
909                 char *fname = NULL;
910                 char *pathreal = NULL;
911                 struct smb_filename smb_fname;
912                 uint32_t mode = 0;
913                 bool ok;
914                 NTSTATUS status;
915
916                 cur_offset = dptr_TellDir(dirptr);
917                 prev_offset = cur_offset;
918                 dname = dptr_ReadDirName(ctx, dirptr, &cur_offset, &sbuf);
919
920                 DEBUG(6,("smbd_dirptr_get_entry: dirptr 0x%lx now at offset %ld\n",
921                         (long)dirptr, cur_offset));
922
923                 if (dname == NULL) {
924                         return false;
925                 }
926
927                 isdots = (ISDOT(dname) || ISDOTDOT(dname));
928                 if (dont_descend && !isdots) {
929                         TALLOC_FREE(dname);
930                         continue;
931                 }
932
933                 /*
934                  * fname may get mangled, dname is never mangled.
935                  * Whenever we're accessing the filesystem we use
936                  * pathreal which is composed from dname.
937                  */
938
939                 ok = match_fn(ctx, private_data, dname, mask, &fname);
940                 if (!ok) {
941                         TALLOC_FREE(dname);
942                         continue;
943                 }
944
945                 pathreal = talloc_asprintf(ctx, "%s%s%s",
946                                            dirptr->path,
947                                            needslash?"/":"",
948                                            dname);
949                 if (!pathreal) {
950                         TALLOC_FREE(dname);
951                         TALLOC_FREE(fname);
952                         return false;
953                 }
954
955                 /* Create smb_fname with NULL stream_name. */
956                 ZERO_STRUCT(smb_fname);
957                 smb_fname.base_name = pathreal;
958                 smb_fname.st = sbuf;
959
960                 ok = mode_fn(ctx, private_data, &smb_fname, &mode);
961                 if (!ok) {
962                         TALLOC_FREE(dname);
963                         TALLOC_FREE(fname);
964                         TALLOC_FREE(pathreal);
965                         continue;
966                 }
967
968                 if (!dir_check_ftype(conn, mode, dirtype)) {
969                         DEBUG(5,("[%s] attribs 0x%x didn't match 0x%x\n",
970                                 fname, (unsigned int)mode, (unsigned int)dirtype));
971                         TALLOC_FREE(dname);
972                         TALLOC_FREE(fname);
973                         TALLOC_FREE(pathreal);
974                         continue;
975                 }
976
977                 if (ask_sharemode) {
978                         struct timespec write_time_ts;
979                         struct file_id fileid;
980
981                         fileid = vfs_file_id_from_sbuf(conn,
982                                                        &smb_fname.st);
983                         get_file_infos(fileid, NULL, &write_time_ts);
984                         if (!null_timespec(write_time_ts)) {
985                                 update_stat_ex_mtime(&smb_fname.st,
986                                                      write_time_ts);
987                         }
988                 }
989
990                 DEBUG(3,("smbd_dirptr_get_entry mask=[%s] found %s "
991                         "fname=%s (%s)\n",
992                         mask, smb_fname_str_dbg(&smb_fname),
993                         dname, fname));
994
995                 DirCacheAdd(dirptr->dir_hnd, dname, cur_offset);
996
997                 TALLOC_FREE(dname);
998
999                 status = copy_smb_filename(ctx, &smb_fname, _smb_fname);
1000                 TALLOC_FREE(pathreal);
1001                 if (!NT_STATUS_IS_OK(status)) {
1002                         return false;
1003                 }
1004                 *_fname = fname;
1005                 *_mode = mode;
1006                 *_prev_offset = prev_offset;
1007
1008                 return true;
1009         }
1010
1011         return false;
1012 }
1013
1014 /****************************************************************************
1015  Get an 8.3 directory entry.
1016 ****************************************************************************/
1017
1018 static bool smbd_dirptr_8_3_match_fn(TALLOC_CTX *ctx,
1019                                      void *private_data,
1020                                      const char *dname,
1021                                      const char *mask,
1022                                      char **_fname)
1023 {
1024         connection_struct *conn = (connection_struct *)private_data;
1025
1026         if ((strcmp(mask,"*.*") == 0) ||
1027             mask_match_search(dname, mask, false) ||
1028             mangle_mask_match(conn, dname, mask)) {
1029                 char mname[13];
1030                 const char *fname;
1031
1032                 if (!mangle_is_8_3(dname, false, conn->params)) {
1033                         bool ok = name_to_8_3(dname, mname, false,
1034                                               conn->params);
1035                         if (!ok) {
1036                                 return false;
1037                         }
1038                         fname = mname;
1039                 } else {
1040                         fname = dname;
1041                 }
1042
1043                 *_fname = talloc_strdup(ctx, fname);
1044                 if (*_fname == NULL) {
1045                         return false;
1046                 }
1047
1048                 return true;
1049         }
1050
1051         return false;
1052 }
1053
1054 static bool smbd_dirptr_8_3_mode_fn(TALLOC_CTX *ctx,
1055                                     void *private_data,
1056                                     struct smb_filename *smb_fname,
1057                                     uint32_t *_mode)
1058 {
1059         connection_struct *conn = (connection_struct *)private_data;
1060
1061         if (!VALID_STAT(smb_fname->st)) {
1062                 if ((SMB_VFS_STAT(conn, smb_fname)) != 0) {
1063                         DEBUG(5,("smbd_dirptr_8_3_mode_fn: "
1064                                  "Couldn't stat [%s]. Error "
1065                                  "= %s\n",
1066                                  smb_fname_str_dbg(smb_fname),
1067                                  strerror(errno)));
1068                         return false;
1069                 }
1070         }
1071
1072         *_mode = dos_mode(conn, smb_fname);
1073         return true;
1074 }
1075
1076 bool get_dir_entry(TALLOC_CTX *ctx,
1077                 struct dptr_struct *dirptr,
1078                 const char *mask,
1079                 uint32_t dirtype,
1080                 char **_fname,
1081                 SMB_OFF_T *_size,
1082                 uint32_t *_mode,
1083                 struct timespec *_date,
1084                 bool check_descend,
1085                 bool ask_sharemode)
1086 {
1087         connection_struct *conn = dirptr->conn;
1088         char *fname = NULL;
1089         struct smb_filename *smb_fname = NULL;
1090         uint32_t mode = 0;
1091         long prev_offset;
1092         bool ok;
1093
1094         ok = smbd_dirptr_get_entry(ctx,
1095                                    dirptr,
1096                                    mask,
1097                                    dirtype,
1098                                    check_descend,
1099                                    ask_sharemode,
1100                                    smbd_dirptr_8_3_match_fn,
1101                                    smbd_dirptr_8_3_mode_fn,
1102                                    conn,
1103                                    &fname,
1104                                    &smb_fname,
1105                                    &mode,
1106                                    &prev_offset);
1107         if (!ok) {
1108                 return false;
1109         }
1110
1111         *_fname = talloc_move(ctx, &fname);
1112         *_size = smb_fname->st.st_ex_size;
1113         *_mode = mode;
1114         *_date = smb_fname->st.st_ex_mtime;
1115         TALLOC_FREE(smb_fname);
1116         return true;
1117 }
1118
1119 /*******************************************************************
1120  Check to see if a user can read a file. This is only approximate,
1121  it is used as part of the "hide unreadable" option. Don't
1122  use it for anything security sensitive.
1123 ********************************************************************/
1124
1125 static bool user_can_read_file(connection_struct *conn,
1126                                struct smb_filename *smb_fname)
1127 {
1128         /*
1129          * Never hide files from the root user.
1130          * We use (uid_t)0 here not sec_initial_uid()
1131          * as make test uses a single user context.
1132          */
1133
1134         if (get_current_uid(conn) == (uid_t)0) {
1135                 return True;
1136         }
1137
1138         return can_access_file_acl(conn, smb_fname, FILE_READ_DATA);
1139 }
1140
1141 /*******************************************************************
1142  Check to see if a user can write a file (and only files, we do not
1143  check dirs on this one). This is only approximate,
1144  it is used as part of the "hide unwriteable" option. Don't
1145  use it for anything security sensitive.
1146 ********************************************************************/
1147
1148 static bool user_can_write_file(connection_struct *conn,
1149                                 const struct smb_filename *smb_fname)
1150 {
1151         /*
1152          * Never hide files from the root user.
1153          * We use (uid_t)0 here not sec_initial_uid()
1154          * as make test uses a single user context.
1155          */
1156
1157         if (get_current_uid(conn) == (uid_t)0) {
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          * Never hide files from the root user.
1181          * We use (uid_t)0 here not sec_initial_uid()
1182          * as make test uses a single user context.
1183          */
1184
1185         if (get_current_uid(conn) == (uid_t)0) {
1186                 return False;
1187         }
1188
1189         SMB_ASSERT(VALID_STAT(smb_fname->st));
1190
1191         if (S_ISREG(smb_fname->st.st_ex_mode) ||
1192             S_ISDIR(smb_fname->st.st_ex_mode) ||
1193             S_ISLNK(smb_fname->st.st_ex_mode))
1194                 return False;
1195
1196         return True;
1197 }
1198
1199 /*******************************************************************
1200  Should the file be seen by the client?
1201  NOTE: A successful return is no guarantee of the file's existence.
1202 ********************************************************************/
1203
1204 bool is_visible_file(connection_struct *conn, const char *dir_path,
1205                      const char *name, SMB_STRUCT_STAT *pst, bool use_veto)
1206 {
1207         bool hide_unreadable = lp_hideunreadable(SNUM(conn));
1208         bool hide_unwriteable = lp_hideunwriteable_files(SNUM(conn));
1209         bool hide_special = lp_hide_special_files(SNUM(conn));
1210         char *entry = NULL;
1211         struct smb_filename *smb_fname_base = NULL;
1212         NTSTATUS status;
1213         bool ret = false;
1214
1215         if ((strcmp(".",name) == 0) || (strcmp("..",name) == 0)) {
1216                 return True; /* . and .. are always visible. */
1217         }
1218
1219         /* If it's a vetoed file, pretend it doesn't even exist */
1220         if (use_veto && IS_VETO_PATH(conn, name)) {
1221                 DEBUG(10,("is_visible_file: file %s is vetoed.\n", name ));
1222                 return False;
1223         }
1224
1225         if (hide_unreadable || hide_unwriteable || hide_special) {
1226                 entry = talloc_asprintf(talloc_tos(), "%s/%s", dir_path, name);
1227                 if (!entry) {
1228                         ret = false;
1229                         goto out;
1230                 }
1231
1232                 /* Create an smb_filename with stream_name == NULL. */
1233                 status = create_synthetic_smb_fname(talloc_tos(), entry, NULL,
1234                                                     pst, &smb_fname_base);
1235                 if (!NT_STATUS_IS_OK(status)) {
1236                         ret = false;
1237                         goto out;
1238                 }
1239
1240                 /* If the file name does not exist, there's no point checking
1241                  * the configuration options. We succeed, on the basis that the
1242                  * checks *might* have passed if the file was present.
1243                  */
1244                 if (!VALID_STAT(*pst)) {
1245                         if (SMB_VFS_STAT(conn, smb_fname_base) != 0) {
1246                                 ret = true;
1247                                 goto out;
1248                         } else {
1249                                 *pst = smb_fname_base->st;
1250                         }
1251                 }
1252
1253                 /* Honour _hide unreadable_ option */
1254                 if (hide_unreadable &&
1255                     !user_can_read_file(conn, smb_fname_base)) {
1256                         DEBUG(10,("is_visible_file: file %s is unreadable.\n",
1257                                  entry ));
1258                         ret = false;
1259                         goto out;
1260                 }
1261                 /* Honour _hide unwriteable_ option */
1262                 if (hide_unwriteable && !user_can_write_file(conn,
1263                                                              smb_fname_base)) {
1264                         DEBUG(10,("is_visible_file: file %s is unwritable.\n",
1265                                  entry ));
1266                         ret = false;
1267                         goto out;
1268                 }
1269                 /* Honour _hide_special_ option */
1270                 if (hide_special && file_is_special(conn, smb_fname_base)) {
1271                         DEBUG(10,("is_visible_file: file %s is special.\n",
1272                                  entry ));
1273                         ret = false;
1274                         goto out;
1275                 }
1276         }
1277
1278         ret = true;
1279  out:
1280         TALLOC_FREE(smb_fname_base);
1281         TALLOC_FREE(entry);
1282         return ret;
1283 }
1284
1285 static int smb_Dir_destructor(struct smb_Dir *dirp)
1286 {
1287         if (dirp->dir) {
1288                 SMB_VFS_CLOSEDIR(dirp->conn,dirp->dir);
1289         }
1290         if (dirp->conn->sconn) {
1291                 dirp->conn->sconn->smb1.searches.dirhandles_open--;
1292         }
1293         return 0;
1294 }
1295
1296 /*******************************************************************
1297  Open a directory.
1298 ********************************************************************/
1299
1300 struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn,
1301                         const char *name, const char *mask, uint32 attr)
1302 {
1303         struct smb_Dir *dirp = TALLOC_ZERO_P(mem_ctx, struct smb_Dir);
1304         struct smbd_server_connection *sconn = conn->sconn;
1305
1306         if (!dirp) {
1307                 return NULL;
1308         }
1309
1310         dirp->conn = conn;
1311         dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
1312
1313         dirp->dir_path = talloc_strdup(dirp, name);
1314         if (!dirp->dir_path) {
1315                 errno = ENOMEM;
1316                 goto fail;
1317         }
1318
1319         if (sconn) {
1320                 sconn->smb1.searches.dirhandles_open++;
1321         }
1322         talloc_set_destructor(dirp, smb_Dir_destructor);
1323
1324         dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path, mask, attr);
1325         if (!dirp->dir) {
1326                 DEBUG(5,("OpenDir: Can't open %s. %s\n", dirp->dir_path,
1327                          strerror(errno) ));
1328                 goto fail;
1329         }
1330
1331         return dirp;
1332
1333   fail:
1334         TALLOC_FREE(dirp);
1335         return NULL;
1336 }
1337
1338 /*******************************************************************
1339  Read from a directory.
1340  Return directory entry, current offset, and optional stat information.
1341  Don't check for veto or invisible files.
1342 ********************************************************************/
1343
1344 const char *ReadDirName(struct smb_Dir *dirp, long *poffset,
1345                         SMB_STRUCT_STAT *sbuf, char **ptalloced)
1346 {
1347         const char *n;
1348         char *talloced = NULL;
1349         connection_struct *conn = dirp->conn;
1350
1351         /* Cheat to allow . and .. to be the first entries returned. */
1352         if (((*poffset == START_OF_DIRECTORY_OFFSET) ||
1353              (*poffset == DOT_DOT_DIRECTORY_OFFSET)) && (dirp->file_number < 2))
1354         {
1355                 if (dirp->file_number == 0) {
1356                         n = ".";
1357                         *poffset = dirp->offset = START_OF_DIRECTORY_OFFSET;
1358                 } else {
1359                         n = "..";
1360                         *poffset = dirp->offset = DOT_DOT_DIRECTORY_OFFSET;
1361                 }
1362                 dirp->file_number++;
1363                 *ptalloced = NULL;
1364                 return n;
1365         } else if (*poffset == END_OF_DIRECTORY_OFFSET) {
1366                 *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1367                 return NULL;
1368         } else {
1369                 /* A real offset, seek to it. */
1370                 SeekDir(dirp, *poffset);
1371         }
1372
1373         while ((n = vfs_readdirname(conn, dirp->dir, sbuf, &talloced))) {
1374                 /* Ignore . and .. - we've already returned them. */
1375                 if (*n == '.') {
1376                         if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) {
1377                                 TALLOC_FREE(talloced);
1378                                 continue;
1379                         }
1380                 }
1381                 *poffset = dirp->offset = SMB_VFS_TELLDIR(conn, dirp->dir);
1382                 *ptalloced = talloced;
1383                 dirp->file_number++;
1384                 return n;
1385         }
1386         *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1387         *ptalloced = NULL;
1388         return NULL;
1389 }
1390
1391 /*******************************************************************
1392  Rewind to the start.
1393 ********************************************************************/
1394
1395 void RewindDir(struct smb_Dir *dirp, long *poffset)
1396 {
1397         SMB_VFS_REWINDDIR(dirp->conn, dirp->dir);
1398         dirp->file_number = 0;
1399         dirp->offset = START_OF_DIRECTORY_OFFSET;
1400         *poffset = START_OF_DIRECTORY_OFFSET;
1401 }
1402
1403 /*******************************************************************
1404  Seek a dir.
1405 ********************************************************************/
1406
1407 void SeekDir(struct smb_Dir *dirp, long offset)
1408 {
1409         if (offset != dirp->offset) {
1410                 if (offset == START_OF_DIRECTORY_OFFSET) {
1411                         RewindDir(dirp, &offset);
1412                         /*
1413                          * Ok we should really set the file number here
1414                          * to 1 to enable ".." to be returned next. Trouble
1415                          * is I'm worried about callers using SeekDir(dirp,0)
1416                          * as equivalent to RewindDir(). So leave this alone
1417                          * for now.
1418                          */
1419                 } else if  (offset == DOT_DOT_DIRECTORY_OFFSET) {
1420                         RewindDir(dirp, &offset);
1421                         /*
1422                          * Set the file number to 2 - we want to get the first
1423                          * real file entry (the one we return after "..")
1424                          * on the next ReadDir.
1425                          */
1426                         dirp->file_number = 2;
1427                 } else if (offset == END_OF_DIRECTORY_OFFSET) {
1428                         ; /* Don't seek in this case. */
1429                 } else {
1430                         SMB_VFS_SEEKDIR(dirp->conn, dirp->dir, offset);
1431                 }
1432                 dirp->offset = offset;
1433         }
1434 }
1435
1436 /*******************************************************************
1437  Tell a dir position.
1438 ********************************************************************/
1439
1440 long TellDir(struct smb_Dir *dirp)
1441 {
1442         return(dirp->offset);
1443 }
1444
1445 /*******************************************************************
1446  Add an entry into the dcache.
1447 ********************************************************************/
1448
1449 void DirCacheAdd(struct smb_Dir *dirp, const char *name, long offset)
1450 {
1451         struct name_cache_entry *e;
1452
1453         if (dirp->name_cache_size == 0) {
1454                 return;
1455         }
1456
1457         if (dirp->name_cache == NULL) {
1458                 dirp->name_cache = TALLOC_ZERO_ARRAY(
1459                         dirp, struct name_cache_entry, dirp->name_cache_size);
1460
1461                 if (dirp->name_cache == NULL) {
1462                         return;
1463                 }
1464         }
1465
1466         dirp->name_cache_index = (dirp->name_cache_index+1) %
1467                                         dirp->name_cache_size;
1468         e = &dirp->name_cache[dirp->name_cache_index];
1469         TALLOC_FREE(e->name);
1470         e->name = talloc_strdup(dirp, name);
1471         e->offset = offset;
1472 }
1473
1474 /*******************************************************************
1475  Find an entry by name. Leave us at the offset after it.
1476  Don't check for veto or invisible files.
1477 ********************************************************************/
1478
1479 bool SearchDir(struct smb_Dir *dirp, const char *name, long *poffset)
1480 {
1481         int i;
1482         const char *entry = NULL;
1483         char *talloced = NULL;
1484         connection_struct *conn = dirp->conn;
1485
1486         /* Search back in the name cache. */
1487         if (dirp->name_cache_size && dirp->name_cache) {
1488                 for (i = dirp->name_cache_index; i >= 0; i--) {
1489                         struct name_cache_entry *e = &dirp->name_cache[i];
1490                         if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1491                                 *poffset = e->offset;
1492                                 SeekDir(dirp, e->offset);
1493                                 return True;
1494                         }
1495                 }
1496                 for (i = dirp->name_cache_size - 1; i > dirp->name_cache_index; i--) {
1497                         struct name_cache_entry *e = &dirp->name_cache[i];
1498                         if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1499                                 *poffset = e->offset;
1500                                 SeekDir(dirp, e->offset);
1501                                 return True;
1502                         }
1503                 }
1504         }
1505
1506         /* Not found in the name cache. Rewind directory and start from scratch. */
1507         SMB_VFS_REWINDDIR(conn, dirp->dir);
1508         dirp->file_number = 0;
1509         *poffset = START_OF_DIRECTORY_OFFSET;
1510         while ((entry = ReadDirName(dirp, poffset, NULL, &talloced))) {
1511                 if (conn->case_sensitive ? (strcmp(entry, name) == 0) : strequal(entry, name)) {
1512                         TALLOC_FREE(talloced);
1513                         return True;
1514                 }
1515                 TALLOC_FREE(talloced);
1516         }
1517         return False;
1518 }
1519
1520 /*****************************************************************
1521  Is this directory empty ?
1522 *****************************************************************/
1523
1524 NTSTATUS can_delete_directory(struct connection_struct *conn,
1525                                 const char *dirname)
1526 {
1527         NTSTATUS status = NT_STATUS_OK;
1528         long dirpos = 0;
1529         const char *dname = NULL;
1530         char *talloced = NULL;
1531         SMB_STRUCT_STAT st;
1532         struct smb_Dir *dir_hnd = OpenDir(talloc_tos(), conn, dirname,
1533                                           NULL, 0);
1534
1535         if (!dir_hnd) {
1536                 return map_nt_error_from_unix(errno);
1537         }
1538
1539         while ((dname = ReadDirName(dir_hnd, &dirpos, &st, &talloced))) {
1540                 /* Quick check for "." and ".." */
1541                 if (dname[0] == '.') {
1542                         if (!dname[1] || (dname[1] == '.' && !dname[2])) {
1543                                 TALLOC_FREE(talloced);
1544                                 continue;
1545                         }
1546                 }
1547
1548                 if (!is_visible_file(conn, dirname, dname, &st, True)) {
1549                         TALLOC_FREE(talloced);
1550                         continue;
1551                 }
1552
1553                 DEBUG(10,("can_delete_directory: got name %s - can't delete\n",
1554                          dname ));
1555                 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
1556                 break;
1557         }
1558         TALLOC_FREE(talloced);
1559         TALLOC_FREE(dir_hnd);
1560
1561         return status;
1562 }