2 Unix SMB/CIFS implementation.
3 Directory handling routines
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Jeremy Allison 2007
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.
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.
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/>.
22 #include "smbd/globals.h"
23 #include "libcli/security/security.h"
26 This module implements directory related functions for Samba.
29 /* "Special" directory offsets. */
30 #define END_OF_DIRECTORY_OFFSET ((long)-1)
31 #define START_OF_DIRECTORY_OFFSET ((long)0)
32 #define DOT_DOT_DIRECTORY_OFFSET ((long)0x80000000)
34 /* Make directory handle internals available. */
36 struct name_cache_entry {
42 connection_struct *conn;
46 size_t name_cache_size;
47 struct name_cache_entry *name_cache;
48 unsigned int name_cache_index;
49 unsigned int file_number;
53 struct dptr_struct *next, *prev;
56 struct connection_struct *conn;
57 struct smb_Dir *dir_hnd;
62 bool has_wild; /* Set to true if the wcard entry has MS wildcard characters in it. */
63 bool did_stat; /* Optimisation for non-wcard searches. */
67 #define INVALID_DPTR_KEY (-3)
69 /****************************************************************************
71 ****************************************************************************/
73 bool make_dir_struct(TALLOC_CTX *ctx,
83 char *mask2 = talloc_strdup(ctx, mask);
89 if ((mode & aDIR) != 0) {
94 if ((p = strchr_m(mask2,'.')) != NULL) {
96 push_ascii(buf+1,mask2,8, 0);
97 push_ascii(buf+9,p+1,3, 0);
100 push_ascii(buf+1,mask2,11, 0);
103 memset(buf+21,'\0',DIR_STRUCT_SIZE-21);
105 srv_put_dos_date(buf,22,date);
106 SSVAL(buf,26,size & 0xFFFF);
107 SSVAL(buf,28,(size >> 16)&0xFFFF);
108 /* We only uppercase if FLAGS2_LONG_PATH_COMPONENTS is zero in the input buf.
109 Strange, but verified on W2K3. Needed for OS/2. JRA. */
110 push_ascii(buf+30,fname,12, uc ? STR_UPPER : 0);
111 DEBUG(8,("put name [%s] from [%s] into dir struct\n",buf+30, fname));
115 /****************************************************************************
116 Initialise the dir bitmap.
117 ****************************************************************************/
119 bool init_dptrs(struct smbd_server_connection *sconn)
121 if (sconn->smb1.searches.dptr_bmap) {
125 sconn->smb1.searches.dptr_bmap = bitmap_talloc(
126 sconn, MAX_DIRECTORY_HANDLES);
128 if (sconn->smb1.searches.dptr_bmap == NULL) {
135 /****************************************************************************
136 Idle a dptr - the directory is closed but the control info is kept.
137 ****************************************************************************/
139 static void dptr_idle(struct dptr_struct *dptr)
142 DEBUG(4,("Idling dptr dnum %d\n",dptr->dnum));
143 TALLOC_FREE(dptr->dir_hnd);
147 /****************************************************************************
148 Idle the oldest dptr.
149 ****************************************************************************/
151 static void dptr_idleoldest(struct smbd_server_connection *sconn)
153 struct dptr_struct *dptr;
156 * Go to the end of the list.
158 dptr = DLIST_TAIL(sconn->smb1.searches.dirptrs);
161 DEBUG(0,("No dptrs available to idle ?\n"));
166 * Idle the oldest pointer.
169 for(; dptr; dptr = DLIST_PREV(dptr)) {
177 /****************************************************************************
178 Get the struct dptr_struct for a dir index.
179 ****************************************************************************/
181 static struct dptr_struct *dptr_get(struct smbd_server_connection *sconn,
182 int key, bool forclose)
184 struct dptr_struct *dptr;
186 for(dptr = sconn->smb1.searches.dirptrs; dptr; dptr = dptr->next) {
187 if(dptr->dnum == key) {
188 if (!forclose && !dptr->dir_hnd) {
189 if (sconn->smb1.searches.dirhandles_open >= MAX_OPEN_DIRECTORIES)
190 dptr_idleoldest(sconn);
191 DEBUG(4,("dptr_get: Reopening dptr key %d\n",key));
192 if (!(dptr->dir_hnd = OpenDir(
193 NULL, dptr->conn, NULL, dptr->path,
194 dptr->wcard, dptr->attr))) {
195 DEBUG(4,("dptr_get: Failed to open %s (%s)\n",dptr->path,
200 DLIST_PROMOTE(sconn->smb1.searches.dirptrs,dptr);
207 /****************************************************************************
208 Get the dir path for a dir index.
209 ****************************************************************************/
211 char *dptr_path(struct smbd_server_connection *sconn, int key)
213 struct dptr_struct *dptr = dptr_get(sconn, key, false);
219 /****************************************************************************
220 Get the dir wcard for a dir index.
221 ****************************************************************************/
223 char *dptr_wcard(struct smbd_server_connection *sconn, int key)
225 struct dptr_struct *dptr = dptr_get(sconn, key, false);
231 /****************************************************************************
232 Get the dir attrib for a dir index.
233 ****************************************************************************/
235 uint16 dptr_attr(struct smbd_server_connection *sconn, int key)
237 struct dptr_struct *dptr = dptr_get(sconn, key, false);
243 /****************************************************************************
244 Close a dptr (internal func).
245 ****************************************************************************/
247 static void dptr_close_internal(struct dptr_struct *dptr)
249 struct smbd_server_connection *sconn = dptr->conn->sconn;
251 DEBUG(4,("closing dptr key %d\n",dptr->dnum));
257 DLIST_REMOVE(sconn->smb1.searches.dirptrs, dptr);
260 * Free the dnum in the bitmap. Remember the dnum value is always
261 * biased by one with respect to the bitmap.
264 if (!bitmap_query(sconn->smb1.searches.dptr_bmap, dptr->dnum - 1)) {
265 DEBUG(0,("dptr_close_internal : Error - closing dnum = %d and bitmap not set !\n",
269 bitmap_clear(sconn->smb1.searches.dptr_bmap, dptr->dnum - 1);
272 TALLOC_FREE(dptr->dir_hnd);
274 /* Lanman 2 specific code */
275 SAFE_FREE(dptr->wcard);
276 string_set(&dptr->path,"");
280 /****************************************************************************
281 Close a dptr given a key.
282 ****************************************************************************/
284 void dptr_close(struct smbd_server_connection *sconn, int *key)
286 struct dptr_struct *dptr;
288 if(*key == INVALID_DPTR_KEY)
291 /* OS/2 seems to use -1 to indicate "close all directories" */
293 struct dptr_struct *next;
294 for(dptr = sconn->smb1.searches.dirptrs; dptr; dptr = next) {
296 dptr_close_internal(dptr);
298 *key = INVALID_DPTR_KEY;
302 dptr = dptr_get(sconn, *key, true);
305 DEBUG(0,("Invalid key %d given to dptr_close\n", *key));
309 dptr_close_internal(dptr);
311 *key = INVALID_DPTR_KEY;
314 /****************************************************************************
315 Close all dptrs for a cnum.
316 ****************************************************************************/
318 void dptr_closecnum(connection_struct *conn)
320 struct dptr_struct *dptr, *next;
321 struct smbd_server_connection *sconn = conn->sconn;
327 for(dptr = sconn->smb1.searches.dirptrs; dptr; dptr = next) {
329 if (dptr->conn == conn) {
330 dptr_close_internal(dptr);
335 /****************************************************************************
336 Idle all dptrs for a cnum.
337 ****************************************************************************/
339 void dptr_idlecnum(connection_struct *conn)
341 struct dptr_struct *dptr;
342 struct smbd_server_connection *sconn = conn->sconn;
348 for(dptr = sconn->smb1.searches.dirptrs; dptr; dptr = dptr->next) {
349 if (dptr->conn == conn && dptr->dir_hnd) {
355 /****************************************************************************
356 Close a dptr that matches a given path, only if it matches the spid also.
357 ****************************************************************************/
359 void dptr_closepath(struct smbd_server_connection *sconn,
360 char *path,uint16 spid)
362 struct dptr_struct *dptr, *next;
363 for(dptr = sconn->smb1.searches.dirptrs; dptr; dptr = next) {
365 if (spid == dptr->spid && strequal(dptr->path,path))
366 dptr_close_internal(dptr);
370 /****************************************************************************
371 Try and close the oldest handle not marked for
372 expect close in the hope that the client has
373 finished with that one.
374 ****************************************************************************/
376 static void dptr_close_oldest(struct smbd_server_connection *sconn,
379 struct dptr_struct *dptr;
382 * Go to the end of the list.
384 for(dptr = sconn->smb1.searches.dirptrs; dptr && dptr->next; dptr = dptr->next)
388 DEBUG(0,("No old dptrs available to close oldest ?\n"));
393 * If 'old' is true, close the oldest oldhandle dnum (ie. 1 < dnum < 256) that
394 * does not have expect_close set. If 'old' is false, close
395 * one of the new dnum handles.
398 for(; dptr; dptr = DLIST_PREV(dptr)) {
399 if ((old && (dptr->dnum < 256) && !dptr->expect_close) ||
400 (!old && (dptr->dnum > 255))) {
401 dptr_close_internal(dptr);
407 /****************************************************************************
408 Create a new dir ptr. If the flag old_handle is true then we must allocate
409 from the bitmap range 0 - 255 as old SMBsearch directory handles are only
410 one byte long. If old_handle is false we allocate from the range
411 256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
412 a directory handle is never zero.
413 wcard must not be zero.
414 ****************************************************************************/
416 NTSTATUS dptr_create(connection_struct *conn, files_struct *fsp,
417 const char *path, bool old_handle, bool expect_close,uint16 spid,
418 const char *wcard, bool wcard_has_wild, uint32 attr, struct dptr_struct **dptr_ret)
420 struct smbd_server_connection *sconn = conn->sconn;
421 struct dptr_struct *dptr = NULL;
422 struct smb_Dir *dir_hnd;
425 if (fsp && fsp->is_directory && fsp->fh->fd != -1) {
426 path = fsp->fsp_name->base_name;
429 DEBUG(5,("dptr_create dir=%s\n", path));
432 DEBUG(0,("dptr_create: called with fake connection_struct\n"));
433 return NT_STATUS_INTERNAL_ERROR;
437 return NT_STATUS_INVALID_PARAMETER;
441 status = check_name(conn,path);
442 if (!NT_STATUS_IS_OK(status)) {
447 dir_hnd = OpenDir(NULL, conn, fsp, path, wcard, attr);
449 return map_nt_error_from_unix(errno);
452 if (sconn->smb1.searches.dirhandles_open >= MAX_OPEN_DIRECTORIES) {
453 dptr_idleoldest(sconn);
456 dptr = SMB_MALLOC_P(struct dptr_struct);
458 DEBUG(0,("malloc fail in dptr_create.\n"));
459 TALLOC_FREE(dir_hnd);
460 return NT_STATUS_NO_MEMORY;
468 * This is an old-style SMBsearch request. Ensure the
469 * value we return will fit in the range 1-255.
472 dptr->dnum = bitmap_find(sconn->smb1.searches.dptr_bmap, 0);
474 if(dptr->dnum == -1 || dptr->dnum > 254) {
477 * Try and close the oldest handle not marked for
478 * expect close in the hope that the client has
479 * finished with that one.
482 dptr_close_oldest(sconn, true);
484 /* Now try again... */
485 dptr->dnum = bitmap_find(sconn->smb1.searches.dptr_bmap, 0);
486 if(dptr->dnum == -1 || dptr->dnum > 254) {
487 DEBUG(0,("dptr_create: returned %d: Error - all old dirptrs in use ?\n", dptr->dnum));
489 TALLOC_FREE(dir_hnd);
490 return NT_STATUS_TOO_MANY_OPENED_FILES;
496 * This is a new-style trans2 request. Allocate from
497 * a range that will return 256 - MAX_DIRECTORY_HANDLES.
500 dptr->dnum = bitmap_find(sconn->smb1.searches.dptr_bmap, 255);
502 if(dptr->dnum == -1 || dptr->dnum < 255) {
505 * Try and close the oldest handle close in the hope that
506 * the client has finished with that one. This will only
507 * happen in the case of the Win98 client bug where it leaks
511 dptr_close_oldest(sconn, false);
513 /* Now try again... */
514 dptr->dnum = bitmap_find(sconn->smb1.searches.dptr_bmap, 255);
516 if(dptr->dnum == -1 || dptr->dnum < 255) {
517 DEBUG(0,("dptr_create: returned %d: Error - all new dirptrs in use ?\n", dptr->dnum));
519 TALLOC_FREE(dir_hnd);
520 return NT_STATUS_TOO_MANY_OPENED_FILES;
525 bitmap_set(sconn->smb1.searches.dptr_bmap, dptr->dnum);
527 dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
529 string_set(&dptr->path,path);
531 dptr->dir_hnd = dir_hnd;
533 dptr->expect_close = expect_close;
534 dptr->wcard = SMB_STRDUP(wcard);
536 bitmap_clear(sconn->smb1.searches.dptr_bmap, dptr->dnum - 1);
538 TALLOC_FREE(dir_hnd);
539 return NT_STATUS_NO_MEMORY;
541 if (lp_posix_pathnames() || (wcard[0] == '.' && wcard[1] == 0)) {
542 dptr->has_wild = True;
544 dptr->has_wild = wcard_has_wild;
549 DLIST_ADD(sconn->smb1.searches.dirptrs, dptr);
551 DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
552 dptr->dnum,path,expect_close));
560 /****************************************************************************
561 Wrapper functions to access the lower level directory handles.
562 ****************************************************************************/
564 void dptr_CloseDir(files_struct *fsp)
567 if (fsp->fh->fd == dirfd(fsp->dptr->dir_hnd->dir)) {
568 /* The call below closes the underlying fd. */
571 dptr_close_internal(fsp->dptr);
576 void dptr_SeekDir(struct dptr_struct *dptr, long offset)
578 SeekDir(dptr->dir_hnd, offset);
581 long dptr_TellDir(struct dptr_struct *dptr)
583 return TellDir(dptr->dir_hnd);
586 bool dptr_has_wild(struct dptr_struct *dptr)
588 return dptr->has_wild;
591 int dptr_dnum(struct dptr_struct *dptr)
596 /****************************************************************************
597 Return the next visible file name, skipping veto'd and invisible files.
598 ****************************************************************************/
600 static const char *dptr_normal_ReadDirName(struct dptr_struct *dptr,
601 long *poffset, SMB_STRUCT_STAT *pst,
604 /* Normal search for the next file. */
606 char *talloced = NULL;
608 while ((name = ReadDirName(dptr->dir_hnd, poffset, pst, &talloced))
610 if (is_visible_file(dptr->conn, dptr->path, name, pst, True)) {
611 *ptalloced = talloced;
614 TALLOC_FREE(talloced);
619 /****************************************************************************
620 Return the next visible file name, skipping veto'd and invisible files.
621 ****************************************************************************/
623 char *dptr_ReadDirName(TALLOC_CTX *ctx,
624 struct dptr_struct *dptr,
626 SMB_STRUCT_STAT *pst)
628 struct smb_filename smb_fname_base;
630 const char *name_temp = NULL;
631 char *talloced = NULL;
632 char *pathreal = NULL;
633 char *found_name = NULL;
636 SET_STAT_INVALID(*pst);
638 if (dptr->has_wild || dptr->did_stat) {
639 name_temp = dptr_normal_ReadDirName(dptr, poffset, pst,
641 if (name_temp == NULL) {
644 if (talloced != NULL) {
645 return talloc_move(ctx, &talloced);
647 return talloc_strdup(ctx, name_temp);
650 /* If poffset is -1 then we know we returned this name before and we
651 * have no wildcards. We're at the end of the directory. */
652 if (*poffset == END_OF_DIRECTORY_OFFSET) {
656 /* We know the stored wcard contains no wildcard characters.
657 * See if we can match with a stat call. If we can't, then set
658 * did_stat to true to ensure we only do this once and keep
661 dptr->did_stat = true;
663 /* First check if it should be visible. */
664 if (!is_visible_file(dptr->conn, dptr->path, dptr->wcard,
667 /* This only returns false if the file was found, but
668 is explicitly not visible. Set us to end of
669 directory, but return NULL as we know we can't ever
674 if (VALID_STAT(*pst)) {
675 name = talloc_strdup(ctx, dptr->wcard);
679 pathreal = talloc_asprintf(ctx,
686 /* Create an smb_filename with stream_name == NULL. */
687 ZERO_STRUCT(smb_fname_base);
688 smb_fname_base.base_name = pathreal;
690 if (SMB_VFS_STAT(dptr->conn, &smb_fname_base) == 0) {
691 *pst = smb_fname_base.st;
692 name = talloc_strdup(ctx, dptr->wcard);
695 /* If we get any other error than ENOENT or ENOTDIR
696 then the file exists we just can't stat it. */
697 if (errno != ENOENT && errno != ENOTDIR) {
698 name = talloc_strdup(ctx, dptr->wcard);
703 /* Stat failed. We know this is authoratiative if we are
704 * providing case sensitive semantics or the underlying
705 * filesystem is case sensitive.
707 if (dptr->conn->case_sensitive ||
708 !(dptr->conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH))
714 * Try case-insensitive stat if the fs has the ability. This avoids
715 * scanning the whole directory.
717 ret = SMB_VFS_GET_REAL_FILENAME(dptr->conn, dptr->path, dptr->wcard,
722 } else if (errno == ENOENT) {
723 /* The case-insensitive lookup was authoritative. */
727 TALLOC_FREE(pathreal);
729 name_temp = dptr_normal_ReadDirName(dptr, poffset, pst, &talloced);
730 if (name_temp == NULL) {
733 if (talloced != NULL) {
734 return talloc_move(ctx, &talloced);
736 return talloc_strdup(ctx, name_temp);
739 TALLOC_FREE(pathreal);
741 /* We need to set the underlying dir_hnd offset to -1
742 * also as this function is usually called with the
743 * output from TellDir. */
744 dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
748 /****************************************************************************
749 Search for a file by name, skipping veto'ed and not visible files.
750 ****************************************************************************/
752 bool dptr_SearchDir(struct dptr_struct *dptr, const char *name, long *poffset, SMB_STRUCT_STAT *pst)
754 SET_STAT_INVALID(*pst);
756 if (!dptr->has_wild && (dptr->dir_hnd->offset == END_OF_DIRECTORY_OFFSET)) {
757 /* This is a singleton directory and we're already at the end. */
758 *poffset = END_OF_DIRECTORY_OFFSET;
762 return SearchDir(dptr->dir_hnd, name, poffset);
765 /****************************************************************************
766 Add the name we're returning into the underlying cache.
767 ****************************************************************************/
769 void dptr_DirCacheAdd(struct dptr_struct *dptr, const char *name, long offset)
771 DirCacheAdd(dptr->dir_hnd, name, offset);
774 /****************************************************************************
775 Initialize variables & state data at the beginning of all search SMB requests.
776 ****************************************************************************/
777 void dptr_init_search_op(struct dptr_struct *dptr)
779 SMB_VFS_INIT_SEARCH_OP(dptr->conn, dptr->dir_hnd->dir);
782 /****************************************************************************
783 Fill the 5 byte server reserved dptr field.
784 ****************************************************************************/
786 bool dptr_fill(struct smbd_server_connection *sconn,
787 char *buf1,unsigned int key)
789 unsigned char *buf = (unsigned char *)buf1;
790 struct dptr_struct *dptr = dptr_get(sconn, key, false);
793 DEBUG(1,("filling null dirptr %d\n",key));
796 offset = (uint32)TellDir(dptr->dir_hnd);
797 DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key,
798 (long)dptr->dir_hnd,(int)offset));
804 /****************************************************************************
805 Fetch the dir ptr and seek it given the 5 byte server field.
806 ****************************************************************************/
808 struct dptr_struct *dptr_fetch(struct smbd_server_connection *sconn,
811 unsigned int key = *(unsigned char *)buf;
812 struct dptr_struct *dptr = dptr_get(sconn, key, false);
817 DEBUG(3,("fetched null dirptr %d\n",key));
821 offset = IVAL(buf,1);
822 if (offset == (uint32)-1) {
823 seekoff = END_OF_DIRECTORY_OFFSET;
825 seekoff = (long)offset;
827 SeekDir(dptr->dir_hnd,seekoff);
828 DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
829 key, dptr->path, (int)seekoff));
833 /****************************************************************************
835 ****************************************************************************/
837 struct dptr_struct *dptr_fetch_lanman2(struct smbd_server_connection *sconn,
840 struct dptr_struct *dptr = dptr_get(sconn, dptr_num, false);
843 DEBUG(3,("fetched null dirptr %d\n",dptr_num));
846 DEBUG(3,("fetching dirptr %d for path %s\n",dptr_num,dptr->path));
850 /****************************************************************************
851 Check that a file matches a particular file type.
852 ****************************************************************************/
854 bool dir_check_ftype(connection_struct *conn, uint32 mode, uint32 dirtype)
858 /* Check the "may have" search bits. */
859 if (((mode & ~dirtype) & (aHIDDEN | aSYSTEM | aDIR)) != 0)
862 /* Check the "must have" bits, which are the may have bits shifted eight */
863 /* If must have bit is set, the file/dir can not be returned in search unless the matching
864 file attribute is set */
865 mask = ((dirtype >> 8) & (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM)); /* & 0x37 */
867 if((mask & (mode & (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM))) == mask) /* check if matching attribute present */
876 static bool mangle_mask_match(connection_struct *conn,
877 const char *filename,
882 if (!name_to_8_3(filename,mname,False,conn->params)) {
885 return mask_match_search(mname,mask,False);
888 bool smbd_dirptr_get_entry(TALLOC_CTX *ctx,
889 struct dptr_struct *dirptr,
894 bool (*match_fn)(TALLOC_CTX *ctx,
899 bool (*mode_fn)(TALLOC_CTX *ctx,
901 struct smb_filename *smb_fname,
905 struct smb_filename **_smb_fname,
909 connection_struct *conn = dirptr->conn;
915 needslash = ( dirptr->path[strlen(dirptr->path) -1] != '/');
920 SMB_STRUCT_STAT sbuf;
924 char *pathreal = NULL;
925 struct smb_filename smb_fname;
930 cur_offset = dptr_TellDir(dirptr);
931 prev_offset = cur_offset;
932 dname = dptr_ReadDirName(ctx, dirptr, &cur_offset, &sbuf);
934 DEBUG(6,("smbd_dirptr_get_entry: dirptr 0x%lx now at offset %ld\n",
935 (long)dirptr, cur_offset));
941 isdots = (ISDOT(dname) || ISDOTDOT(dname));
942 if (dont_descend && !isdots) {
948 * fname may get mangled, dname is never mangled.
949 * Whenever we're accessing the filesystem we use
950 * pathreal which is composed from dname.
953 ok = match_fn(ctx, private_data, dname, mask, &fname);
959 pathreal = talloc_asprintf(ctx, "%s%s%s",
969 /* Create smb_fname with NULL stream_name. */
970 ZERO_STRUCT(smb_fname);
971 smb_fname.base_name = pathreal;
974 ok = mode_fn(ctx, private_data, &smb_fname, &mode);
978 TALLOC_FREE(pathreal);
982 if (!dir_check_ftype(conn, mode, dirtype)) {
983 DEBUG(5,("[%s] attribs 0x%x didn't match 0x%x\n",
984 fname, (unsigned int)mode, (unsigned int)dirtype));
987 TALLOC_FREE(pathreal);
992 struct timespec write_time_ts;
993 struct file_id fileid;
995 fileid = vfs_file_id_from_sbuf(conn,
997 get_file_infos(fileid, 0, NULL, &write_time_ts);
998 if (!null_timespec(write_time_ts)) {
999 update_stat_ex_mtime(&smb_fname.st,
1004 DEBUG(3,("smbd_dirptr_get_entry mask=[%s] found %s "
1006 mask, smb_fname_str_dbg(&smb_fname),
1009 DirCacheAdd(dirptr->dir_hnd, dname, cur_offset);
1013 status = copy_smb_filename(ctx, &smb_fname, _smb_fname);
1014 TALLOC_FREE(pathreal);
1015 if (!NT_STATUS_IS_OK(status)) {
1020 *_prev_offset = prev_offset;
1028 /****************************************************************************
1029 Get an 8.3 directory entry.
1030 ****************************************************************************/
1032 static bool smbd_dirptr_8_3_match_fn(TALLOC_CTX *ctx,
1038 connection_struct *conn = (connection_struct *)private_data;
1040 if ((strcmp(mask,"*.*") == 0) ||
1041 mask_match_search(dname, mask, false) ||
1042 mangle_mask_match(conn, dname, mask)) {
1046 if (!mangle_is_8_3(dname, false, conn->params)) {
1047 bool ok = name_to_8_3(dname, mname, false,
1057 *_fname = talloc_strdup(ctx, fname);
1058 if (*_fname == NULL) {
1068 static bool smbd_dirptr_8_3_mode_fn(TALLOC_CTX *ctx,
1070 struct smb_filename *smb_fname,
1073 connection_struct *conn = (connection_struct *)private_data;
1075 if (!VALID_STAT(smb_fname->st)) {
1076 if ((SMB_VFS_STAT(conn, smb_fname)) != 0) {
1077 DEBUG(5,("smbd_dirptr_8_3_mode_fn: "
1078 "Couldn't stat [%s]. Error "
1080 smb_fname_str_dbg(smb_fname),
1086 *_mode = dos_mode(conn, smb_fname);
1090 bool get_dir_entry(TALLOC_CTX *ctx,
1091 struct dptr_struct *dirptr,
1097 struct timespec *_date,
1101 connection_struct *conn = dirptr->conn;
1103 struct smb_filename *smb_fname = NULL;
1108 ok = smbd_dirptr_get_entry(ctx,
1114 smbd_dirptr_8_3_match_fn,
1115 smbd_dirptr_8_3_mode_fn,
1125 *_fname = talloc_move(ctx, &fname);
1126 *_size = smb_fname->st.st_ex_size;
1128 *_date = smb_fname->st.st_ex_mtime;
1129 TALLOC_FREE(smb_fname);
1133 /*******************************************************************
1134 Check to see if a user can read a file. This is only approximate,
1135 it is used as part of the "hide unreadable" option. Don't
1136 use it for anything security sensitive.
1137 ********************************************************************/
1139 static bool user_can_read_file(connection_struct *conn,
1140 struct smb_filename *smb_fname)
1143 * Never hide files from the root user.
1144 * We use (uid_t)0 here not sec_initial_uid()
1145 * as make test uses a single user context.
1148 if (get_current_uid(conn) == (uid_t)0) {
1152 return can_access_file_acl(conn, smb_fname, FILE_READ_DATA);
1155 /*******************************************************************
1156 Check to see if a user can write a file (and only files, we do not
1157 check dirs on this one). This is only approximate,
1158 it is used as part of the "hide unwriteable" option. Don't
1159 use it for anything security sensitive.
1160 ********************************************************************/
1162 static bool user_can_write_file(connection_struct *conn,
1163 const struct smb_filename *smb_fname)
1166 * Never hide files from the root user.
1167 * We use (uid_t)0 here not sec_initial_uid()
1168 * as make test uses a single user context.
1171 if (get_current_uid(conn) == (uid_t)0) {
1175 SMB_ASSERT(VALID_STAT(smb_fname->st));
1177 /* Pseudo-open the file */
1179 if(S_ISDIR(smb_fname->st.st_ex_mode)) {
1183 return can_write_to_file(conn, smb_fname);
1186 /*******************************************************************
1187 Is a file a "special" type ?
1188 ********************************************************************/
1190 static bool file_is_special(connection_struct *conn,
1191 const struct smb_filename *smb_fname)
1194 * Never hide files from the root user.
1195 * We use (uid_t)0 here not sec_initial_uid()
1196 * as make test uses a single user context.
1199 if (get_current_uid(conn) == (uid_t)0) {
1203 SMB_ASSERT(VALID_STAT(smb_fname->st));
1205 if (S_ISREG(smb_fname->st.st_ex_mode) ||
1206 S_ISDIR(smb_fname->st.st_ex_mode) ||
1207 S_ISLNK(smb_fname->st.st_ex_mode))
1213 /*******************************************************************
1214 Should the file be seen by the client?
1215 NOTE: A successful return is no guarantee of the file's existence.
1216 ********************************************************************/
1218 bool is_visible_file(connection_struct *conn, const char *dir_path,
1219 const char *name, SMB_STRUCT_STAT *pst, bool use_veto)
1221 bool hide_unreadable = lp_hideunreadable(SNUM(conn));
1222 bool hide_unwriteable = lp_hideunwriteable_files(SNUM(conn));
1223 bool hide_special = lp_hide_special_files(SNUM(conn));
1225 struct smb_filename *smb_fname_base = NULL;
1229 if ((strcmp(".",name) == 0) || (strcmp("..",name) == 0)) {
1230 return True; /* . and .. are always visible. */
1233 /* If it's a vetoed file, pretend it doesn't even exist */
1234 if (use_veto && IS_VETO_PATH(conn, name)) {
1235 DEBUG(10,("is_visible_file: file %s is vetoed.\n", name ));
1239 if (hide_unreadable || hide_unwriteable || hide_special) {
1240 entry = talloc_asprintf(talloc_tos(), "%s/%s", dir_path, name);
1246 /* Create an smb_filename with stream_name == NULL. */
1247 status = create_synthetic_smb_fname(talloc_tos(), entry, NULL,
1248 pst, &smb_fname_base);
1249 if (!NT_STATUS_IS_OK(status)) {
1254 /* If the file name does not exist, there's no point checking
1255 * the configuration options. We succeed, on the basis that the
1256 * checks *might* have passed if the file was present.
1258 if (!VALID_STAT(*pst)) {
1259 if (SMB_VFS_STAT(conn, smb_fname_base) != 0) {
1263 *pst = smb_fname_base->st;
1267 /* Honour _hide unreadable_ option */
1268 if (hide_unreadable &&
1269 !user_can_read_file(conn, smb_fname_base)) {
1270 DEBUG(10,("is_visible_file: file %s is unreadable.\n",
1275 /* Honour _hide unwriteable_ option */
1276 if (hide_unwriteable && !user_can_write_file(conn,
1278 DEBUG(10,("is_visible_file: file %s is unwritable.\n",
1283 /* Honour _hide_special_ option */
1284 if (hide_special && file_is_special(conn, smb_fname_base)) {
1285 DEBUG(10,("is_visible_file: file %s is special.\n",
1294 TALLOC_FREE(smb_fname_base);
1299 static int smb_Dir_destructor(struct smb_Dir *dirp)
1302 SMB_VFS_CLOSEDIR(dirp->conn,dirp->dir);
1304 if (dirp->conn->sconn) {
1305 dirp->conn->sconn->smb1.searches.dirhandles_open--;
1310 /*******************************************************************
1312 ********************************************************************/
1314 struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn,
1320 struct smb_Dir *dirp = TALLOC_ZERO_P(mem_ctx, struct smb_Dir);
1321 struct smbd_server_connection *sconn = conn->sconn;
1328 dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
1331 dirp->dir_path = talloc_strdup(dirp, fsp->fsp_name->base_name);
1333 dirp->dir_path = talloc_strdup(dirp, name);
1335 if (!dirp->dir_path) {
1341 sconn->smb1.searches.dirhandles_open++;
1343 talloc_set_destructor(dirp, smb_Dir_destructor);
1345 if (fsp && fsp->is_directory && fsp->fh->fd != -1) {
1346 dirp->dir = SMB_VFS_FDOPENDIR(fsp, mask, attr);
1347 if (dirp->dir == NULL) {
1348 DEBUG(10,("OpenDir: SMB_VFS_FDOPENDIR on %s returned "
1352 if (errno != ENOSYS) {
1358 if (dirp->dir == NULL) {
1359 /* FDOPENDIR didn't work - or fsp == NULL. Use
1361 dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path, mask, attr);
1365 DEBUG(5,("OpenDir: Can't open %s. %s\n", dirp->dir_path,
1377 /*******************************************************************
1378 Read from a directory.
1379 Return directory entry, current offset, and optional stat information.
1380 Don't check for veto or invisible files.
1381 ********************************************************************/
1383 const char *ReadDirName(struct smb_Dir *dirp, long *poffset,
1384 SMB_STRUCT_STAT *sbuf, char **ptalloced)
1387 char *talloced = NULL;
1388 connection_struct *conn = dirp->conn;
1390 /* Cheat to allow . and .. to be the first entries returned. */
1391 if (((*poffset == START_OF_DIRECTORY_OFFSET) ||
1392 (*poffset == DOT_DOT_DIRECTORY_OFFSET)) && (dirp->file_number < 2))
1394 if (dirp->file_number == 0) {
1396 *poffset = dirp->offset = START_OF_DIRECTORY_OFFSET;
1399 *poffset = dirp->offset = DOT_DOT_DIRECTORY_OFFSET;
1401 dirp->file_number++;
1404 } else if (*poffset == END_OF_DIRECTORY_OFFSET) {
1405 *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1408 /* A real offset, seek to it. */
1409 SeekDir(dirp, *poffset);
1412 while ((n = vfs_readdirname(conn, dirp->dir, sbuf, &talloced))) {
1413 /* Ignore . and .. - we've already returned them. */
1415 if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) {
1416 TALLOC_FREE(talloced);
1420 *poffset = dirp->offset = SMB_VFS_TELLDIR(conn, dirp->dir);
1421 *ptalloced = talloced;
1422 dirp->file_number++;
1425 *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1430 /*******************************************************************
1431 Rewind to the start.
1432 ********************************************************************/
1434 void RewindDir(struct smb_Dir *dirp, long *poffset)
1436 SMB_VFS_REWINDDIR(dirp->conn, dirp->dir);
1437 dirp->file_number = 0;
1438 dirp->offset = START_OF_DIRECTORY_OFFSET;
1439 *poffset = START_OF_DIRECTORY_OFFSET;
1442 /*******************************************************************
1444 ********************************************************************/
1446 void SeekDir(struct smb_Dir *dirp, long offset)
1448 if (offset != dirp->offset) {
1449 if (offset == START_OF_DIRECTORY_OFFSET) {
1450 RewindDir(dirp, &offset);
1452 * Ok we should really set the file number here
1453 * to 1 to enable ".." to be returned next. Trouble
1454 * is I'm worried about callers using SeekDir(dirp,0)
1455 * as equivalent to RewindDir(). So leave this alone
1458 } else if (offset == DOT_DOT_DIRECTORY_OFFSET) {
1459 RewindDir(dirp, &offset);
1461 * Set the file number to 2 - we want to get the first
1462 * real file entry (the one we return after "..")
1463 * on the next ReadDir.
1465 dirp->file_number = 2;
1466 } else if (offset == END_OF_DIRECTORY_OFFSET) {
1467 ; /* Don't seek in this case. */
1469 SMB_VFS_SEEKDIR(dirp->conn, dirp->dir, offset);
1471 dirp->offset = offset;
1475 /*******************************************************************
1476 Tell a dir position.
1477 ********************************************************************/
1479 long TellDir(struct smb_Dir *dirp)
1481 return(dirp->offset);
1484 /*******************************************************************
1485 Add an entry into the dcache.
1486 ********************************************************************/
1488 void DirCacheAdd(struct smb_Dir *dirp, const char *name, long offset)
1490 struct name_cache_entry *e;
1492 if (dirp->name_cache_size == 0) {
1496 if (dirp->name_cache == NULL) {
1497 dirp->name_cache = TALLOC_ZERO_ARRAY(
1498 dirp, struct name_cache_entry, dirp->name_cache_size);
1500 if (dirp->name_cache == NULL) {
1505 dirp->name_cache_index = (dirp->name_cache_index+1) %
1506 dirp->name_cache_size;
1507 e = &dirp->name_cache[dirp->name_cache_index];
1508 TALLOC_FREE(e->name);
1509 e->name = talloc_strdup(dirp, name);
1513 /*******************************************************************
1514 Find an entry by name. Leave us at the offset after it.
1515 Don't check for veto or invisible files.
1516 ********************************************************************/
1518 bool SearchDir(struct smb_Dir *dirp, const char *name, long *poffset)
1521 const char *entry = NULL;
1522 char *talloced = NULL;
1523 connection_struct *conn = dirp->conn;
1525 /* Search back in the name cache. */
1526 if (dirp->name_cache_size && dirp->name_cache) {
1527 for (i = dirp->name_cache_index; i >= 0; i--) {
1528 struct name_cache_entry *e = &dirp->name_cache[i];
1529 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1530 *poffset = e->offset;
1531 SeekDir(dirp, e->offset);
1535 for (i = dirp->name_cache_size - 1; i > dirp->name_cache_index; i--) {
1536 struct name_cache_entry *e = &dirp->name_cache[i];
1537 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1538 *poffset = e->offset;
1539 SeekDir(dirp, e->offset);
1545 /* Not found in the name cache. Rewind directory and start from scratch. */
1546 SMB_VFS_REWINDDIR(conn, dirp->dir);
1547 dirp->file_number = 0;
1548 *poffset = START_OF_DIRECTORY_OFFSET;
1549 while ((entry = ReadDirName(dirp, poffset, NULL, &talloced))) {
1550 if (conn->case_sensitive ? (strcmp(entry, name) == 0) : strequal(entry, name)) {
1551 TALLOC_FREE(talloced);
1554 TALLOC_FREE(talloced);
1559 /*****************************************************************
1560 Is this directory empty ?
1561 *****************************************************************/
1563 NTSTATUS can_delete_directory(struct connection_struct *conn,
1564 const char *dirname)
1566 NTSTATUS status = NT_STATUS_OK;
1568 const char *dname = NULL;
1569 char *talloced = NULL;
1571 struct smb_Dir *dir_hnd = OpenDir(talloc_tos(), conn, NULL,
1575 return map_nt_error_from_unix(errno);
1578 while ((dname = ReadDirName(dir_hnd, &dirpos, &st, &talloced))) {
1579 /* Quick check for "." and ".." */
1580 if (dname[0] == '.') {
1581 if (!dname[1] || (dname[1] == '.' && !dname[2])) {
1582 TALLOC_FREE(talloced);
1587 if (!is_visible_file(conn, dirname, dname, &st, True)) {
1588 TALLOC_FREE(talloced);
1592 DEBUG(10,("can_delete_directory: got name %s - can't delete\n",
1594 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
1597 TALLOC_FREE(talloced);
1598 TALLOC_FREE(dir_hnd);