WHATSNEW: Start release notes for Samba 3.5.17.
[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         for(dptr = sconn->smb1.searches.dirptrs; dptr && dptr->next; dptr = dptr->next)
157                 ;
158
159         if(!dptr) {
160                 DEBUG(0,("No dptrs available to idle ?\n"));
161                 return;
162         }
163
164         /*
165          * Idle the oldest pointer.
166          */
167
168         for(; dptr; dptr = dptr->prev) {
169                 if (dptr->dir_hnd) {
170                         dptr_idle(dptr);
171                         return;
172                 }
173         }
174 }
175
176 /****************************************************************************
177  Get the struct dptr_struct for a dir index.
178 ****************************************************************************/
179
180 static struct dptr_struct *dptr_get(struct smbd_server_connection *sconn,
181                                     int key, bool forclose)
182 {
183         struct dptr_struct *dptr;
184
185         for(dptr = sconn->smb1.searches.dirptrs; dptr; dptr = dptr->next) {
186                 if(dptr->dnum == key) {
187                         if (!forclose && !dptr->dir_hnd) {
188                                 if (sconn->smb1.searches.dirhandles_open >= MAX_OPEN_DIRECTORIES)
189                                         dptr_idleoldest(sconn);
190                                 DEBUG(4,("dptr_get: Reopening dptr key %d\n",key));
191                                 if (!(dptr->dir_hnd = OpenDir(
192                                               NULL, dptr->conn, dptr->path,
193                                               dptr->wcard, dptr->attr))) {
194                                         DEBUG(4,("dptr_get: Failed to open %s (%s)\n",dptr->path,
195                                                 strerror(errno)));
196                                         return False;
197                                 }
198                         }
199                         DLIST_PROMOTE(sconn->smb1.searches.dirptrs,dptr);
200                         return dptr;
201                 }
202         }
203         return(NULL);
204 }
205
206 /****************************************************************************
207  Get the dir path for a dir index.
208 ****************************************************************************/
209
210 char *dptr_path(struct smbd_server_connection *sconn, int key)
211 {
212         struct dptr_struct *dptr = dptr_get(sconn, key, false);
213         if (dptr)
214                 return(dptr->path);
215         return(NULL);
216 }
217
218 /****************************************************************************
219  Get the dir wcard for a dir index.
220 ****************************************************************************/
221
222 char *dptr_wcard(struct smbd_server_connection *sconn, int key)
223 {
224         struct dptr_struct *dptr = dptr_get(sconn, key, false);
225         if (dptr)
226                 return(dptr->wcard);
227         return(NULL);
228 }
229
230 /****************************************************************************
231  Get the dir attrib for a dir index.
232 ****************************************************************************/
233
234 uint16 dptr_attr(struct smbd_server_connection *sconn, int key)
235 {
236         struct dptr_struct *dptr = dptr_get(sconn, key, false);
237         if (dptr)
238                 return(dptr->attr);
239         return(0);
240 }
241
242 /****************************************************************************
243  Close a dptr (internal func).
244 ****************************************************************************/
245
246 static void dptr_close_internal(struct dptr_struct *dptr)
247 {
248         struct smbd_server_connection *sconn = dptr->conn->sconn;
249
250         DEBUG(4,("closing dptr key %d\n",dptr->dnum));
251
252         if (sconn == NULL) {
253                 goto done;
254         }
255
256         DLIST_REMOVE(sconn->smb1.searches.dirptrs, dptr);
257
258         /*
259          * Free the dnum in the bitmap. Remember the dnum value is always 
260          * biased by one with respect to the bitmap.
261          */
262
263         if(bitmap_query(sconn->smb1.searches.dptr_bmap, dptr->dnum - 1) != true) {
264                 DEBUG(0,("dptr_close_internal : Error - closing dnum = %d and bitmap not set !\n",
265                         dptr->dnum ));
266         }
267
268         bitmap_clear(sconn->smb1.searches.dptr_bmap, dptr->dnum - 1);
269
270 done:
271         TALLOC_FREE(dptr->dir_hnd);
272
273         /* Lanman 2 specific code */
274         SAFE_FREE(dptr->wcard);
275         string_set(&dptr->path,"");
276         SAFE_FREE(dptr);
277 }
278
279 /****************************************************************************
280  Close a dptr given a key.
281 ****************************************************************************/
282
283 void dptr_close(struct smbd_server_connection *sconn, int *key)
284 {
285         struct dptr_struct *dptr;
286
287         if(*key == INVALID_DPTR_KEY)
288                 return;
289
290         /* OS/2 seems to use -1 to indicate "close all directories" */
291         if (*key == -1) {
292                 struct dptr_struct *next;
293                 for(dptr = sconn->smb1.searches.dirptrs; dptr; dptr = next) {
294                         next = dptr->next;
295                         dptr_close_internal(dptr);
296                 }
297                 *key = INVALID_DPTR_KEY;
298                 return;
299         }
300
301         dptr = dptr_get(sconn, *key, true);
302
303         if (!dptr) {
304                 DEBUG(0,("Invalid key %d given to dptr_close\n", *key));
305                 return;
306         }
307
308         dptr_close_internal(dptr);
309
310         *key = INVALID_DPTR_KEY;
311 }
312
313 /****************************************************************************
314  Close all dptrs for a cnum.
315 ****************************************************************************/
316
317 void dptr_closecnum(connection_struct *conn)
318 {
319         struct dptr_struct *dptr, *next;
320         struct smbd_server_connection *sconn = conn->sconn;
321
322         if (sconn == NULL) {
323                 return;
324         }
325
326         for(dptr = sconn->smb1.searches.dirptrs; dptr; dptr = next) {
327                 next = dptr->next;
328                 if (dptr->conn == conn) {
329                         dptr_close_internal(dptr);
330                 }
331         }
332 }
333
334 /****************************************************************************
335  Idle all dptrs for a cnum.
336 ****************************************************************************/
337
338 void dptr_idlecnum(connection_struct *conn)
339 {
340         struct dptr_struct *dptr;
341         struct smbd_server_connection *sconn = conn->sconn;
342
343         if (sconn == NULL) {
344                 return;
345         }
346
347         for(dptr = sconn->smb1.searches.dirptrs; dptr; dptr = dptr->next) {
348                 if (dptr->conn == conn && dptr->dir_hnd) {
349                         dptr_idle(dptr);
350                 }
351         }
352 }
353
354 /****************************************************************************
355  Close a dptr that matches a given path, only if it matches the spid also.
356 ****************************************************************************/
357
358 void dptr_closepath(struct smbd_server_connection *sconn,
359                     char *path,uint16 spid)
360 {
361         struct dptr_struct *dptr, *next;
362         for(dptr = sconn->smb1.searches.dirptrs; dptr; dptr = next) {
363                 next = dptr->next;
364                 if (spid == dptr->spid && strequal(dptr->path,path))
365                         dptr_close_internal(dptr);
366         }
367 }
368
369 /****************************************************************************
370  Try and close the oldest handle not marked for
371  expect close in the hope that the client has
372  finished with that one.
373 ****************************************************************************/
374
375 static void dptr_close_oldest(struct smbd_server_connection *sconn,
376                               bool old)
377 {
378         struct dptr_struct *dptr;
379
380         /*
381          * Go to the end of the list.
382          */
383         for(dptr = sconn->smb1.searches.dirptrs; dptr && dptr->next; dptr = dptr->next)
384                 ;
385
386         if(!dptr) {
387                 DEBUG(0,("No old dptrs available to close oldest ?\n"));
388                 return;
389         }
390
391         /*
392          * If 'old' is true, close the oldest oldhandle dnum (ie. 1 < dnum < 256) that
393          * does not have expect_close set. If 'old' is false, close
394          * one of the new dnum handles.
395          */
396
397         for(; dptr; dptr = dptr->prev) {
398                 if ((old && (dptr->dnum < 256) && !dptr->expect_close) ||
399                         (!old && (dptr->dnum > 255))) {
400                                 dptr_close_internal(dptr);
401                                 return;
402                 }
403         }
404 }
405
406 /****************************************************************************
407  Create a new dir ptr. If the flag old_handle is true then we must allocate
408  from the bitmap range 0 - 255 as old SMBsearch directory handles are only
409  one byte long. If old_handle is false we allocate from the range
410  256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
411  a directory handle is never zero.
412  wcard must not be zero.
413 ****************************************************************************/
414
415 NTSTATUS dptr_create(connection_struct *conn, const char *path, bool old_handle, bool expect_close,uint16 spid,
416                 const char *wcard, bool wcard_has_wild, uint32 attr, struct dptr_struct **dptr_ret)
417 {
418         struct smbd_server_connection *sconn = conn->sconn;
419         struct dptr_struct *dptr = NULL;
420         struct smb_Dir *dir_hnd;
421         NTSTATUS status;
422
423         DEBUG(5,("dptr_create dir=%s\n", path));
424
425         if (sconn == NULL) {
426                 DEBUG(0,("dptr_create: called with fake connection_struct\n"));
427                 return NT_STATUS_INTERNAL_ERROR;
428         }
429
430         if (!wcard) {
431                 return NT_STATUS_INVALID_PARAMETER;
432         }
433
434         status = check_name(conn,path);
435         if (!NT_STATUS_IS_OK(status)) {
436                 return status;
437         }
438
439         dir_hnd = OpenDir(NULL, conn, path, wcard, attr);
440         if (!dir_hnd) {
441                 return map_nt_error_from_unix(errno);
442         }
443
444         if (sconn->smb1.searches.dirhandles_open >= MAX_OPEN_DIRECTORIES) {
445                 dptr_idleoldest(sconn);
446         }
447
448         dptr = SMB_MALLOC_P(struct dptr_struct);
449         if(!dptr) {
450                 DEBUG(0,("malloc fail in dptr_create.\n"));
451                 TALLOC_FREE(dir_hnd);
452                 return NT_STATUS_NO_MEMORY;
453         }
454
455         ZERO_STRUCTP(dptr);
456
457         if(old_handle) {
458
459                 /*
460                  * This is an old-style SMBsearch request. Ensure the
461                  * value we return will fit in the range 1-255.
462                  */
463
464                 dptr->dnum = bitmap_find(sconn->smb1.searches.dptr_bmap, 0);
465
466                 if(dptr->dnum == -1 || dptr->dnum > 254) {
467
468                         /*
469                          * Try and close the oldest handle not marked for
470                          * expect close in the hope that the client has
471                          * finished with that one.
472                          */
473
474                         dptr_close_oldest(sconn, true);
475
476                         /* Now try again... */
477                         dptr->dnum = bitmap_find(sconn->smb1.searches.dptr_bmap, 0);
478                         if(dptr->dnum == -1 || dptr->dnum > 254) {
479                                 DEBUG(0,("dptr_create: returned %d: Error - all old dirptrs in use ?\n", dptr->dnum));
480                                 SAFE_FREE(dptr);
481                                 TALLOC_FREE(dir_hnd);
482                                 return NT_STATUS_TOO_MANY_OPENED_FILES;
483                         }
484                 }
485         } else {
486
487                 /*
488                  * This is a new-style trans2 request. Allocate from
489                  * a range that will return 256 - MAX_DIRECTORY_HANDLES.
490                  */
491
492                 dptr->dnum = bitmap_find(sconn->smb1.searches.dptr_bmap, 255);
493
494                 if(dptr->dnum == -1 || dptr->dnum < 255) {
495
496                         /*
497                          * Try and close the oldest handle close in the hope that
498                          * the client has finished with that one. This will only
499                          * happen in the case of the Win98 client bug where it leaks
500                          * directory handles.
501                          */
502
503                         dptr_close_oldest(sconn, false);
504
505                         /* Now try again... */
506                         dptr->dnum = bitmap_find(sconn->smb1.searches.dptr_bmap, 255);
507
508                         if(dptr->dnum == -1 || dptr->dnum < 255) {
509                                 DEBUG(0,("dptr_create: returned %d: Error - all new dirptrs in use ?\n", dptr->dnum));
510                                 SAFE_FREE(dptr);
511                                 TALLOC_FREE(dir_hnd);
512                                 return NT_STATUS_TOO_MANY_OPENED_FILES;
513                         }
514                 }
515         }
516
517         bitmap_set(sconn->smb1.searches.dptr_bmap, dptr->dnum);
518
519         dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
520
521         string_set(&dptr->path,path);
522         dptr->conn = conn;
523         dptr->dir_hnd = dir_hnd;
524         dptr->spid = spid;
525         dptr->expect_close = expect_close;
526         dptr->wcard = SMB_STRDUP(wcard);
527         if (!dptr->wcard) {
528                 bitmap_clear(sconn->smb1.searches.dptr_bmap, dptr->dnum - 1);
529                 SAFE_FREE(dptr);
530                 TALLOC_FREE(dir_hnd);
531                 return NT_STATUS_NO_MEMORY;
532         }
533         if (lp_posix_pathnames() || (wcard[0] == '.' && wcard[1] == 0)) {
534                 dptr->has_wild = True;
535         } else {
536                 dptr->has_wild = wcard_has_wild;
537         }
538
539         dptr->attr = attr;
540
541         DLIST_ADD(sconn->smb1.searches.dirptrs, dptr);
542
543         DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
544                 dptr->dnum,path,expect_close));  
545
546         *dptr_ret = dptr;
547
548         return NT_STATUS_OK;
549 }
550
551
552 /****************************************************************************
553  Wrapper functions to access the lower level directory handles.
554 ****************************************************************************/
555
556 int dptr_CloseDir(struct dptr_struct *dptr)
557 {
558         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          * If user is a member of the Admin group
1130          * we never hide files from them.
1131          */
1132
1133         if (conn->admin_user) {
1134                 return True;
1135         }
1136
1137         return can_access_file_acl(conn, smb_fname, FILE_READ_DATA);
1138 }
1139
1140 /*******************************************************************
1141  Check to see if a user can write a file (and only files, we do not
1142  check dirs on this one). This is only approximate,
1143  it is used as part of the "hide unwriteable" option. Don't
1144  use it for anything security sensitive.
1145 ********************************************************************/
1146
1147 static bool user_can_write_file(connection_struct *conn,
1148                                 const struct smb_filename *smb_fname)
1149 {
1150         /*
1151          * If user is a member of the Admin group
1152          * we never hide files from them.
1153          */
1154
1155         if (conn->admin_user) {
1156                 return True;
1157         }
1158
1159         SMB_ASSERT(VALID_STAT(smb_fname->st));
1160
1161         /* Pseudo-open the file */
1162
1163         if(S_ISDIR(smb_fname->st.st_ex_mode)) {
1164                 return True;
1165         }
1166
1167         return can_write_to_file(conn, smb_fname);
1168 }
1169
1170 /*******************************************************************
1171   Is a file a "special" type ?
1172 ********************************************************************/
1173
1174 static bool file_is_special(connection_struct *conn,
1175                             const struct smb_filename *smb_fname)
1176 {
1177         /*
1178          * If user is a member of the Admin group
1179          * we never hide files from them.
1180          */
1181
1182         if (conn->admin_user)
1183                 return False;
1184
1185         SMB_ASSERT(VALID_STAT(smb_fname->st));
1186
1187         if (S_ISREG(smb_fname->st.st_ex_mode) ||
1188             S_ISDIR(smb_fname->st.st_ex_mode) ||
1189             S_ISLNK(smb_fname->st.st_ex_mode))
1190                 return False;
1191
1192         return True;
1193 }
1194
1195 /*******************************************************************
1196  Should the file be seen by the client?
1197  NOTE: A successful return is no guarantee of the file's existence.
1198 ********************************************************************/
1199
1200 bool is_visible_file(connection_struct *conn, const char *dir_path,
1201                      const char *name, SMB_STRUCT_STAT *pst, bool use_veto)
1202 {
1203         bool hide_unreadable = lp_hideunreadable(SNUM(conn));
1204         bool hide_unwriteable = lp_hideunwriteable_files(SNUM(conn));
1205         bool hide_special = lp_hide_special_files(SNUM(conn));
1206         char *entry = NULL;
1207         struct smb_filename *smb_fname_base = NULL;
1208         NTSTATUS status;
1209         bool ret = false;
1210
1211         if ((strcmp(".",name) == 0) || (strcmp("..",name) == 0)) {
1212                 return True; /* . and .. are always visible. */
1213         }
1214
1215         /* If it's a vetoed file, pretend it doesn't even exist */
1216         if (use_veto && IS_VETO_PATH(conn, name)) {
1217                 DEBUG(10,("is_visible_file: file %s is vetoed.\n", name ));
1218                 return False;
1219         }
1220
1221         if (hide_unreadable || hide_unwriteable || hide_special) {
1222                 entry = talloc_asprintf(talloc_tos(), "%s/%s", dir_path, name);
1223                 if (!entry) {
1224                         ret = false;
1225                         goto out;
1226                 }
1227
1228                 /* If it's a dfs symlink, ignore _hide xxxx_ options */
1229                 if (lp_host_msdfs() &&
1230                                 lp_msdfs_root(SNUM(conn)) &&
1231                                 is_msdfs_link(conn, entry, NULL)) {
1232                         ret = true;
1233                         goto out;
1234                 }
1235
1236                 /* Create an smb_filename with stream_name == NULL. */
1237                 status = create_synthetic_smb_fname(talloc_tos(), entry, NULL,
1238                                                     pst, &smb_fname_base);
1239                 if (!NT_STATUS_IS_OK(status)) {
1240                         ret = false;
1241                         goto out;
1242                 }
1243
1244                 /* If the file name does not exist, there's no point checking
1245                  * the configuration options. We succeed, on the basis that the
1246                  * checks *might* have passed if the file was present.
1247                  */
1248                 if (!VALID_STAT(*pst)) {
1249                         if (SMB_VFS_STAT(conn, smb_fname_base) != 0) {
1250                                 ret = true;
1251                                 goto out;
1252                         } else {
1253                                 *pst = smb_fname_base->st;
1254                         }
1255                 }
1256
1257                 /* Honour _hide unreadable_ option */
1258                 if (hide_unreadable &&
1259                     !user_can_read_file(conn, smb_fname_base)) {
1260                         DEBUG(10,("is_visible_file: file %s is unreadable.\n",
1261                                  entry ));
1262                         ret = false;
1263                         goto out;
1264                 }
1265                 /* Honour _hide unwriteable_ option */
1266                 if (hide_unwriteable && !user_can_write_file(conn,
1267                                                              smb_fname_base)) {
1268                         DEBUG(10,("is_visible_file: file %s is unwritable.\n",
1269                                  entry ));
1270                         ret = false;
1271                         goto out;
1272                 }
1273                 /* Honour _hide_special_ option */
1274                 if (hide_special && file_is_special(conn, smb_fname_base)) {
1275                         DEBUG(10,("is_visible_file: file %s is special.\n",
1276                                  entry ));
1277                         ret = false;
1278                         goto out;
1279                 }
1280         }
1281
1282         ret = true;
1283  out:
1284         TALLOC_FREE(smb_fname_base);
1285         TALLOC_FREE(entry);
1286         return ret;
1287 }
1288
1289 static int smb_Dir_destructor(struct smb_Dir *dirp)
1290 {
1291         if (dirp->dir) {
1292                 SMB_VFS_CLOSEDIR(dirp->conn,dirp->dir);
1293         }
1294         if (dirp->conn->sconn) {
1295                 dirp->conn->sconn->smb1.searches.dirhandles_open--;
1296         }
1297         return 0;
1298 }
1299
1300 /*******************************************************************
1301  Open a directory.
1302 ********************************************************************/
1303
1304 struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn,
1305                         const char *name, const char *mask, uint32 attr)
1306 {
1307         struct smb_Dir *dirp = TALLOC_ZERO_P(mem_ctx, struct smb_Dir);
1308         struct smbd_server_connection *sconn = conn->sconn;
1309
1310         if (!dirp) {
1311                 return NULL;
1312         }
1313
1314         dirp->conn = conn;
1315         dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
1316
1317         dirp->dir_path = talloc_strdup(dirp, name);
1318         if (!dirp->dir_path) {
1319                 errno = ENOMEM;
1320                 goto fail;
1321         }
1322
1323         if (sconn) {
1324                 sconn->smb1.searches.dirhandles_open++;
1325         }
1326         talloc_set_destructor(dirp, smb_Dir_destructor);
1327
1328         dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path, mask, attr);
1329         if (!dirp->dir) {
1330                 DEBUG(5,("OpenDir: Can't open %s. %s\n", dirp->dir_path,
1331                          strerror(errno) ));
1332                 goto fail;
1333         }
1334
1335         return dirp;
1336
1337   fail:
1338         TALLOC_FREE(dirp);
1339         return NULL;
1340 }
1341
1342 /*******************************************************************
1343  Read from a directory.
1344  Return directory entry, current offset, and optional stat information.
1345  Don't check for veto or invisible files.
1346 ********************************************************************/
1347
1348 const char *ReadDirName(struct smb_Dir *dirp, long *poffset,
1349                         SMB_STRUCT_STAT *sbuf, char **ptalloced)
1350 {
1351         const char *n;
1352         char *talloced = NULL;
1353         connection_struct *conn = dirp->conn;
1354
1355         /* Cheat to allow . and .. to be the first entries returned. */
1356         if (((*poffset == START_OF_DIRECTORY_OFFSET) ||
1357              (*poffset == DOT_DOT_DIRECTORY_OFFSET)) && (dirp->file_number < 2))
1358         {
1359                 if (dirp->file_number == 0) {
1360                         n = ".";
1361                         *poffset = dirp->offset = START_OF_DIRECTORY_OFFSET;
1362                 } else {
1363                         n = "..";
1364                         *poffset = dirp->offset = DOT_DOT_DIRECTORY_OFFSET;
1365                 }
1366                 dirp->file_number++;
1367                 *ptalloced = NULL;
1368                 return n;
1369         } else if (*poffset == END_OF_DIRECTORY_OFFSET) {
1370                 *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1371                 return NULL;
1372         } else {
1373                 /* A real offset, seek to it. */
1374                 SeekDir(dirp, *poffset);
1375         }
1376
1377         while ((n = vfs_readdirname(conn, dirp->dir, sbuf, &talloced))) {
1378                 /* Ignore . and .. - we've already returned them. */
1379                 if (*n == '.') {
1380                         if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) {
1381                                 TALLOC_FREE(talloced);
1382                                 continue;
1383                         }
1384                 }
1385                 *poffset = dirp->offset = SMB_VFS_TELLDIR(conn, dirp->dir);
1386                 *ptalloced = talloced;
1387                 dirp->file_number++;
1388                 return n;
1389         }
1390         *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1391         *ptalloced = NULL;
1392         return NULL;
1393 }
1394
1395 /*******************************************************************
1396  Rewind to the start.
1397 ********************************************************************/
1398
1399 void RewindDir(struct smb_Dir *dirp, long *poffset)
1400 {
1401         SMB_VFS_REWINDDIR(dirp->conn, dirp->dir);
1402         dirp->file_number = 0;
1403         dirp->offset = START_OF_DIRECTORY_OFFSET;
1404         *poffset = START_OF_DIRECTORY_OFFSET;
1405 }
1406
1407 /*******************************************************************
1408  Seek a dir.
1409 ********************************************************************/
1410
1411 void SeekDir(struct smb_Dir *dirp, long offset)
1412 {
1413         if (offset != dirp->offset) {
1414                 if (offset == START_OF_DIRECTORY_OFFSET) {
1415                         RewindDir(dirp, &offset);
1416                         /*
1417                          * Ok we should really set the file number here
1418                          * to 1 to enable ".." to be returned next. Trouble
1419                          * is I'm worried about callers using SeekDir(dirp,0)
1420                          * as equivalent to RewindDir(). So leave this alone
1421                          * for now.
1422                          */
1423                 } else if  (offset == DOT_DOT_DIRECTORY_OFFSET) {
1424                         RewindDir(dirp, &offset);
1425                         /*
1426                          * Set the file number to 2 - we want to get the first
1427                          * real file entry (the one we return after "..")
1428                          * on the next ReadDir.
1429                          */
1430                         dirp->file_number = 2;
1431                 } else if (offset == END_OF_DIRECTORY_OFFSET) {
1432                         ; /* Don't seek in this case. */
1433                 } else {
1434                         SMB_VFS_SEEKDIR(dirp->conn, dirp->dir, offset);
1435                 }
1436                 dirp->offset = offset;
1437         }
1438 }
1439
1440 /*******************************************************************
1441  Tell a dir position.
1442 ********************************************************************/
1443
1444 long TellDir(struct smb_Dir *dirp)
1445 {
1446         return(dirp->offset);
1447 }
1448
1449 /*******************************************************************
1450  Add an entry into the dcache.
1451 ********************************************************************/
1452
1453 void DirCacheAdd(struct smb_Dir *dirp, const char *name, long offset)
1454 {
1455         struct name_cache_entry *e;
1456
1457         if (dirp->name_cache_size == 0) {
1458                 return;
1459         }
1460
1461         if (dirp->name_cache == NULL) {
1462                 dirp->name_cache = TALLOC_ZERO_ARRAY(
1463                         dirp, struct name_cache_entry, dirp->name_cache_size);
1464
1465                 if (dirp->name_cache == NULL) {
1466                         return;
1467                 }
1468         }
1469
1470         dirp->name_cache_index = (dirp->name_cache_index+1) %
1471                                         dirp->name_cache_size;
1472         e = &dirp->name_cache[dirp->name_cache_index];
1473         TALLOC_FREE(e->name);
1474         e->name = talloc_strdup(dirp, name);
1475         e->offset = offset;
1476 }
1477
1478 /*******************************************************************
1479  Find an entry by name. Leave us at the offset after it.
1480  Don't check for veto or invisible files.
1481 ********************************************************************/
1482
1483 bool SearchDir(struct smb_Dir *dirp, const char *name, long *poffset)
1484 {
1485         int i;
1486         const char *entry = NULL;
1487         char *talloced = NULL;
1488         connection_struct *conn = dirp->conn;
1489
1490         /* Search back in the name cache. */
1491         if (dirp->name_cache_size && dirp->name_cache) {
1492                 for (i = dirp->name_cache_index; i >= 0; i--) {
1493                         struct name_cache_entry *e = &dirp->name_cache[i];
1494                         if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1495                                 *poffset = e->offset;
1496                                 SeekDir(dirp, e->offset);
1497                                 return True;
1498                         }
1499                 }
1500                 for (i = dirp->name_cache_size - 1; i > dirp->name_cache_index; i--) {
1501                         struct name_cache_entry *e = &dirp->name_cache[i];
1502                         if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1503                                 *poffset = e->offset;
1504                                 SeekDir(dirp, e->offset);
1505                                 return True;
1506                         }
1507                 }
1508         }
1509
1510         /* Not found in the name cache. Rewind directory and start from scratch. */
1511         SMB_VFS_REWINDDIR(conn, dirp->dir);
1512         dirp->file_number = 0;
1513         *poffset = START_OF_DIRECTORY_OFFSET;
1514         while ((entry = ReadDirName(dirp, poffset, NULL, &talloced))) {
1515                 if (conn->case_sensitive ? (strcmp(entry, name) == 0) : strequal(entry, name)) {
1516                         TALLOC_FREE(talloced);
1517                         return True;
1518                 }
1519                 TALLOC_FREE(talloced);
1520         }
1521         return False;
1522 }
1523
1524 /*****************************************************************
1525  Is this directory empty ?
1526 *****************************************************************/
1527
1528 NTSTATUS can_delete_directory(struct connection_struct *conn,
1529                                 const char *dirname)
1530 {
1531         NTSTATUS status = NT_STATUS_OK;
1532         long dirpos = 0;
1533         const char *dname = NULL;
1534         char *talloced = NULL;
1535         SMB_STRUCT_STAT st;
1536         struct smb_Dir *dir_hnd = OpenDir(talloc_tos(), conn, dirname,
1537                                           NULL, 0);
1538
1539         if (!dir_hnd) {
1540                 return map_nt_error_from_unix(errno);
1541         }
1542
1543         while ((dname = ReadDirName(dir_hnd, &dirpos, &st, &talloced))) {
1544                 /* Quick check for "." and ".." */
1545                 if (dname[0] == '.') {
1546                         if (!dname[1] || (dname[1] == '.' && !dname[2])) {
1547                                 TALLOC_FREE(talloced);
1548                                 continue;
1549                         }
1550                 }
1551
1552                 if (!is_visible_file(conn, dirname, dname, &st, True)) {
1553                         TALLOC_FREE(talloced);
1554                         continue;
1555                 }
1556
1557                 DEBUG(10,("can_delete_directory: got name %s - can't delete\n",
1558                          dname ));
1559                 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
1560                 break;
1561         }
1562         TALLOC_FREE(talloced);
1563         TALLOC_FREE(dir_hnd);
1564
1565         return status;
1566 }