[PATCH 6/6] ntdll: add initial ZFS case sensitivity support

Damjan Jovanovic damjan.jov at gmail.com
Mon Nov 9 22:50:09 CST 2020


ZFS supports a creation-time "casesensitivity" property on filesystems,
whose "insensitive" and possibly "mixed" values are of benefit to us.

This patch adds initial support for the "insensitive" case. There are
10 directories of header files needed in the include path for libzfs,
which don't always ship with FreeBSD releases, so useful bits have been
copied here instead, types abstracted (eg. void* instead of struct
pointers), and libzfs loaded through run-time dynamic linking.

It's only been tested on FreeBSD so far. Kernel and Wine bitness must
match, as there is no 32->64 ZFS ioctl compatibility at present;
such cases are always treated as case-sensitive.

The licensing situation is unclear. The ZFS headers and libzfs are
under the CDDL licence.

Signed-off-by: Damjan Jovanovic <damjan.jov at gmail.com>
---
 dlls/ntdll/unix/file.c | 226 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 226 insertions(+)
-------------- next part --------------
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 <unistd.h>
 #endif
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+#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 <mm at FreeBSD.org>. 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
      */


More information about the wine-devel mailing list