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