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