Remove more uses of "extern struct current_user current_user;".
[kai/samba-autobuild/.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          * Use (uid_t)0 here not sec_initial_uid()
1133          * because of the RAW-SAMBA3HIDE test.
1134          */
1135
1136         if (get_current_uid(conn) == (uid_t)0) {
1137                 return True;
1138         }
1139
1140         return can_access_file_acl(conn, smb_fname, FILE_READ_DATA);
1141 }
1142
1143 /*******************************************************************
1144  Check to see if a user can write a file (and only files, we do not
1145  check dirs on this one). This is only approximate,
1146  it is used as part of the "hide unwriteable" option. Don't
1147  use it for anything security sensitive.
1148 ********************************************************************/
1149
1150 static bool user_can_write_file(connection_struct *conn,
1151                                 const struct smb_filename *smb_fname)
1152 {
1153         /*
1154          * If user is a member of the Admin group
1155          * we never hide files from them.
1156          * Use (uid_t)0 here not sec_initial_uid()
1157          * because of the RAW-SAMBA3HIDE test.
1158          */
1159
1160         if (get_current_uid(conn) == (uid_t)0) {
1161                 return True;
1162         }
1163
1164         SMB_ASSERT(VALID_STAT(smb_fname->st));
1165
1166         /* Pseudo-open the file */
1167
1168         if(S_ISDIR(smb_fname->st.st_ex_mode)) {
1169                 return True;
1170         }
1171
1172         return can_write_to_file(conn, smb_fname);
1173 }
1174
1175 /*******************************************************************
1176   Is a file a "special" type ?
1177 ********************************************************************/
1178
1179 static bool file_is_special(connection_struct *conn,
1180                             const struct smb_filename *smb_fname)
1181 {
1182         /*
1183          * If user is a member of the Admin group
1184          * we never hide files from them.
1185          * Use (uid_t)0 here not sec_initial_uid()
1186          * because of the RAW-SAMBA3HIDE test.
1187          */
1188
1189         if (get_current_uid(conn) == (uid_t)0) {
1190                 return False;
1191         }
1192
1193         SMB_ASSERT(VALID_STAT(smb_fname->st));
1194
1195         if (S_ISREG(smb_fname->st.st_ex_mode) ||
1196             S_ISDIR(smb_fname->st.st_ex_mode) ||
1197             S_ISLNK(smb_fname->st.st_ex_mode))
1198                 return False;
1199
1200         return True;
1201 }
1202
1203 /*******************************************************************
1204  Should the file be seen by the client?
1205  NOTE: A successful return is no guarantee of the file's existence.
1206 ********************************************************************/
1207
1208 bool is_visible_file(connection_struct *conn, const char *dir_path,
1209                      const char *name, SMB_STRUCT_STAT *pst, bool use_veto)
1210 {
1211         bool hide_unreadable = lp_hideunreadable(SNUM(conn));
1212         bool hide_unwriteable = lp_hideunwriteable_files(SNUM(conn));
1213         bool hide_special = lp_hide_special_files(SNUM(conn));
1214         char *entry = NULL;
1215         struct smb_filename *smb_fname_base = NULL;
1216         NTSTATUS status;
1217         bool ret = false;
1218
1219         if ((strcmp(".",name) == 0) || (strcmp("..",name) == 0)) {
1220                 return True; /* . and .. are always visible. */
1221         }
1222
1223         /* If it's a vetoed file, pretend it doesn't even exist */
1224         if (use_veto && IS_VETO_PATH(conn, name)) {
1225                 DEBUG(10,("is_visible_file: file %s is vetoed.\n", name ));
1226                 return False;
1227         }
1228
1229         if (hide_unreadable || hide_unwriteable || hide_special) {
1230                 entry = talloc_asprintf(talloc_tos(), "%s/%s", dir_path, name);
1231                 if (!entry) {
1232                         ret = false;
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 }