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