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