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