diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index ff95db6c688..b448a5114de 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -112,6 +112,9 @@ #ifdef HAVE_UNISTD_H # include #endif +#ifdef HAVE_DLFCN_H +#include +#endif #include "ntstatus.h" #define WIN32_NO_STATUS @@ -1111,6 +1114,227 @@ static int get_dir_case_sensitivity_attr( const char *dir ) } #endif +/* Based on declarations from FreeBSD's + * /usr/src/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h, + * which is effectively under the CDDL licence: + */ + +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011 Pawel Jakub Dawidek. All rights reserved. + * Copyright (c) 2011, 2017 by Delphix. All rights reserved. + * Copyright 2019 Joyent, Inc. + * Copyright (c) 2012 Martin Matuska . All rights reserved. + * Copyright (c) 2013 Steven Hartland. All rights reserved. + * Copyright (c) 2014 Integros [integros.com] + * Copyright 2016 Nexenta Systems, Inc. + * Copyright (c) 2019 Datto Inc. + */ + +typedef enum { + ZPROP_CONT = -2, + ZPROP_INVAL = -1, + ZFS_PROP_TYPE = 0, + ZFS_PROP_CREATION, + ZFS_PROP_USED, + ZFS_PROP_AVAILABLE, + ZFS_PROP_REFERENCED, + ZFS_PROP_COMPRESSRATIO, + ZFS_PROP_MOUNTED, + ZFS_PROP_ORIGIN, + ZFS_PROP_QUOTA, + ZFS_PROP_RESERVATION, + ZFS_PROP_VOLSIZE, + ZFS_PROP_VOLBLOCKSIZE, + ZFS_PROP_RECORDSIZE, + ZFS_PROP_MOUNTPOINT, + ZFS_PROP_SHARENFS, + ZFS_PROP_CHECKSUM, + ZFS_PROP_COMPRESSION, + ZFS_PROP_ATIME, + ZFS_PROP_DEVICES, + ZFS_PROP_EXEC, + ZFS_PROP_SETUID, + ZFS_PROP_READONLY, + ZFS_PROP_ZONED, + ZFS_PROP_SNAPDIR, + ZFS_PROP_ACLMODE, + ZFS_PROP_ACLINHERIT, + ZFS_PROP_CREATETXG, + ZFS_PROP_NAME, /* not exposed to the user */ + ZFS_PROP_CANMOUNT, + ZFS_PROP_ISCSIOPTIONS, /* not exposed to the user */ + ZFS_PROP_XATTR, + ZFS_PROP_NUMCLONES, /* not exposed to the user */ + ZFS_PROP_COPIES, + ZFS_PROP_VERSION, + ZFS_PROP_UTF8ONLY, + ZFS_PROP_NORMALIZE, + ZFS_PROP_CASE, + ZFS_PROP_VSCAN, + ZFS_PROP_NBMAND, + ZFS_PROP_SHARESMB, + ZFS_PROP_REFQUOTA, + ZFS_PROP_REFRESERVATION, + ZFS_PROP_GUID, + ZFS_PROP_PRIMARYCACHE, + ZFS_PROP_SECONDARYCACHE, + ZFS_PROP_USEDSNAP, + ZFS_PROP_USEDDS, + ZFS_PROP_USEDCHILD, + ZFS_PROP_USEDREFRESERV, + ZFS_PROP_USERACCOUNTING, /* not exposed to the user */ + ZFS_PROP_STMF_SHAREINFO, /* not exposed to the user */ + ZFS_PROP_DEFER_DESTROY, + ZFS_PROP_USERREFS, + ZFS_PROP_LOGBIAS, + ZFS_PROP_UNIQUE, /* not exposed to the user */ + ZFS_PROP_OBJSETID, /* not exposed to the user */ + ZFS_PROP_DEDUP, + ZFS_PROP_MLSLABEL, + ZFS_PROP_SYNC, + ZFS_PROP_DNODESIZE, + ZFS_PROP_REFRATIO, + ZFS_PROP_WRITTEN, + ZFS_PROP_CLONES, + ZFS_PROP_LOGICALUSED, + ZFS_PROP_LOGICALREFERENCED, + ZFS_PROP_INCONSISTENT, /* not exposed to the user */ + ZFS_PROP_VOLMODE, + ZFS_PROP_FILESYSTEM_LIMIT, + ZFS_PROP_SNAPSHOT_LIMIT, + ZFS_PROP_FILESYSTEM_COUNT, + ZFS_PROP_SNAPSHOT_COUNT, + ZFS_PROP_REDUNDANT_METADATA, + ZFS_PROP_PREV_SNAP, + ZFS_PROP_RECEIVE_RESUME_TOKEN, + ZFS_PROP_REMAPTXG, /* not exposed to the user */ + ZFS_PROP_SPECIAL_SMALL_BLOCKS, + ZFS_NUM_PROPS +} zfs_prop_t; + +typedef enum { + ZFS_TYPE_FILESYSTEM = (1 << 0), + ZFS_TYPE_SNAPSHOT = (1 << 1), + ZFS_TYPE_VOLUME = (1 << 2), + ZFS_TYPE_POOL = (1 << 3), + ZFS_TYPE_BOOKMARK = (1 << 4) +} zfs_type_t; + +typedef enum { + ZPROP_SRC_NONE = 0x1, + ZPROP_SRC_DEFAULT = 0x2, + ZPROP_SRC_TEMPORARY = 0x4, + ZPROP_SRC_LOCAL = 0x8, + ZPROP_SRC_INHERITED = 0x10, + ZPROP_SRC_RECEIVED = 0x20 +} zprop_source_t; + +typedef enum { B_FALSE, B_TRUE } boolean_t; + +#define ZFS_MAXPROPLEN MAXPATHLEN + +typedef void libzfs_handle_t; +static libzfs_handle_t* (*p_libzfs_init)(void); +static void* (*p_libzfs_fini)(libzfs_handle_t *); +static const char *(*p_libzfs_error_description)(libzfs_handle_t *); + +typedef void zfs_handle_t; +static zfs_handle_t* (*p_zfs_open)(libzfs_handle_t *, const char *, int); +static void (*p_zfs_close)(zfs_handle_t *); +static int (*p_zfs_prop_get)(zfs_handle_t *, zfs_prop_t, char *, size_t, + zprop_source_t *, char *, size_t, boolean_t); + +static libzfs_handle_t *libzfs_handle = NULL; + +static void load_libzfs(void) +{ +#ifdef HAVE_DLFCN_H + void *libzfs = dlopen("libzfs.so.3", RTLD_LOCAL | RTLD_NOW); + if (!libzfs) + { + WARN("libzfs open failed: %s\n", dlerror()); + return; + } + + p_libzfs_init = dlsym(libzfs, "libzfs_init"); + p_libzfs_fini = dlsym(libzfs, "libzfs_fini"); + p_libzfs_error_description = dlsym(libzfs, "libzfs_error_description"); + p_zfs_open = dlsym(libzfs, "zfs_open"); + p_zfs_prop_get = dlsym(libzfs, "zfs_prop_get"); + p_zfs_close = dlsym(libzfs, "zfs_close"); + + if (p_libzfs_init && p_libzfs_fini && p_libzfs_error_description && + p_zfs_open && p_zfs_prop_get && p_zfs_close) + { + libzfs_handle = p_libzfs_init(); + if (!libzfs_handle) + ERR("libzfs_init failed\n"); + return; + } + ERR("couldn't find required libzfs symbols\n"); + dlclose(libzfs); +#endif +} + +static pthread_mutex_t zfs_mutex = PTHREAD_MUTEX_INITIALIZER; + +static BOOLEAN is_zfs_case_sensitive(const char *filesystem) +{ + static volatile BOOLEAN zfs_inited = FALSE; + zfs_handle_t *zfs_handle = NULL; + char case_sensitivity[ZFS_MAXPROPLEN]; + BOOLEAN case_sensitive = TRUE; + + mutex_lock(&zfs_mutex); + if (!zfs_inited) + { + zfs_inited = TRUE; + load_libzfs(); + } + mutex_unlock(&zfs_mutex); + if (libzfs_handle == NULL) + return TRUE; + + zfs_handle = p_zfs_open(libzfs_handle, filesystem, ZFS_TYPE_FILESYSTEM); + if (zfs_handle) + { + if (p_zfs_prop_get(zfs_handle, ZFS_PROP_CASE, + case_sensitivity, sizeof(case_sensitivity), + NULL, NULL, 0, B_FALSE) == 0) + case_sensitive = !strcmp(case_sensitivity, "insensitive"); + else + WARN("zfs_prop_get failed: %s\n", p_libzfs_error_description(libzfs_handle)); + p_zfs_close(zfs_handle); + } + else + WARN("could not zfs_open %s: %s\n", filesystem, p_libzfs_error_description(libzfs_handle)); + + TRACE("zfs case sensitivity of %s: %d\n", filesystem, case_sensitive); + return case_sensitive; +} + /*********************************************************************** * get_dir_case_sensitivity_stat * @@ -1133,6 +1357,8 @@ static BOOLEAN get_dir_case_sensitivity_stat( const char *dir ) * newer versions should be case-insensitive on the server anyway */ !strcmp( stfs.f_fstypename, "smbfs" )) return FALSE; + if (!strcmp( stfs.f_fstypename, "zfs" )) + return is_zfs_case_sensitive( stfs.f_mntfromname ); /* no ntfs-3g: modern fusefs has no way to report the filesystem on FreeBSD * no cd9660 or udf, they're case-sensitive on FreeBSD */