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