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 "system/filesys.h"
23 #include "smbd/globals.h"
24 #include "libcli/security/security.h"
27 This module implements directory related functions for Samba.
30 /* "Special" directory offsets. */
31 #define END_OF_DIRECTORY_OFFSET ((long)-1)
32 #define START_OF_DIRECTORY_OFFSET ((long)0)
33 #define DOT_DOT_DIRECTORY_OFFSET ((long)0x80000000)
35 /* Make directory handle internals available. */
37 struct name_cache_entry {
43 connection_struct *conn;
47 size_t name_cache_size;
48 struct name_cache_entry *name_cache;
49 unsigned int name_cache_index;
50 unsigned int file_number;
54 struct dptr_struct *next, *prev;
57 struct connection_struct *conn;
58 struct smb_Dir *dir_hnd;
63 bool has_wild; /* Set to true if the wcard entry has MS wildcard characters in it. */
64 bool did_stat; /* Optimisation for non-wcard searches. */
67 static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn,
72 #define INVALID_DPTR_KEY (-3)
74 /****************************************************************************
76 ****************************************************************************/
78 bool make_dir_struct(TALLOC_CTX *ctx,
88 char *mask2 = talloc_strdup(ctx, mask);
94 if ((mode & aDIR) != 0) {
99 if ((p = strchr_m(mask2,'.')) != NULL) {
101 push_ascii(buf+1,mask2,8, 0);
102 push_ascii(buf+9,p+1,3, 0);
105 push_ascii(buf+1,mask2,11, 0);
108 memset(buf+21,'\0',DIR_STRUCT_SIZE-21);
110 srv_put_dos_date(buf,22,date);
111 SSVAL(buf,26,size & 0xFFFF);
112 SSVAL(buf,28,(size >> 16)&0xFFFF);
113 /* We only uppercase if FLAGS2_LONG_PATH_COMPONENTS is zero in the input buf.
114 Strange, but verified on W2K3. Needed for OS/2. JRA. */
115 push_ascii(buf+30,fname,12, uc ? STR_UPPER : 0);
116 DEBUG(8,("put name [%s] from [%s] into dir struct\n",buf+30, fname));
120 /****************************************************************************
121 Initialise the dir bitmap.
122 ****************************************************************************/
124 bool init_dptrs(struct smbd_server_connection *sconn)
126 if (sconn->searches.dptr_bmap) {
130 sconn->searches.dptr_bmap = bitmap_talloc(
131 sconn, MAX_DIRECTORY_HANDLES);
133 if (sconn->searches.dptr_bmap == NULL) {
140 /****************************************************************************
141 Idle a dptr - the directory is closed but the control info is kept.
142 ****************************************************************************/
144 static void dptr_idle(struct dptr_struct *dptr)
147 DEBUG(4,("Idling dptr dnum %d\n",dptr->dnum));
148 TALLOC_FREE(dptr->dir_hnd);
152 /****************************************************************************
153 Idle the oldest dptr.
154 ****************************************************************************/
156 static void dptr_idleoldest(struct smbd_server_connection *sconn)
158 struct dptr_struct *dptr;
161 * Go to the end of the list.
163 dptr = DLIST_TAIL(sconn->searches.dirptrs);
166 DEBUG(0,("No dptrs available to idle ?\n"));
171 * Idle the oldest pointer.
174 for(; dptr; dptr = DLIST_PREV(dptr)) {
182 /****************************************************************************
183 Get the struct dptr_struct for a dir index.
184 ****************************************************************************/
186 static struct dptr_struct *dptr_get(struct smbd_server_connection *sconn,
187 int key, bool forclose)
189 struct dptr_struct *dptr;
191 for(dptr = sconn->searches.dirptrs; dptr; dptr = dptr->next) {
192 if(dptr->dnum == key) {
193 if (!forclose && !dptr->dir_hnd) {
194 if (sconn->searches.dirhandles_open >= MAX_OPEN_DIRECTORIES)
195 dptr_idleoldest(sconn);
196 DEBUG(4,("dptr_get: Reopening dptr key %d\n",key));
197 if (!(dptr->dir_hnd = OpenDir(
198 NULL, dptr->conn, dptr->path,
199 dptr->wcard, dptr->attr))) {
200 DEBUG(4,("dptr_get: Failed to open %s (%s)\n",dptr->path,
205 DLIST_PROMOTE(sconn->searches.dirptrs,dptr);
212 /****************************************************************************
213 Get the dir path for a dir index.
214 ****************************************************************************/
216 char *dptr_path(struct smbd_server_connection *sconn, int key)
218 struct dptr_struct *dptr = dptr_get(sconn, key, false);
224 /****************************************************************************
225 Get the dir wcard for a dir index.
226 ****************************************************************************/
228 char *dptr_wcard(struct smbd_server_connection *sconn, int key)
230 struct dptr_struct *dptr = dptr_get(sconn, key, false);
236 /****************************************************************************
237 Get the dir attrib for a dir index.
238 ****************************************************************************/
240 uint16 dptr_attr(struct smbd_server_connection *sconn, int key)
242 struct dptr_struct *dptr = dptr_get(sconn, key, false);
248 /****************************************************************************
249 Close a dptr (internal func).
250 ****************************************************************************/
252 static void dptr_close_internal(struct dptr_struct *dptr)
254 struct smbd_server_connection *sconn = dptr->conn->sconn;
256 DEBUG(4,("closing dptr key %d\n",dptr->dnum));
262 DLIST_REMOVE(sconn->searches.dirptrs, dptr);
265 * Free the dnum in the bitmap. Remember the dnum value is always
266 * biased by one with respect to the bitmap.
269 if (!bitmap_query(sconn->searches.dptr_bmap, dptr->dnum - 1)) {
270 DEBUG(0,("dptr_close_internal : Error - closing dnum = %d and bitmap not set !\n",
274 bitmap_clear(sconn->searches.dptr_bmap, dptr->dnum - 1);
277 TALLOC_FREE(dptr->dir_hnd);
279 /* Lanman 2 specific code */
280 SAFE_FREE(dptr->wcard);
281 string_set(&dptr->path,"");
285 /****************************************************************************
286 Close a dptr given a key.
287 ****************************************************************************/
289 void dptr_close(struct smbd_server_connection *sconn, int *key)
291 struct dptr_struct *dptr;
293 if(*key == INVALID_DPTR_KEY)
296 /* OS/2 seems to use -1 to indicate "close all directories" */
298 struct dptr_struct *next;
299 for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
301 dptr_close_internal(dptr);
303 *key = INVALID_DPTR_KEY;
307 dptr = dptr_get(sconn, *key, true);
310 DEBUG(0,("Invalid key %d given to dptr_close\n", *key));
314 dptr_close_internal(dptr);
316 *key = INVALID_DPTR_KEY;
319 /****************************************************************************
320 Close all dptrs for a cnum.
321 ****************************************************************************/
323 void dptr_closecnum(connection_struct *conn)
325 struct dptr_struct *dptr, *next;
326 struct smbd_server_connection *sconn = conn->sconn;
332 for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
334 if (dptr->conn == conn) {
335 dptr_close_internal(dptr);
340 /****************************************************************************
341 Idle all dptrs for a cnum.
342 ****************************************************************************/
344 void dptr_idlecnum(connection_struct *conn)
346 struct dptr_struct *dptr;
347 struct smbd_server_connection *sconn = conn->sconn;
353 for(dptr = sconn->searches.dirptrs; dptr; dptr = dptr->next) {
354 if (dptr->conn == conn && dptr->dir_hnd) {
360 /****************************************************************************
361 Close a dptr that matches a given path, only if it matches the spid also.
362 ****************************************************************************/
364 void dptr_closepath(struct smbd_server_connection *sconn,
365 char *path,uint16 spid)
367 struct dptr_struct *dptr, *next;
368 for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
370 if (spid == dptr->spid && strequal(dptr->path,path))
371 dptr_close_internal(dptr);
375 /****************************************************************************
376 Try and close the oldest handle not marked for
377 expect close in the hope that the client has
378 finished with that one.
379 ****************************************************************************/
381 static void dptr_close_oldest(struct smbd_server_connection *sconn,
384 struct dptr_struct *dptr;
387 * Go to the end of the list.
389 for(dptr = sconn->searches.dirptrs; dptr && dptr->next; dptr = dptr->next)
393 DEBUG(0,("No old dptrs available to close oldest ?\n"));
398 * If 'old' is true, close the oldest oldhandle dnum (ie. 1 < dnum < 256) that
399 * does not have expect_close set. If 'old' is false, close
400 * one of the new dnum handles.
403 for(; dptr; dptr = DLIST_PREV(dptr)) {
404 if ((old && (dptr->dnum < 256) && !dptr->expect_close) ||
405 (!old && (dptr->dnum > 255))) {
406 dptr_close_internal(dptr);
412 /****************************************************************************
413 Create a new dir ptr. If the flag old_handle is true then we must allocate
414 from the bitmap range 0 - 255 as old SMBsearch directory handles are only
415 one byte long. If old_handle is false we allocate from the range
416 256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
417 a directory handle is never zero.
418 wcard must not be zero.
419 ****************************************************************************/
421 NTSTATUS dptr_create(connection_struct *conn, files_struct *fsp,
422 const char *path, bool old_handle, bool expect_close,uint16 spid,
423 const char *wcard, bool wcard_has_wild, uint32 attr, struct dptr_struct **dptr_ret)
425 struct smbd_server_connection *sconn = conn->sconn;
426 struct dptr_struct *dptr = NULL;
427 struct smb_Dir *dir_hnd;
430 if (fsp && fsp->is_directory && fsp->fh->fd != -1) {
431 path = fsp->fsp_name->base_name;
434 DEBUG(5,("dptr_create dir=%s\n", path));
437 DEBUG(0,("dptr_create: called with fake connection_struct\n"));
438 return NT_STATUS_INTERNAL_ERROR;
442 return NT_STATUS_INVALID_PARAMETER;
446 dir_hnd = OpenDir_fsp(NULL, conn, fsp, wcard, attr);
448 status = check_name(conn,path);
449 if (!NT_STATUS_IS_OK(status)) {
452 dir_hnd = OpenDir(NULL, conn, path, wcard, attr);
456 return map_nt_error_from_unix(errno);
459 if (sconn->searches.dirhandles_open >= MAX_OPEN_DIRECTORIES) {
460 dptr_idleoldest(sconn);
463 dptr = SMB_MALLOC_P(struct dptr_struct);
465 DEBUG(0,("malloc fail in dptr_create.\n"));
466 TALLOC_FREE(dir_hnd);
467 return NT_STATUS_NO_MEMORY;
475 * This is an old-style SMBsearch request. Ensure the
476 * value we return will fit in the range 1-255.
479 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 0);
481 if(dptr->dnum == -1 || dptr->dnum > 254) {
484 * Try and close the oldest handle not marked for
485 * expect close in the hope that the client has
486 * finished with that one.
489 dptr_close_oldest(sconn, true);
491 /* Now try again... */
492 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 0);
493 if(dptr->dnum == -1 || dptr->dnum > 254) {
494 DEBUG(0,("dptr_create: returned %d: Error - all old dirptrs in use ?\n", dptr->dnum));
496 TALLOC_FREE(dir_hnd);
497 return NT_STATUS_TOO_MANY_OPENED_FILES;
503 * This is a new-style trans2 request. Allocate from
504 * a range that will return 256 - MAX_DIRECTORY_HANDLES.
507 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 255);
509 if(dptr->dnum == -1 || dptr->dnum < 255) {
512 * Try and close the oldest handle close in the hope that
513 * the client has finished with that one. This will only
514 * happen in the case of the Win98 client bug where it leaks
518 dptr_close_oldest(sconn, false);
520 /* Now try again... */
521 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 255);
523 if(dptr->dnum == -1 || dptr->dnum < 255) {
524 DEBUG(0,("dptr_create: returned %d: Error - all new dirptrs in use ?\n", dptr->dnum));
526 TALLOC_FREE(dir_hnd);
527 return NT_STATUS_TOO_MANY_OPENED_FILES;
532 bitmap_set(sconn->searches.dptr_bmap, dptr->dnum);
534 dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
536 string_set(&dptr->path,path);
538 dptr->dir_hnd = dir_hnd;
540 dptr->expect_close = expect_close;
541 dptr->wcard = SMB_STRDUP(wcard);
543 bitmap_clear(sconn->searches.dptr_bmap, dptr->dnum - 1);
545 TALLOC_FREE(dir_hnd);
546 return NT_STATUS_NO_MEMORY;
548 if (lp_posix_pathnames() || (wcard[0] == '.' && wcard[1] == 0)) {
549 dptr->has_wild = True;
551 dptr->has_wild = wcard_has_wild;
556 DLIST_ADD(sconn->searches.dirptrs, dptr);
558 DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
559 dptr->dnum,path,expect_close));
567 /****************************************************************************
568 Wrapper functions to access the lower level directory handles.
569 ****************************************************************************/
571 void dptr_CloseDir(files_struct *fsp)
575 * Ugly hack. We have defined fdopendir to return ENOSYS if dirfd also isn't
576 * present. I hate Solaris. JRA.
579 if (fsp->fh->fd != -1 &&
580 fsp->dptr->dir_hnd &&
581 dirfd(fsp->dptr->dir_hnd->dir)) {
582 /* The call below closes the underlying fd. */
586 dptr_close_internal(fsp->dptr);
591 void dptr_SeekDir(struct dptr_struct *dptr, long offset)
593 SeekDir(dptr->dir_hnd, offset);
596 long dptr_TellDir(struct dptr_struct *dptr)
598 return TellDir(dptr->dir_hnd);
601 bool dptr_has_wild(struct dptr_struct *dptr)
603 return dptr->has_wild;
606 int dptr_dnum(struct dptr_struct *dptr)
611 /****************************************************************************
612 Return the next visible file name, skipping veto'd and invisible files.
613 ****************************************************************************/
615 static const char *dptr_normal_ReadDirName(struct dptr_struct *dptr,
616 long *poffset, SMB_STRUCT_STAT *pst,
619 /* Normal search for the next file. */
621 char *talloced = NULL;
623 while ((name = ReadDirName(dptr->dir_hnd, poffset, pst, &talloced))
625 if (is_visible_file(dptr->conn, dptr->path, name, pst, True)) {
626 *ptalloced = talloced;
629 TALLOC_FREE(talloced);
634 /****************************************************************************
635 Return the next visible file name, skipping veto'd and invisible files.
636 ****************************************************************************/
638 char *dptr_ReadDirName(TALLOC_CTX *ctx,
639 struct dptr_struct *dptr,
641 SMB_STRUCT_STAT *pst)
643 struct smb_filename smb_fname_base;
645 const char *name_temp = NULL;
646 char *talloced = NULL;
647 char *pathreal = NULL;
648 char *found_name = NULL;
651 SET_STAT_INVALID(*pst);
653 if (dptr->has_wild || dptr->did_stat) {
654 name_temp = dptr_normal_ReadDirName(dptr, poffset, pst,
656 if (name_temp == NULL) {
659 if (talloced != NULL) {
660 return talloc_move(ctx, &talloced);
662 return talloc_strdup(ctx, name_temp);
665 /* If poffset is -1 then we know we returned this name before and we
666 * have no wildcards. We're at the end of the directory. */
667 if (*poffset == END_OF_DIRECTORY_OFFSET) {
671 /* We know the stored wcard contains no wildcard characters.
672 * See if we can match with a stat call. If we can't, then set
673 * did_stat to true to ensure we only do this once and keep
676 dptr->did_stat = true;
678 /* First check if it should be visible. */
679 if (!is_visible_file(dptr->conn, dptr->path, dptr->wcard,
682 /* This only returns false if the file was found, but
683 is explicitly not visible. Set us to end of
684 directory, but return NULL as we know we can't ever
689 if (VALID_STAT(*pst)) {
690 name = talloc_strdup(ctx, dptr->wcard);
694 pathreal = talloc_asprintf(ctx,
701 /* Create an smb_filename with stream_name == NULL. */
702 ZERO_STRUCT(smb_fname_base);
703 smb_fname_base.base_name = pathreal;
705 if (SMB_VFS_STAT(dptr->conn, &smb_fname_base) == 0) {
706 *pst = smb_fname_base.st;
707 name = talloc_strdup(ctx, dptr->wcard);
710 /* If we get any other error than ENOENT or ENOTDIR
711 then the file exists we just can't stat it. */
712 if (errno != ENOENT && errno != ENOTDIR) {
713 name = talloc_strdup(ctx, dptr->wcard);
718 /* Stat failed. We know this is authoratiative if we are
719 * providing case sensitive semantics or the underlying
720 * filesystem is case sensitive.
722 if (dptr->conn->case_sensitive ||
723 !(dptr->conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH))
729 * Try case-insensitive stat if the fs has the ability. This avoids
730 * scanning the whole directory.
732 ret = SMB_VFS_GET_REAL_FILENAME(dptr->conn, dptr->path, dptr->wcard,
737 } else if (errno == ENOENT) {
738 /* The case-insensitive lookup was authoritative. */
742 TALLOC_FREE(pathreal);
744 name_temp = dptr_normal_ReadDirName(dptr, poffset, pst, &talloced);
745 if (name_temp == NULL) {
748 if (talloced != NULL) {
749 return talloc_move(ctx, &talloced);
751 return talloc_strdup(ctx, name_temp);
754 TALLOC_FREE(pathreal);
756 /* We need to set the underlying dir_hnd offset to -1
757 * also as this function is usually called with the
758 * output from TellDir. */
759 dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
763 /****************************************************************************
764 Search for a file by name, skipping veto'ed and not visible files.
765 ****************************************************************************/
767 bool dptr_SearchDir(struct dptr_struct *dptr, const char *name, long *poffset, SMB_STRUCT_STAT *pst)
769 SET_STAT_INVALID(*pst);
771 if (!dptr->has_wild && (dptr->dir_hnd->offset == END_OF_DIRECTORY_OFFSET)) {
772 /* This is a singleton directory and we're already at the end. */
773 *poffset = END_OF_DIRECTORY_OFFSET;
777 return SearchDir(dptr->dir_hnd, name, poffset);
780 /****************************************************************************
781 Add the name we're returning into the underlying cache.
782 ****************************************************************************/
784 void dptr_DirCacheAdd(struct dptr_struct *dptr, const char *name, long offset)
786 DirCacheAdd(dptr->dir_hnd, name, offset);
789 /****************************************************************************
790 Initialize variables & state data at the beginning of all search SMB requests.
791 ****************************************************************************/
792 void dptr_init_search_op(struct dptr_struct *dptr)
794 SMB_VFS_INIT_SEARCH_OP(dptr->conn, dptr->dir_hnd->dir);
797 /****************************************************************************
798 Fill the 5 byte server reserved dptr field.
799 ****************************************************************************/
801 bool dptr_fill(struct smbd_server_connection *sconn,
802 char *buf1,unsigned int key)
804 unsigned char *buf = (unsigned char *)buf1;
805 struct dptr_struct *dptr = dptr_get(sconn, key, false);
808 DEBUG(1,("filling null dirptr %d\n",key));
811 offset = (uint32)TellDir(dptr->dir_hnd);
812 DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key,
813 (long)dptr->dir_hnd,(int)offset));
819 /****************************************************************************
820 Fetch the dir ptr and seek it given the 5 byte server field.
821 ****************************************************************************/
823 struct dptr_struct *dptr_fetch(struct smbd_server_connection *sconn,
826 unsigned int key = *(unsigned char *)buf;
827 struct dptr_struct *dptr = dptr_get(sconn, key, false);
832 DEBUG(3,("fetched null dirptr %d\n",key));
836 offset = IVAL(buf,1);
837 if (offset == (uint32)-1) {
838 seekoff = END_OF_DIRECTORY_OFFSET;
840 seekoff = (long)offset;
842 SeekDir(dptr->dir_hnd,seekoff);
843 DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
844 key, dptr->path, (int)seekoff));
848 /****************************************************************************
850 ****************************************************************************/
852 struct dptr_struct *dptr_fetch_lanman2(struct smbd_server_connection *sconn,
855 struct dptr_struct *dptr = dptr_get(sconn, dptr_num, false);
858 DEBUG(3,("fetched null dirptr %d\n",dptr_num));
861 DEBUG(3,("fetching dirptr %d for path %s\n",dptr_num,dptr->path));
865 /****************************************************************************
866 Check that a file matches a particular file type.
867 ****************************************************************************/
869 bool dir_check_ftype(connection_struct *conn, uint32 mode, uint32 dirtype)
873 /* Check the "may have" search bits. */
874 if (((mode & ~dirtype) & (aHIDDEN | aSYSTEM | aDIR)) != 0)
877 /* Check the "must have" bits, which are the may have bits shifted eight */
878 /* If must have bit is set, the file/dir can not be returned in search unless the matching
879 file attribute is set */
880 mask = ((dirtype >> 8) & (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM)); /* & 0x37 */
882 if((mask & (mode & (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM))) == mask) /* check if matching attribute present */
891 static bool mangle_mask_match(connection_struct *conn,
892 const char *filename,
897 if (!name_to_8_3(filename,mname,False,conn->params)) {
900 return mask_match_search(mname,mask,False);
903 bool smbd_dirptr_get_entry(TALLOC_CTX *ctx,
904 struct dptr_struct *dirptr,
909 bool (*match_fn)(TALLOC_CTX *ctx,
914 bool (*mode_fn)(TALLOC_CTX *ctx,
916 struct smb_filename *smb_fname,
920 struct smb_filename **_smb_fname,
924 connection_struct *conn = dirptr->conn;
930 needslash = ( dirptr->path[strlen(dirptr->path) -1] != '/');
935 SMB_STRUCT_STAT sbuf;
939 char *pathreal = NULL;
940 struct smb_filename smb_fname;
945 cur_offset = dptr_TellDir(dirptr);
946 prev_offset = cur_offset;
947 dname = dptr_ReadDirName(ctx, dirptr, &cur_offset, &sbuf);
949 DEBUG(6,("smbd_dirptr_get_entry: dirptr 0x%lx now at offset %ld\n",
950 (long)dirptr, cur_offset));
956 isdots = (ISDOT(dname) || ISDOTDOT(dname));
957 if (dont_descend && !isdots) {
963 * fname may get mangled, dname is never mangled.
964 * Whenever we're accessing the filesystem we use
965 * pathreal which is composed from dname.
968 ok = match_fn(ctx, private_data, dname, mask, &fname);
974 pathreal = talloc_asprintf(ctx, "%s%s%s",
984 /* Create smb_fname with NULL stream_name. */
985 ZERO_STRUCT(smb_fname);
986 smb_fname.base_name = pathreal;
989 ok = mode_fn(ctx, private_data, &smb_fname, &mode);
993 TALLOC_FREE(pathreal);
997 if (!dir_check_ftype(conn, mode, dirtype)) {
998 DEBUG(5,("[%s] attribs 0x%x didn't match 0x%x\n",
999 fname, (unsigned int)mode, (unsigned int)dirtype));
1002 TALLOC_FREE(pathreal);
1006 if (ask_sharemode) {
1007 struct timespec write_time_ts;
1008 struct file_id fileid;
1010 fileid = vfs_file_id_from_sbuf(conn,
1012 get_file_infos(fileid, 0, NULL, &write_time_ts);
1013 if (!null_timespec(write_time_ts)) {
1014 update_stat_ex_mtime(&smb_fname.st,
1019 DEBUG(3,("smbd_dirptr_get_entry mask=[%s] found %s "
1021 mask, smb_fname_str_dbg(&smb_fname),
1024 DirCacheAdd(dirptr->dir_hnd, dname, cur_offset);
1028 status = copy_smb_filename(ctx, &smb_fname, _smb_fname);
1029 TALLOC_FREE(pathreal);
1030 if (!NT_STATUS_IS_OK(status)) {
1035 *_prev_offset = prev_offset;
1043 /****************************************************************************
1044 Get an 8.3 directory entry.
1045 ****************************************************************************/
1047 static bool smbd_dirptr_8_3_match_fn(TALLOC_CTX *ctx,
1053 connection_struct *conn = (connection_struct *)private_data;
1055 if ((strcmp(mask,"*.*") == 0) ||
1056 mask_match_search(dname, mask, false) ||
1057 mangle_mask_match(conn, dname, mask)) {
1061 if (!mangle_is_8_3(dname, false, conn->params)) {
1062 bool ok = name_to_8_3(dname, mname, false,
1072 *_fname = talloc_strdup(ctx, fname);
1073 if (*_fname == NULL) {
1083 static bool smbd_dirptr_8_3_mode_fn(TALLOC_CTX *ctx,
1085 struct smb_filename *smb_fname,
1088 connection_struct *conn = (connection_struct *)private_data;
1090 if (!VALID_STAT(smb_fname->st)) {
1091 if ((SMB_VFS_STAT(conn, smb_fname)) != 0) {
1092 DEBUG(5,("smbd_dirptr_8_3_mode_fn: "
1093 "Couldn't stat [%s]. Error "
1095 smb_fname_str_dbg(smb_fname),
1101 *_mode = dos_mode(conn, smb_fname);
1105 bool get_dir_entry(TALLOC_CTX *ctx,
1106 struct dptr_struct *dirptr,
1112 struct timespec *_date,
1116 connection_struct *conn = dirptr->conn;
1118 struct smb_filename *smb_fname = NULL;
1123 ok = smbd_dirptr_get_entry(ctx,
1129 smbd_dirptr_8_3_match_fn,
1130 smbd_dirptr_8_3_mode_fn,
1140 *_fname = talloc_move(ctx, &fname);
1141 *_size = smb_fname->st.st_ex_size;
1143 *_date = smb_fname->st.st_ex_mtime;
1144 TALLOC_FREE(smb_fname);
1148 /*******************************************************************
1149 Check to see if a user can read a file. This is only approximate,
1150 it is used as part of the "hide unreadable" option. Don't
1151 use it for anything security sensitive.
1152 ********************************************************************/
1154 static bool user_can_read_file(connection_struct *conn,
1155 struct smb_filename *smb_fname)
1158 * Never hide files from the root user.
1159 * We use (uid_t)0 here not sec_initial_uid()
1160 * as make test uses a single user context.
1163 if (get_current_uid(conn) == (uid_t)0) {
1167 return can_access_file_acl(conn, smb_fname, FILE_READ_DATA);
1170 /*******************************************************************
1171 Check to see if a user can write a file (and only files, we do not
1172 check dirs on this one). This is only approximate,
1173 it is used as part of the "hide unwriteable" option. Don't
1174 use it for anything security sensitive.
1175 ********************************************************************/
1177 static bool user_can_write_file(connection_struct *conn,
1178 const struct smb_filename *smb_fname)
1181 * Never hide files from the root user.
1182 * We use (uid_t)0 here not sec_initial_uid()
1183 * as make test uses a single user context.
1186 if (get_current_uid(conn) == (uid_t)0) {
1190 SMB_ASSERT(VALID_STAT(smb_fname->st));
1192 /* Pseudo-open the file */
1194 if(S_ISDIR(smb_fname->st.st_ex_mode)) {
1198 return can_write_to_file(conn, smb_fname);
1201 /*******************************************************************
1202 Is a file a "special" type ?
1203 ********************************************************************/
1205 static bool file_is_special(connection_struct *conn,
1206 const struct smb_filename *smb_fname)
1209 * Never hide files from the root user.
1210 * We use (uid_t)0 here not sec_initial_uid()
1211 * as make test uses a single user context.
1214 if (get_current_uid(conn) == (uid_t)0) {
1218 SMB_ASSERT(VALID_STAT(smb_fname->st));
1220 if (S_ISREG(smb_fname->st.st_ex_mode) ||
1221 S_ISDIR(smb_fname->st.st_ex_mode) ||
1222 S_ISLNK(smb_fname->st.st_ex_mode))
1228 /*******************************************************************
1229 Should the file be seen by the client?
1230 NOTE: A successful return is no guarantee of the file's existence.
1231 ********************************************************************/
1233 bool is_visible_file(connection_struct *conn, const char *dir_path,
1234 const char *name, SMB_STRUCT_STAT *pst, bool use_veto)
1236 bool hide_unreadable = lp_hideunreadable(SNUM(conn));
1237 bool hide_unwriteable = lp_hideunwriteable_files(SNUM(conn));
1238 bool hide_special = lp_hide_special_files(SNUM(conn));
1240 struct smb_filename *smb_fname_base = NULL;
1244 if ((strcmp(".",name) == 0) || (strcmp("..",name) == 0)) {
1245 return True; /* . and .. are always visible. */
1248 /* If it's a vetoed file, pretend it doesn't even exist */
1249 if (use_veto && IS_VETO_PATH(conn, name)) {
1250 DEBUG(10,("is_visible_file: file %s is vetoed.\n", name ));
1254 if (hide_unreadable || hide_unwriteable || hide_special) {
1255 entry = talloc_asprintf(talloc_tos(), "%s/%s", dir_path, name);
1261 /* Create an smb_filename with stream_name == NULL. */
1262 status = create_synthetic_smb_fname(talloc_tos(), entry, NULL,
1263 pst, &smb_fname_base);
1264 if (!NT_STATUS_IS_OK(status)) {
1269 /* If the file name does not exist, there's no point checking
1270 * the configuration options. We succeed, on the basis that the
1271 * checks *might* have passed if the file was present.
1273 if (!VALID_STAT(*pst)) {
1274 if (SMB_VFS_STAT(conn, smb_fname_base) != 0) {
1278 *pst = smb_fname_base->st;
1282 /* Honour _hide unreadable_ option */
1283 if (hide_unreadable &&
1284 !user_can_read_file(conn, smb_fname_base)) {
1285 DEBUG(10,("is_visible_file: file %s is unreadable.\n",
1290 /* Honour _hide unwriteable_ option */
1291 if (hide_unwriteable && !user_can_write_file(conn,
1293 DEBUG(10,("is_visible_file: file %s is unwritable.\n",
1298 /* Honour _hide_special_ option */
1299 if (hide_special && file_is_special(conn, smb_fname_base)) {
1300 DEBUG(10,("is_visible_file: file %s is special.\n",
1309 TALLOC_FREE(smb_fname_base);
1314 static int smb_Dir_destructor(struct smb_Dir *dirp)
1318 if (dirp->conn->sconn) {
1319 files_struct *fsp = file_find_fd(dirp->conn->sconn,
1322 /* The call below closes the underlying fd. */
1327 SMB_VFS_CLOSEDIR(dirp->conn,dirp->dir);
1329 if (dirp->conn->sconn) {
1330 dirp->conn->sconn->searches.dirhandles_open--;
1335 /*******************************************************************
1337 ********************************************************************/
1339 struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn,
1344 struct smb_Dir *dirp = TALLOC_ZERO_P(mem_ctx, struct smb_Dir);
1345 struct smbd_server_connection *sconn = conn->sconn;
1352 dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
1354 dirp->dir_path = talloc_strdup(dirp, name);
1355 if (!dirp->dir_path) {
1361 sconn->searches.dirhandles_open++;
1363 talloc_set_destructor(dirp, smb_Dir_destructor);
1365 dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path, mask, attr);
1367 DEBUG(5,("OpenDir: Can't open %s. %s\n", dirp->dir_path,
1379 /*******************************************************************
1380 Open a directory from an fsp.
1381 ********************************************************************/
1383 static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn,
1388 struct smb_Dir *dirp = TALLOC_ZERO_P(mem_ctx, struct smb_Dir);
1389 struct smbd_server_connection *sconn = conn->sconn;
1396 dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
1398 dirp->dir_path = talloc_strdup(dirp, fsp->fsp_name->base_name);
1399 if (!dirp->dir_path) {
1405 sconn->searches.dirhandles_open++;
1407 talloc_set_destructor(dirp, smb_Dir_destructor);
1409 if (fsp->is_directory && fsp->fh->fd != -1) {
1410 dirp->dir = SMB_VFS_FDOPENDIR(fsp, mask, attr);
1411 if (dirp->dir == NULL) {
1412 DEBUG(10,("OpenDir_fsp: SMB_VFS_FDOPENDIR on %s returned "
1416 if (errno != ENOSYS) {
1422 if (dirp->dir == NULL) {
1423 /* FDOPENDIR didn't work. Use OPENDIR instead. */
1424 dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path, mask, attr);
1428 DEBUG(5,("OpenDir_fsp: Can't open %s. %s\n", dirp->dir_path,
1441 /*******************************************************************
1442 Read from a directory.
1443 Return directory entry, current offset, and optional stat information.
1444 Don't check for veto or invisible files.
1445 ********************************************************************/
1447 const char *ReadDirName(struct smb_Dir *dirp, long *poffset,
1448 SMB_STRUCT_STAT *sbuf, char **ptalloced)
1451 char *talloced = NULL;
1452 connection_struct *conn = dirp->conn;
1454 /* Cheat to allow . and .. to be the first entries returned. */
1455 if (((*poffset == START_OF_DIRECTORY_OFFSET) ||
1456 (*poffset == DOT_DOT_DIRECTORY_OFFSET)) && (dirp->file_number < 2))
1458 if (dirp->file_number == 0) {
1460 *poffset = dirp->offset = START_OF_DIRECTORY_OFFSET;
1463 *poffset = dirp->offset = DOT_DOT_DIRECTORY_OFFSET;
1465 dirp->file_number++;
1468 } else if (*poffset == END_OF_DIRECTORY_OFFSET) {
1469 *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1472 /* A real offset, seek to it. */
1473 SeekDir(dirp, *poffset);
1476 while ((n = vfs_readdirname(conn, dirp->dir, sbuf, &talloced))) {
1477 /* Ignore . and .. - we've already returned them. */
1479 if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) {
1480 TALLOC_FREE(talloced);
1484 *poffset = dirp->offset = SMB_VFS_TELLDIR(conn, dirp->dir);
1485 *ptalloced = talloced;
1486 dirp->file_number++;
1489 *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1494 /*******************************************************************
1495 Rewind to the start.
1496 ********************************************************************/
1498 void RewindDir(struct smb_Dir *dirp, long *poffset)
1500 SMB_VFS_REWINDDIR(dirp->conn, dirp->dir);
1501 dirp->file_number = 0;
1502 dirp->offset = START_OF_DIRECTORY_OFFSET;
1503 *poffset = START_OF_DIRECTORY_OFFSET;
1506 /*******************************************************************
1508 ********************************************************************/
1510 void SeekDir(struct smb_Dir *dirp, long offset)
1512 if (offset != dirp->offset) {
1513 if (offset == START_OF_DIRECTORY_OFFSET) {
1514 RewindDir(dirp, &offset);
1516 * Ok we should really set the file number here
1517 * to 1 to enable ".." to be returned next. Trouble
1518 * is I'm worried about callers using SeekDir(dirp,0)
1519 * as equivalent to RewindDir(). So leave this alone
1522 } else if (offset == DOT_DOT_DIRECTORY_OFFSET) {
1523 RewindDir(dirp, &offset);
1525 * Set the file number to 2 - we want to get the first
1526 * real file entry (the one we return after "..")
1527 * on the next ReadDir.
1529 dirp->file_number = 2;
1530 } else if (offset == END_OF_DIRECTORY_OFFSET) {
1531 ; /* Don't seek in this case. */
1533 SMB_VFS_SEEKDIR(dirp->conn, dirp->dir, offset);
1535 dirp->offset = offset;
1539 /*******************************************************************
1540 Tell a dir position.
1541 ********************************************************************/
1543 long TellDir(struct smb_Dir *dirp)
1545 return(dirp->offset);
1548 /*******************************************************************
1549 Add an entry into the dcache.
1550 ********************************************************************/
1552 void DirCacheAdd(struct smb_Dir *dirp, const char *name, long offset)
1554 struct name_cache_entry *e;
1556 if (dirp->name_cache_size == 0) {
1560 if (dirp->name_cache == NULL) {
1561 dirp->name_cache = TALLOC_ZERO_ARRAY(
1562 dirp, struct name_cache_entry, dirp->name_cache_size);
1564 if (dirp->name_cache == NULL) {
1569 dirp->name_cache_index = (dirp->name_cache_index+1) %
1570 dirp->name_cache_size;
1571 e = &dirp->name_cache[dirp->name_cache_index];
1572 TALLOC_FREE(e->name);
1573 e->name = talloc_strdup(dirp, name);
1577 /*******************************************************************
1578 Find an entry by name. Leave us at the offset after it.
1579 Don't check for veto or invisible files.
1580 ********************************************************************/
1582 bool SearchDir(struct smb_Dir *dirp, const char *name, long *poffset)
1585 const char *entry = NULL;
1586 char *talloced = NULL;
1587 connection_struct *conn = dirp->conn;
1589 /* Search back in the name cache. */
1590 if (dirp->name_cache_size && dirp->name_cache) {
1591 for (i = dirp->name_cache_index; i >= 0; i--) {
1592 struct name_cache_entry *e = &dirp->name_cache[i];
1593 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1594 *poffset = e->offset;
1595 SeekDir(dirp, e->offset);
1599 for (i = dirp->name_cache_size - 1; i > dirp->name_cache_index; i--) {
1600 struct name_cache_entry *e = &dirp->name_cache[i];
1601 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1602 *poffset = e->offset;
1603 SeekDir(dirp, e->offset);
1609 /* Not found in the name cache. Rewind directory and start from scratch. */
1610 SMB_VFS_REWINDDIR(conn, dirp->dir);
1611 dirp->file_number = 0;
1612 *poffset = START_OF_DIRECTORY_OFFSET;
1613 while ((entry = ReadDirName(dirp, poffset, NULL, &talloced))) {
1614 if (conn->case_sensitive ? (strcmp(entry, name) == 0) : strequal(entry, name)) {
1615 TALLOC_FREE(talloced);
1618 TALLOC_FREE(talloced);
1623 /*****************************************************************
1624 Is this directory empty ?
1625 *****************************************************************/
1627 NTSTATUS can_delete_directory(struct connection_struct *conn,
1628 const char *dirname)
1630 NTSTATUS status = NT_STATUS_OK;
1632 const char *dname = NULL;
1633 char *talloced = NULL;
1635 struct smb_Dir *dir_hnd = OpenDir(talloc_tos(), conn,
1639 return map_nt_error_from_unix(errno);
1642 while ((dname = ReadDirName(dir_hnd, &dirpos, &st, &talloced))) {
1643 /* Quick check for "." and ".." */
1644 if (dname[0] == '.') {
1645 if (!dname[1] || (dname[1] == '.' && !dname[2])) {
1646 TALLOC_FREE(talloced);
1651 if (!is_visible_file(conn, dirname, dname, &st, True)) {
1652 TALLOC_FREE(talloced);
1656 DEBUG(10,("can_delete_directory: got name %s - can't delete\n",
1658 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
1661 TALLOC_FREE(talloced);
1662 TALLOC_FREE(dir_hnd);