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