e6f431eb33ed8da4f2a57906e4d439f6ea487f2a
[metze/samba/wip.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         SAFE_FREE(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         dptr->path = SMB_STRDUP(path);
538         if (!dptr->path) {
539                 bitmap_clear(sconn->searches.dptr_bmap, dptr->dnum - 1);
540                 SAFE_FREE(dptr);
541                 TALLOC_FREE(dir_hnd);
542                 return NT_STATUS_NO_MEMORY;
543         }
544         dptr->conn = conn;
545         dptr->dir_hnd = dir_hnd;
546         dptr->spid = spid;
547         dptr->expect_close = expect_close;
548         dptr->wcard = SMB_STRDUP(wcard);
549         if (!dptr->wcard) {
550                 bitmap_clear(sconn->searches.dptr_bmap, dptr->dnum - 1);
551                 SAFE_FREE(dptr->path);
552                 SAFE_FREE(dptr);
553                 TALLOC_FREE(dir_hnd);
554                 return NT_STATUS_NO_MEMORY;
555         }
556         if (lp_posix_pathnames() || (wcard[0] == '.' && wcard[1] == 0)) {
557                 dptr->has_wild = True;
558         } else {
559                 dptr->has_wild = wcard_has_wild;
560         }
561
562         dptr->attr = attr;
563
564         DLIST_ADD(sconn->searches.dirptrs, dptr);
565
566         DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
567                 dptr->dnum,path,expect_close));  
568
569         *dptr_ret = dptr;
570
571         return NT_STATUS_OK;
572 }
573
574
575 /****************************************************************************
576  Wrapper functions to access the lower level directory handles.
577 ****************************************************************************/
578
579 void dptr_CloseDir(files_struct *fsp)
580 {
581         if (fsp->dptr) {
582 /*
583  * Ugly hack. We have defined fdopendir to return ENOSYS if dirfd also isn't
584  * present. I hate Solaris. JRA.
585  */
586 #ifdef HAVE_DIRFD
587                 if (fsp->fh->fd != -1 &&
588                                 fsp->dptr->dir_hnd &&
589                                 dirfd(fsp->dptr->dir_hnd->dir)) {
590                         /* The call below closes the underlying fd. */
591                         fsp->fh->fd = -1;
592                 }
593 #endif
594                 dptr_close_internal(fsp->dptr);
595                 fsp->dptr = NULL;
596         }
597 }
598
599 void dptr_SeekDir(struct dptr_struct *dptr, long offset)
600 {
601         SeekDir(dptr->dir_hnd, offset);
602 }
603
604 long dptr_TellDir(struct dptr_struct *dptr)
605 {
606         return TellDir(dptr->dir_hnd);
607 }
608
609 bool dptr_has_wild(struct dptr_struct *dptr)
610 {
611         return dptr->has_wild;
612 }
613
614 int dptr_dnum(struct dptr_struct *dptr)
615 {
616         return dptr->dnum;
617 }
618
619 /****************************************************************************
620  Return the next visible file name, skipping veto'd and invisible files.
621 ****************************************************************************/
622
623 static const char *dptr_normal_ReadDirName(struct dptr_struct *dptr,
624                                            long *poffset, SMB_STRUCT_STAT *pst,
625                                            char **ptalloced)
626 {
627         /* Normal search for the next file. */
628         const char *name;
629         char *talloced = NULL;
630
631         while ((name = ReadDirName(dptr->dir_hnd, poffset, pst, &talloced))
632                != NULL) {
633                 if (is_visible_file(dptr->conn, dptr->path, name, pst, True)) {
634                         *ptalloced = talloced;
635                         return name;
636                 }
637                 TALLOC_FREE(talloced);
638         }
639         return NULL;
640 }
641
642 /****************************************************************************
643  Return the next visible file name, skipping veto'd and invisible files.
644 ****************************************************************************/
645
646 char *dptr_ReadDirName(TALLOC_CTX *ctx,
647                         struct dptr_struct *dptr,
648                         long *poffset,
649                         SMB_STRUCT_STAT *pst)
650 {
651         struct smb_filename smb_fname_base;
652         char *name = NULL;
653         const char *name_temp = NULL;
654         char *talloced = NULL;
655         char *pathreal = NULL;
656         char *found_name = NULL;
657         int ret;
658
659         SET_STAT_INVALID(*pst);
660
661         if (dptr->has_wild || dptr->did_stat) {
662                 name_temp = dptr_normal_ReadDirName(dptr, poffset, pst,
663                                                     &talloced);
664                 if (name_temp == NULL) {
665                         return NULL;
666                 }
667                 if (talloced != NULL) {
668                         return talloc_move(ctx, &talloced);
669                 }
670                 return talloc_strdup(ctx, name_temp);
671         }
672
673         /* If poffset is -1 then we know we returned this name before and we
674          * have no wildcards. We're at the end of the directory. */
675         if (*poffset == END_OF_DIRECTORY_OFFSET) {
676                 return NULL;
677         }
678
679         /* We know the stored wcard contains no wildcard characters.
680          * See if we can match with a stat call. If we can't, then set
681          * did_stat to true to ensure we only do this once and keep
682          * searching. */
683
684         dptr->did_stat = true;
685
686         /* First check if it should be visible. */
687         if (!is_visible_file(dptr->conn, dptr->path, dptr->wcard,
688             pst, true))
689         {
690                 /* This only returns false if the file was found, but
691                    is explicitly not visible. Set us to end of
692                    directory, but return NULL as we know we can't ever
693                    find it. */
694                 goto ret;
695         }
696
697         if (VALID_STAT(*pst)) {
698                 name = talloc_strdup(ctx, dptr->wcard);
699                 goto ret;
700         }
701
702         pathreal = talloc_asprintf(ctx,
703                                 "%s/%s",
704                                 dptr->path,
705                                 dptr->wcard);
706         if (!pathreal)
707                 return NULL;
708
709         /* Create an smb_filename with stream_name == NULL. */
710         ZERO_STRUCT(smb_fname_base);
711         smb_fname_base.base_name = pathreal;
712
713         if (SMB_VFS_STAT(dptr->conn, &smb_fname_base) == 0) {
714                 *pst = smb_fname_base.st;
715                 name = talloc_strdup(ctx, dptr->wcard);
716                 goto clean;
717         } else {
718                 /* If we get any other error than ENOENT or ENOTDIR
719                    then the file exists we just can't stat it. */
720                 if (errno != ENOENT && errno != ENOTDIR) {
721                         name = talloc_strdup(ctx, dptr->wcard);
722                         goto clean;
723                 }
724         }
725
726         /* Stat failed. We know this is authoratiative if we are
727          * providing case sensitive semantics or the underlying
728          * filesystem is case sensitive.
729          */
730         if (dptr->conn->case_sensitive ||
731             !(dptr->conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH))
732         {
733                 goto clean;
734         }
735
736         /*
737          * Try case-insensitive stat if the fs has the ability. This avoids
738          * scanning the whole directory.
739          */
740         ret = SMB_VFS_GET_REAL_FILENAME(dptr->conn, dptr->path, dptr->wcard,
741                                         ctx, &found_name);
742         if (ret == 0) {
743                 name = found_name;
744                 goto clean;
745         } else if (errno == ENOENT) {
746                 /* The case-insensitive lookup was authoritative. */
747                 goto clean;
748         }
749
750         TALLOC_FREE(pathreal);
751
752         name_temp = dptr_normal_ReadDirName(dptr, poffset, pst, &talloced);
753         if (name_temp == NULL) {
754                 return NULL;
755         }
756         if (talloced != NULL) {
757                 return talloc_move(ctx, &talloced);
758         }
759         return talloc_strdup(ctx, name_temp);
760
761 clean:
762         TALLOC_FREE(pathreal);
763 ret:
764         /* We need to set the underlying dir_hnd offset to -1
765          * also as this function is usually called with the
766          * output from TellDir. */
767         dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
768         return name;
769 }
770
771 /****************************************************************************
772  Search for a file by name, skipping veto'ed and not visible files.
773 ****************************************************************************/
774
775 bool dptr_SearchDir(struct dptr_struct *dptr, const char *name, long *poffset, SMB_STRUCT_STAT *pst)
776 {
777         SET_STAT_INVALID(*pst);
778
779         if (!dptr->has_wild && (dptr->dir_hnd->offset == END_OF_DIRECTORY_OFFSET)) {
780                 /* This is a singleton directory and we're already at the end. */
781                 *poffset = END_OF_DIRECTORY_OFFSET;
782                 return False;
783         }
784
785         return SearchDir(dptr->dir_hnd, name, poffset);
786 }
787
788 /****************************************************************************
789  Add the name we're returning into the underlying cache.
790 ****************************************************************************/
791
792 void dptr_DirCacheAdd(struct dptr_struct *dptr, const char *name, long offset)
793 {
794         DirCacheAdd(dptr->dir_hnd, name, offset);
795 }
796
797 /****************************************************************************
798  Initialize variables & state data at the beginning of all search SMB requests.
799 ****************************************************************************/
800 void dptr_init_search_op(struct dptr_struct *dptr)
801 {
802         SMB_VFS_INIT_SEARCH_OP(dptr->conn, dptr->dir_hnd->dir);
803 }
804
805 /****************************************************************************
806  Fill the 5 byte server reserved dptr field.
807 ****************************************************************************/
808
809 bool dptr_fill(struct smbd_server_connection *sconn,
810                char *buf1,unsigned int key)
811 {
812         unsigned char *buf = (unsigned char *)buf1;
813         struct dptr_struct *dptr = dptr_get(sconn, key, false);
814         uint32 offset;
815         if (!dptr) {
816                 DEBUG(1,("filling null dirptr %d\n",key));
817                 return(False);
818         }
819         offset = (uint32)TellDir(dptr->dir_hnd);
820         DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key,
821                 (long)dptr->dir_hnd,(int)offset));
822         buf[0] = key;
823         SIVAL(buf,1,offset);
824         return(True);
825 }
826
827 /****************************************************************************
828  Fetch the dir ptr and seek it given the 5 byte server field.
829 ****************************************************************************/
830
831 struct dptr_struct *dptr_fetch(struct smbd_server_connection *sconn,
832                                char *buf, int *num)
833 {
834         unsigned int key = *(unsigned char *)buf;
835         struct dptr_struct *dptr = dptr_get(sconn, key, false);
836         uint32 offset;
837         long seekoff;
838
839         if (!dptr) {
840                 DEBUG(3,("fetched null dirptr %d\n",key));
841                 return(NULL);
842         }
843         *num = key;
844         offset = IVAL(buf,1);
845         if (offset == (uint32)-1) {
846                 seekoff = END_OF_DIRECTORY_OFFSET;
847         } else {
848                 seekoff = (long)offset;
849         }
850         SeekDir(dptr->dir_hnd,seekoff);
851         DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
852                 key, dptr->path, (int)seekoff));
853         return(dptr);
854 }
855
856 /****************************************************************************
857  Fetch the dir ptr.
858 ****************************************************************************/
859
860 struct dptr_struct *dptr_fetch_lanman2(struct smbd_server_connection *sconn,
861                                        int dptr_num)
862 {
863         struct dptr_struct *dptr  = dptr_get(sconn, dptr_num, false);
864
865         if (!dptr) {
866                 DEBUG(3,("fetched null dirptr %d\n",dptr_num));
867                 return(NULL);
868         }
869         DEBUG(3,("fetching dirptr %d for path %s\n",dptr_num,dptr->path));
870         return(dptr);
871 }
872
873 /****************************************************************************
874  Check that a file matches a particular file type.
875 ****************************************************************************/
876
877 bool dir_check_ftype(connection_struct *conn, uint32 mode, uint32 dirtype)
878 {
879         uint32 mask;
880
881         /* Check the "may have" search bits. */
882         if (((mode & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY)) != 0)
883                 return False;
884
885         /* Check the "must have" bits, which are the may have bits shifted eight */
886         /* If must have bit is set, the file/dir can not be returned in search unless the matching
887                 file attribute is set */
888         mask = ((dirtype >> 8) & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)); /* & 0x37 */
889         if(mask) {
890                 if((mask & (mode & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM))) == mask)   /* check if matching attribute present */
891                         return True;
892                 else
893                         return False;
894         }
895
896         return True;
897 }
898
899 static bool mangle_mask_match(connection_struct *conn,
900                 const char *filename,
901                 const char *mask)
902 {
903         char mname[13];
904
905         if (!name_to_8_3(filename,mname,False,conn->params)) {
906                 return False;
907         }
908         return mask_match_search(mname,mask,False);
909 }
910
911 bool smbd_dirptr_get_entry(TALLOC_CTX *ctx,
912                            struct dptr_struct *dirptr,
913                            const char *mask,
914                            uint32_t dirtype,
915                            bool dont_descend,
916                            bool ask_sharemode,
917                            bool (*match_fn)(TALLOC_CTX *ctx,
918                                             void *private_data,
919                                             const char *dname,
920                                             const char *mask,
921                                             char **_fname),
922                            bool (*mode_fn)(TALLOC_CTX *ctx,
923                                            void *private_data,
924                                            struct smb_filename *smb_fname,
925                                            uint32_t *_mode),
926                            void *private_data,
927                            char **_fname,
928                            struct smb_filename **_smb_fname,
929                            uint32_t *_mode,
930                            long *_prev_offset)
931 {
932         connection_struct *conn = dirptr->conn;
933         bool needslash;
934
935         *_smb_fname = NULL;
936         *_mode = 0;
937
938         needslash = ( dirptr->path[strlen(dirptr->path) -1] != '/');
939
940         while (true) {
941                 long cur_offset;
942                 long prev_offset;
943                 SMB_STRUCT_STAT sbuf;
944                 char *dname = NULL;
945                 bool isdots;
946                 char *fname = NULL;
947                 char *pathreal = NULL;
948                 struct smb_filename smb_fname;
949                 uint32_t mode = 0;
950                 bool ok;
951                 NTSTATUS status;
952
953                 cur_offset = dptr_TellDir(dirptr);
954                 prev_offset = cur_offset;
955                 dname = dptr_ReadDirName(ctx, dirptr, &cur_offset, &sbuf);
956
957                 DEBUG(6,("smbd_dirptr_get_entry: dirptr 0x%lx now at offset %ld\n",
958                         (long)dirptr, cur_offset));
959
960                 if (dname == NULL) {
961                         return false;
962                 }
963
964                 isdots = (ISDOT(dname) || ISDOTDOT(dname));
965                 if (dont_descend && !isdots) {
966                         TALLOC_FREE(dname);
967                         continue;
968                 }
969
970                 /*
971                  * fname may get mangled, dname is never mangled.
972                  * Whenever we're accessing the filesystem we use
973                  * pathreal which is composed from dname.
974                  */
975
976                 ok = match_fn(ctx, private_data, dname, mask, &fname);
977                 if (!ok) {
978                         TALLOC_FREE(dname);
979                         continue;
980                 }
981
982                 pathreal = talloc_asprintf(ctx, "%s%s%s",
983                                            dirptr->path,
984                                            needslash?"/":"",
985                                            dname);
986                 if (!pathreal) {
987                         TALLOC_FREE(dname);
988                         TALLOC_FREE(fname);
989                         return false;
990                 }
991
992                 /* Create smb_fname with NULL stream_name. */
993                 ZERO_STRUCT(smb_fname);
994                 smb_fname.base_name = pathreal;
995                 smb_fname.st = sbuf;
996
997                 ok = mode_fn(ctx, private_data, &smb_fname, &mode);
998                 if (!ok) {
999                         TALLOC_FREE(dname);
1000                         TALLOC_FREE(fname);
1001                         TALLOC_FREE(pathreal);
1002                         continue;
1003                 }
1004
1005                 if (!dir_check_ftype(conn, mode, dirtype)) {
1006                         DEBUG(5,("[%s] attribs 0x%x didn't match 0x%x\n",
1007                                 fname, (unsigned int)mode, (unsigned int)dirtype));
1008                         TALLOC_FREE(dname);
1009                         TALLOC_FREE(fname);
1010                         TALLOC_FREE(pathreal);
1011                         continue;
1012                 }
1013
1014                 if (ask_sharemode) {
1015                         struct timespec write_time_ts;
1016                         struct file_id fileid;
1017
1018                         fileid = vfs_file_id_from_sbuf(conn,
1019                                                        &smb_fname.st);
1020                         get_file_infos(fileid, 0, NULL, &write_time_ts);
1021                         if (!null_timespec(write_time_ts)) {
1022                                 update_stat_ex_mtime(&smb_fname.st,
1023                                                      write_time_ts);
1024                         }
1025                 }
1026
1027                 DEBUG(3,("smbd_dirptr_get_entry mask=[%s] found %s "
1028                         "fname=%s (%s)\n",
1029                         mask, smb_fname_str_dbg(&smb_fname),
1030                         dname, fname));
1031
1032                 DirCacheAdd(dirptr->dir_hnd, dname, cur_offset);
1033
1034                 TALLOC_FREE(dname);
1035
1036                 status = copy_smb_filename(ctx, &smb_fname, _smb_fname);
1037                 TALLOC_FREE(pathreal);
1038                 if (!NT_STATUS_IS_OK(status)) {
1039                         return false;
1040                 }
1041                 *_fname = fname;
1042                 *_mode = mode;
1043                 *_prev_offset = prev_offset;
1044
1045                 return true;
1046         }
1047
1048         return false;
1049 }
1050
1051 /****************************************************************************
1052  Get an 8.3 directory entry.
1053 ****************************************************************************/
1054
1055 static bool smbd_dirptr_8_3_match_fn(TALLOC_CTX *ctx,
1056                                      void *private_data,
1057                                      const char *dname,
1058                                      const char *mask,
1059                                      char **_fname)
1060 {
1061         connection_struct *conn = (connection_struct *)private_data;
1062
1063         if ((strcmp(mask,"*.*") == 0) ||
1064             mask_match_search(dname, mask, false) ||
1065             mangle_mask_match(conn, dname, mask)) {
1066                 char mname[13];
1067                 const char *fname;
1068
1069                 if (!mangle_is_8_3(dname, false, conn->params)) {
1070                         bool ok = name_to_8_3(dname, mname, false,
1071                                               conn->params);
1072                         if (!ok) {
1073                                 return false;
1074                         }
1075                         fname = mname;
1076                 } else {
1077                         fname = dname;
1078                 }
1079
1080                 *_fname = talloc_strdup(ctx, fname);
1081                 if (*_fname == NULL) {
1082                         return false;
1083                 }
1084
1085                 return true;
1086         }
1087
1088         return false;
1089 }
1090
1091 static bool smbd_dirptr_8_3_mode_fn(TALLOC_CTX *ctx,
1092                                     void *private_data,
1093                                     struct smb_filename *smb_fname,
1094                                     uint32_t *_mode)
1095 {
1096         connection_struct *conn = (connection_struct *)private_data;
1097
1098         if (!VALID_STAT(smb_fname->st)) {
1099                 if ((SMB_VFS_STAT(conn, smb_fname)) != 0) {
1100                         DEBUG(5,("smbd_dirptr_8_3_mode_fn: "
1101                                  "Couldn't stat [%s]. Error "
1102                                  "= %s\n",
1103                                  smb_fname_str_dbg(smb_fname),
1104                                  strerror(errno)));
1105                         return false;
1106                 }
1107         }
1108
1109         *_mode = dos_mode(conn, smb_fname);
1110         return true;
1111 }
1112
1113 bool get_dir_entry(TALLOC_CTX *ctx,
1114                 struct dptr_struct *dirptr,
1115                 const char *mask,
1116                 uint32_t dirtype,
1117                 char **_fname,
1118                 SMB_OFF_T *_size,
1119                 uint32_t *_mode,
1120                 struct timespec *_date,
1121                 bool check_descend,
1122                 bool ask_sharemode)
1123 {
1124         connection_struct *conn = dirptr->conn;
1125         char *fname = NULL;
1126         struct smb_filename *smb_fname = NULL;
1127         uint32_t mode = 0;
1128         long prev_offset;
1129         bool ok;
1130
1131         ok = smbd_dirptr_get_entry(ctx,
1132                                    dirptr,
1133                                    mask,
1134                                    dirtype,
1135                                    check_descend,
1136                                    ask_sharemode,
1137                                    smbd_dirptr_8_3_match_fn,
1138                                    smbd_dirptr_8_3_mode_fn,
1139                                    conn,
1140                                    &fname,
1141                                    &smb_fname,
1142                                    &mode,
1143                                    &prev_offset);
1144         if (!ok) {
1145                 return false;
1146         }
1147
1148         *_fname = talloc_move(ctx, &fname);
1149         *_size = smb_fname->st.st_ex_size;
1150         *_mode = mode;
1151         *_date = smb_fname->st.st_ex_mtime;
1152         TALLOC_FREE(smb_fname);
1153         return true;
1154 }
1155
1156 /*******************************************************************
1157  Check to see if a user can read a file. This is only approximate,
1158  it is used as part of the "hide unreadable" option. Don't
1159  use it for anything security sensitive.
1160 ********************************************************************/
1161
1162 static bool user_can_read_file(connection_struct *conn,
1163                                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         return can_access_file_acl(conn, smb_fname, FILE_READ_DATA);
1176 }
1177
1178 /*******************************************************************
1179  Check to see if a user can write a file (and only files, we do not
1180  check dirs on this one). This is only approximate,
1181  it is used as part of the "hide unwriteable" option. Don't
1182  use it for anything security sensitive.
1183 ********************************************************************/
1184
1185 static bool user_can_write_file(connection_struct *conn,
1186                                 const struct smb_filename *smb_fname)
1187 {
1188         /*
1189          * Never hide files from the root user.
1190          * We use (uid_t)0 here not sec_initial_uid()
1191          * as make test uses a single user context.
1192          */
1193
1194         if (get_current_uid(conn) == (uid_t)0) {
1195                 return True;
1196         }
1197
1198         SMB_ASSERT(VALID_STAT(smb_fname->st));
1199
1200         /* Pseudo-open the file */
1201
1202         if(S_ISDIR(smb_fname->st.st_ex_mode)) {
1203                 return True;
1204         }
1205
1206         return can_write_to_file(conn, smb_fname);
1207 }
1208
1209 /*******************************************************************
1210   Is a file a "special" type ?
1211 ********************************************************************/
1212
1213 static bool file_is_special(connection_struct *conn,
1214                             const struct smb_filename *smb_fname)
1215 {
1216         /*
1217          * Never hide files from the root user.
1218          * We use (uid_t)0 here not sec_initial_uid()
1219          * as make test uses a single user context.
1220          */
1221
1222         if (get_current_uid(conn) == (uid_t)0) {
1223                 return False;
1224         }
1225
1226         SMB_ASSERT(VALID_STAT(smb_fname->st));
1227
1228         if (S_ISREG(smb_fname->st.st_ex_mode) ||
1229             S_ISDIR(smb_fname->st.st_ex_mode) ||
1230             S_ISLNK(smb_fname->st.st_ex_mode))
1231                 return False;
1232
1233         return True;
1234 }
1235
1236 /*******************************************************************
1237  Should the file be seen by the client?
1238  NOTE: A successful return is no guarantee of the file's existence.
1239 ********************************************************************/
1240
1241 bool is_visible_file(connection_struct *conn, const char *dir_path,
1242                      const char *name, SMB_STRUCT_STAT *pst, bool use_veto)
1243 {
1244         bool hide_unreadable = lp_hideunreadable(SNUM(conn));
1245         bool hide_unwriteable = lp_hideunwriteable_files(SNUM(conn));
1246         bool hide_special = lp_hide_special_files(SNUM(conn));
1247         char *entry = NULL;
1248         struct smb_filename *smb_fname_base = NULL;
1249         NTSTATUS status;
1250         bool ret = false;
1251
1252         if ((strcmp(".",name) == 0) || (strcmp("..",name) == 0)) {
1253                 return True; /* . and .. are always visible. */
1254         }
1255
1256         /* If it's a vetoed file, pretend it doesn't even exist */
1257         if (use_veto && IS_VETO_PATH(conn, name)) {
1258                 DEBUG(10,("is_visible_file: file %s is vetoed.\n", name ));
1259                 return False;
1260         }
1261
1262         if (hide_unreadable || hide_unwriteable || hide_special) {
1263                 entry = talloc_asprintf(talloc_tos(), "%s/%s", dir_path, name);
1264                 if (!entry) {
1265                         ret = false;
1266                         goto out;
1267                 }
1268
1269                 /* Create an smb_filename with stream_name == NULL. */
1270                 status = create_synthetic_smb_fname(talloc_tos(), entry, NULL,
1271                                                     pst, &smb_fname_base);
1272                 if (!NT_STATUS_IS_OK(status)) {
1273                         ret = false;
1274                         goto out;
1275                 }
1276
1277                 /* If the file name does not exist, there's no point checking
1278                  * the configuration options. We succeed, on the basis that the
1279                  * checks *might* have passed if the file was present.
1280                  */
1281                 if (!VALID_STAT(*pst)) {
1282                         if (SMB_VFS_STAT(conn, smb_fname_base) != 0) {
1283                                 ret = true;
1284                                 goto out;
1285                         } else {
1286                                 *pst = smb_fname_base->st;
1287                         }
1288                 }
1289
1290                 /* Honour _hide unreadable_ option */
1291                 if (hide_unreadable &&
1292                     !user_can_read_file(conn, smb_fname_base)) {
1293                         DEBUG(10,("is_visible_file: file %s is unreadable.\n",
1294                                  entry ));
1295                         ret = false;
1296                         goto out;
1297                 }
1298                 /* Honour _hide unwriteable_ option */
1299                 if (hide_unwriteable && !user_can_write_file(conn,
1300                                                              smb_fname_base)) {
1301                         DEBUG(10,("is_visible_file: file %s is unwritable.\n",
1302                                  entry ));
1303                         ret = false;
1304                         goto out;
1305                 }
1306                 /* Honour _hide_special_ option */
1307                 if (hide_special && file_is_special(conn, smb_fname_base)) {
1308                         DEBUG(10,("is_visible_file: file %s is special.\n",
1309                                  entry ));
1310                         ret = false;
1311                         goto out;
1312                 }
1313         }
1314
1315         ret = true;
1316  out:
1317         TALLOC_FREE(smb_fname_base);
1318         TALLOC_FREE(entry);
1319         return ret;
1320 }
1321
1322 static int smb_Dir_destructor(struct smb_Dir *dirp)
1323 {
1324         if (dirp->dir) {
1325 #ifdef HAVE_DIRFD
1326                 if (dirp->conn->sconn) {
1327                         files_struct *fsp = file_find_fd(dirp->conn->sconn,
1328                                                 dirfd(dirp->dir));
1329                         if (fsp) {
1330                                 /* The call below closes the underlying fd. */
1331                                 fsp->fh->fd = -1;
1332                         }
1333                 }
1334 #endif
1335                 SMB_VFS_CLOSEDIR(dirp->conn,dirp->dir);
1336         }
1337         if (dirp->conn->sconn) {
1338                 dirp->conn->sconn->searches.dirhandles_open--;
1339         }
1340         return 0;
1341 }
1342
1343 /*******************************************************************
1344  Open a directory.
1345 ********************************************************************/
1346
1347 struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn,
1348                         const char *name,
1349                         const char *mask,
1350                         uint32 attr)
1351 {
1352         struct smb_Dir *dirp = TALLOC_ZERO_P(mem_ctx, struct smb_Dir);
1353         struct smbd_server_connection *sconn = conn->sconn;
1354
1355         if (!dirp) {
1356                 return NULL;
1357         }
1358
1359         dirp->conn = conn;
1360         dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
1361
1362         dirp->dir_path = talloc_strdup(dirp, name);
1363         if (!dirp->dir_path) {
1364                 errno = ENOMEM;
1365                 goto fail;
1366         }
1367
1368         if (sconn) {
1369                 sconn->searches.dirhandles_open++;
1370         }
1371         talloc_set_destructor(dirp, smb_Dir_destructor);
1372
1373         dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path, mask, attr);
1374         if (!dirp->dir) {
1375                 DEBUG(5,("OpenDir: Can't open %s. %s\n", dirp->dir_path,
1376                          strerror(errno) ));
1377                 goto fail;
1378         }
1379
1380         return dirp;
1381
1382   fail:
1383         TALLOC_FREE(dirp);
1384         return NULL;
1385 }
1386
1387 /*******************************************************************
1388  Open a directory from an fsp.
1389 ********************************************************************/
1390
1391 static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn,
1392                         files_struct *fsp,
1393                         const char *mask,
1394                         uint32 attr)
1395 {
1396         struct smb_Dir *dirp = TALLOC_ZERO_P(mem_ctx, struct smb_Dir);
1397         struct smbd_server_connection *sconn = conn->sconn;
1398
1399         if (!dirp) {
1400                 return NULL;
1401         }
1402
1403         dirp->conn = conn;
1404         dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
1405
1406         dirp->dir_path = talloc_strdup(dirp, fsp->fsp_name->base_name);
1407         if (!dirp->dir_path) {
1408                 errno = ENOMEM;
1409                 goto fail;
1410         }
1411
1412         if (sconn) {
1413                 sconn->searches.dirhandles_open++;
1414         }
1415         talloc_set_destructor(dirp, smb_Dir_destructor);
1416
1417         if (fsp->is_directory && fsp->fh->fd != -1) {
1418                 dirp->dir = SMB_VFS_FDOPENDIR(fsp, mask, attr);
1419                 if (dirp->dir == NULL) {
1420                         DEBUG(10,("OpenDir_fsp: SMB_VFS_FDOPENDIR on %s returned "
1421                                 "NULL (%s)\n",
1422                                 dirp->dir_path,
1423                                 strerror(errno)));
1424                         if (errno != ENOSYS) {
1425                                 return NULL;
1426                         }
1427                 }
1428         }
1429
1430         if (dirp->dir == NULL) {
1431                 /* FDOPENDIR didn't work. Use OPENDIR instead. */
1432                 dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path, mask, attr);
1433         }
1434
1435         if (!dirp->dir) {
1436                 DEBUG(5,("OpenDir_fsp: Can't open %s. %s\n", dirp->dir_path,
1437                          strerror(errno) ));
1438                 goto fail;
1439         }
1440
1441         return dirp;
1442
1443   fail:
1444         TALLOC_FREE(dirp);
1445         return NULL;
1446 }
1447
1448
1449 /*******************************************************************
1450  Read from a directory.
1451  Return directory entry, current offset, and optional stat information.
1452  Don't check for veto or invisible files.
1453 ********************************************************************/
1454
1455 const char *ReadDirName(struct smb_Dir *dirp, long *poffset,
1456                         SMB_STRUCT_STAT *sbuf, char **ptalloced)
1457 {
1458         const char *n;
1459         char *talloced = NULL;
1460         connection_struct *conn = dirp->conn;
1461
1462         /* Cheat to allow . and .. to be the first entries returned. */
1463         if (((*poffset == START_OF_DIRECTORY_OFFSET) ||
1464              (*poffset == DOT_DOT_DIRECTORY_OFFSET)) && (dirp->file_number < 2))
1465         {
1466                 if (dirp->file_number == 0) {
1467                         n = ".";
1468                         *poffset = dirp->offset = START_OF_DIRECTORY_OFFSET;
1469                 } else {
1470                         n = "..";
1471                         *poffset = dirp->offset = DOT_DOT_DIRECTORY_OFFSET;
1472                 }
1473                 dirp->file_number++;
1474                 *ptalloced = NULL;
1475                 return n;
1476         } else if (*poffset == END_OF_DIRECTORY_OFFSET) {
1477                 *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1478                 return NULL;
1479         } else {
1480                 /* A real offset, seek to it. */
1481                 SeekDir(dirp, *poffset);
1482         }
1483
1484         while ((n = vfs_readdirname(conn, dirp->dir, sbuf, &talloced))) {
1485                 /* Ignore . and .. - we've already returned them. */
1486                 if (*n == '.') {
1487                         if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) {
1488                                 TALLOC_FREE(talloced);
1489                                 continue;
1490                         }
1491                 }
1492                 *poffset = dirp->offset = SMB_VFS_TELLDIR(conn, dirp->dir);
1493                 *ptalloced = talloced;
1494                 dirp->file_number++;
1495                 return n;
1496         }
1497         *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1498         *ptalloced = NULL;
1499         return NULL;
1500 }
1501
1502 /*******************************************************************
1503  Rewind to the start.
1504 ********************************************************************/
1505
1506 void RewindDir(struct smb_Dir *dirp, long *poffset)
1507 {
1508         SMB_VFS_REWINDDIR(dirp->conn, dirp->dir);
1509         dirp->file_number = 0;
1510         dirp->offset = START_OF_DIRECTORY_OFFSET;
1511         *poffset = START_OF_DIRECTORY_OFFSET;
1512 }
1513
1514 /*******************************************************************
1515  Seek a dir.
1516 ********************************************************************/
1517
1518 void SeekDir(struct smb_Dir *dirp, long offset)
1519 {
1520         if (offset != dirp->offset) {
1521                 if (offset == START_OF_DIRECTORY_OFFSET) {
1522                         RewindDir(dirp, &offset);
1523                         /*
1524                          * Ok we should really set the file number here
1525                          * to 1 to enable ".." to be returned next. Trouble
1526                          * is I'm worried about callers using SeekDir(dirp,0)
1527                          * as equivalent to RewindDir(). So leave this alone
1528                          * for now.
1529                          */
1530                 } else if  (offset == DOT_DOT_DIRECTORY_OFFSET) {
1531                         RewindDir(dirp, &offset);
1532                         /*
1533                          * Set the file number to 2 - we want to get the first
1534                          * real file entry (the one we return after "..")
1535                          * on the next ReadDir.
1536                          */
1537                         dirp->file_number = 2;
1538                 } else if (offset == END_OF_DIRECTORY_OFFSET) {
1539                         ; /* Don't seek in this case. */
1540                 } else {
1541                         SMB_VFS_SEEKDIR(dirp->conn, dirp->dir, offset);
1542                 }
1543                 dirp->offset = offset;
1544         }
1545 }
1546
1547 /*******************************************************************
1548  Tell a dir position.
1549 ********************************************************************/
1550
1551 long TellDir(struct smb_Dir *dirp)
1552 {
1553         return(dirp->offset);
1554 }
1555
1556 /*******************************************************************
1557  Add an entry into the dcache.
1558 ********************************************************************/
1559
1560 void DirCacheAdd(struct smb_Dir *dirp, const char *name, long offset)
1561 {
1562         struct name_cache_entry *e;
1563
1564         if (dirp->name_cache_size == 0) {
1565                 return;
1566         }
1567
1568         if (dirp->name_cache == NULL) {
1569                 dirp->name_cache = TALLOC_ZERO_ARRAY(
1570                         dirp, struct name_cache_entry, dirp->name_cache_size);
1571
1572                 if (dirp->name_cache == NULL) {
1573                         return;
1574                 }
1575         }
1576
1577         dirp->name_cache_index = (dirp->name_cache_index+1) %
1578                                         dirp->name_cache_size;
1579         e = &dirp->name_cache[dirp->name_cache_index];
1580         TALLOC_FREE(e->name);
1581         e->name = talloc_strdup(dirp, name);
1582         e->offset = offset;
1583 }
1584
1585 /*******************************************************************
1586  Find an entry by name. Leave us at the offset after it.
1587  Don't check for veto or invisible files.
1588 ********************************************************************/
1589
1590 bool SearchDir(struct smb_Dir *dirp, const char *name, long *poffset)
1591 {
1592         int i;
1593         const char *entry = NULL;
1594         char *talloced = NULL;
1595         connection_struct *conn = dirp->conn;
1596
1597         /* Search back in the name cache. */
1598         if (dirp->name_cache_size && dirp->name_cache) {
1599                 for (i = dirp->name_cache_index; i >= 0; i--) {
1600                         struct name_cache_entry *e = &dirp->name_cache[i];
1601                         if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1602                                 *poffset = e->offset;
1603                                 SeekDir(dirp, e->offset);
1604                                 return True;
1605                         }
1606                 }
1607                 for (i = dirp->name_cache_size - 1; i > dirp->name_cache_index; i--) {
1608                         struct name_cache_entry *e = &dirp->name_cache[i];
1609                         if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1610                                 *poffset = e->offset;
1611                                 SeekDir(dirp, e->offset);
1612                                 return True;
1613                         }
1614                 }
1615         }
1616
1617         /* Not found in the name cache. Rewind directory and start from scratch. */
1618         SMB_VFS_REWINDDIR(conn, dirp->dir);
1619         dirp->file_number = 0;
1620         *poffset = START_OF_DIRECTORY_OFFSET;
1621         while ((entry = ReadDirName(dirp, poffset, NULL, &talloced))) {
1622                 if (conn->case_sensitive ? (strcmp(entry, name) == 0) : strequal(entry, name)) {
1623                         TALLOC_FREE(talloced);
1624                         return True;
1625                 }
1626                 TALLOC_FREE(talloced);
1627         }
1628         return False;
1629 }
1630
1631 /*****************************************************************
1632  Is this directory empty ?
1633 *****************************************************************/
1634
1635 NTSTATUS can_delete_directory(struct connection_struct *conn,
1636                                 const char *dirname)
1637 {
1638         NTSTATUS status = NT_STATUS_OK;
1639         long dirpos = 0;
1640         const char *dname = NULL;
1641         char *talloced = NULL;
1642         SMB_STRUCT_STAT st;
1643         struct smb_Dir *dir_hnd = OpenDir(talloc_tos(), conn,
1644                                         dirname, NULL, 0);
1645
1646         if (!dir_hnd) {
1647                 return map_nt_error_from_unix(errno);
1648         }
1649
1650         while ((dname = ReadDirName(dir_hnd, &dirpos, &st, &talloced))) {
1651                 /* Quick check for "." and ".." */
1652                 if (dname[0] == '.') {
1653                         if (!dname[1] || (dname[1] == '.' && !dname[2])) {
1654                                 TALLOC_FREE(talloced);
1655                                 continue;
1656                         }
1657                 }
1658
1659                 if (!is_visible_file(conn, dirname, dname, &st, True)) {
1660                         TALLOC_FREE(talloced);
1661                         continue;
1662                 }
1663
1664                 DEBUG(10,("can_delete_directory: got name %s - can't delete\n",
1665                          dname ));
1666                 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
1667                 break;
1668         }
1669         TALLOC_FREE(talloced);
1670         TALLOC_FREE(dir_hnd);
1671
1672         return status;
1673 }