diff --git a/include/os/windows/zfs/sys/zfs_windows.h b/include/os/windows/zfs/sys/zfs_windows.h index fce558209599..80ba0d732240 100644 --- a/include/os/windows/zfs/sys/zfs_windows.h +++ b/include/os/windows/zfs/sys/zfs_windows.h @@ -183,6 +183,8 @@ extern NTSTATUS set_file_rename_information(PDEVICE_OBJECT, PIRP, PIO_STACK_LOCATION); extern NTSTATUS set_file_valid_data_length_information( PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); +extern NTSTATUS set_file_case_sensitive_information( + PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); extern NTSTATUS set_file_position_information(PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); diff --git a/include/os/windows/zfs/sys/zfs_znode_impl.h b/include/os/windows/zfs/sys/zfs_znode_impl.h index 133a9bc204a3..c781ee0f5086 100644 --- a/include/os/windows/zfs/sys/zfs_znode_impl.h +++ b/include/os/windows/zfs/sys/zfs_znode_impl.h @@ -58,6 +58,8 @@ extern "C" { #define ZFS_SIMMUTABLE 0x0040000000000000ull #define ZFS_SAPPENDONLY 0x0080000000000000ull +#define ZFS_CASESENSITIVEDIR 0x0100000000000000ull + #define SA_ZPL_ADDTIME(z) z->z_attr_table[ZPL_ADDTIME] #define SA_ZPL_DOCUMENTID(z) z->z_attr_table[ZPL_DOCUMENTID] diff --git a/include/sys/xvattr.h b/include/sys/xvattr.h index a7994db894b9..96bdbdd6e076 100644 --- a/include/sys/xvattr.h +++ b/include/sys/xvattr.h @@ -67,6 +67,10 @@ typedef struct xoptattr { uint8_t xoa_sparse; uint8_t xoa_projinherit; uint64_t xoa_projid; + uint8_t xoa_tracked; /* macOS */; + uint8_t xoa_sappendonly; /* macOS */; + uint8_t xoa_simmutable; /* macOS */; + uint8_t xoa_case_sensitive_dir; /* Win */ } xoptattr_t; /* @@ -174,12 +178,18 @@ typedef struct xvattr { #define XAT0_SPARSE 0x00010000 /* sparse */ #define XAT0_PROJINHERIT 0x00020000 /* Create with parent projid */ #define XAT0_PROJID 0x00040000 /* Project ID */ +#define XAT0_TRACKED 0x00080000 /* macOS UF_TRACKED */ +#define XAT0_SAPPENDONLY 0x00100000 /* macOS SF_APPENDONLY */ +#define XAT0_SIMMUTABLE 0x00200000 /* macOS SF_IMMUTABLE */ +#define XAT0_CASESENSITIVEDIR 0x00400000 /* win */ + #define XAT0_ALL_ATTRS (XAT0_CREATETIME|XAT0_ARCHIVE|XAT0_SYSTEM| \ XAT0_READONLY|XAT0_HIDDEN|XAT0_NOUNLINK|XAT0_IMMUTABLE|XAT0_APPENDONLY| \ XAT0_NODUMP|XAT0_OPAQUE|XAT0_AV_QUARANTINED| XAT0_AV_MODIFIED| \ - XAT0_AV_SCANSTAMP|XAT0_REPARSE|XATO_GEN|XAT0_OFFLINE|XAT0_SPARSE| \ - XAT0_PROJINHERIT | XAT0_PROJID) + XAT0_AV_SCANSTAMP|XAT0_REPARSE|XAT0_GEN|XAT0_OFFLINE|XAT0_SPARSE| \ + XAT0_PROJINHERIT | XAT0_PROJID|XAT0_TRACKED|XAT0_SAPPENDONLY| \ + XAT0_SIMMUTABLE|XAT0_CASESENSITIVEDIR) /* Support for XAT_* optional attributes */ #define XVA_MASK 0xffffffff /* Used to mask off 32 bits */ @@ -218,6 +228,10 @@ typedef struct xvattr { #define XAT_SPARSE ((XAT0_INDEX << XVA_SHFT) | XAT0_SPARSE) #define XAT_PROJINHERIT ((XAT0_INDEX << XVA_SHFT) | XAT0_PROJINHERIT) #define XAT_PROJID ((XAT0_INDEX << XVA_SHFT) | XAT0_PROJID) +#define XAT_TRACKED ((XAT0_INDEX << XVA_SHFT) | XAT0_TRACKED) +#define XAT_SAPPENDONLY ((XAT0_INDEX << XVA_SHFT) | XAT0_SAPPENDONLY) +#define XAT_SIMMUTABLE ((XAT0_INDEX << XVA_SHFT) | XAT0_SIMMUTABLE) +#define XAT_CASESENSITIVEDIR ((XAT0_INDEX << XVA_SHFT) | XAT0_CASESENSITIVEDIR) /* * The returned attribute map array (xva_rtnattrmap[]) is located past the diff --git a/module/os/windows/zfs/zfs_dir.c b/module/os/windows/zfs/zfs_dir.c index 36e2d923ff62..27f9d47ffa89 100644 --- a/module/os/windows/zfs/zfs_dir.c +++ b/module/os/windows/zfs/zfs_dir.c @@ -179,6 +179,18 @@ zfs_dirent_lock(zfs_dirlock_t **dlpp, znode_t *dzp, char *name, znode_t **zpp, * once so that simultaneous case-insensitive/case-sensitive * behaves as rationally as possible. */ +#ifdef _WIN32 + /* + * Windows lets you set Case-Sensitive on + * a directory while the dataset as a whole + * is insensitive. + */ + if (S_ISDIR(dzp->z_mode) && + (dzp->z_pflags & ZFS_CASESENSITIVEDIR)) { + flag &= ~ZCILOOK; + flag |= ZCIEXACT; + } +#endif /* * When matching we may need to normalize & change case according to diff --git a/module/os/windows/zfs/zfs_vnops_os.c b/module/os/windows/zfs/zfs_vnops_os.c index 436a93b90a2b..42d0e245bbb4 100644 --- a/module/os/windows/zfs/zfs_vnops_os.c +++ b/module/os/windows/zfs/zfs_vnops_os.c @@ -2012,6 +2012,16 @@ zfs_setattr(znode_t *zp, vattr_t *vap, int flags, cred_t *cr, zidmap_t *mnt_ns) } } + if (XVA_ISSET_REQ(xvap, XAT_CASESENSITIVEDIR)) { + if (xoap->xoa_case_sensitive_dir != + ((zp->z_pflags & ZFS_CASESENSITIVEDIR) != 0)) { + need_policy = TRUE; + } else { + XVA_CLR_REQ(xvap, XAT_CASESENSITIVEDIR); + XVA_SET_REQ(&tmpxvattr, XAT_CASESENSITIVEDIR); + } + } + if (XVA_ISSET_REQ(xvap, XAT_AV_MODIFIED)) { if (xoap->xoa_av_modified != ((zp->z_pflags & ZFS_AV_MODIFIED) != 0)) { @@ -2404,6 +2414,9 @@ zfs_setattr(znode_t *zp, vattr_t *vap, int flags, cred_t *cr, zidmap_t *mnt_ns) if (XVA_ISSET_REQ(&tmpxvattr, XAT_PROJINHERIT)) { XVA_SET_REQ(xvap, XAT_PROJINHERIT); } + if (XVA_ISSET_REQ(&tmpxvattr, XAT_CASESENSITIVEDIR)) { + XVA_SET_REQ(xvap, XAT_CASESENSITIVEDIR); + } if (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP)) ASSERT(vp->v_type == VREG); diff --git a/module/os/windows/zfs/zfs_vnops_windows.c b/module/os/windows/zfs/zfs_vnops_windows.c index 24f435940a50..7dd0a7fe7c43 100644 --- a/module/os/windows/zfs/zfs_vnops_windows.c +++ b/module/os/windows/zfs/zfs_vnops_windows.c @@ -735,7 +735,7 @@ zfs_find_dvp_vp(zfsvfs_t *zfsvfs, char *filename, int finalpartmaynotexist, */ int zfs_vnop_lookup_impl(PIRP Irp, PIO_STACK_LOCATION IrpSp, mount_t *zmo, - char *filename, vattr_t *vap) + char *filename, xvattr_t *xvap) { int error; cred_t *cr = NULL; @@ -773,6 +773,7 @@ zfs_vnop_lookup_impl(PIRP Irp, PIO_STACK_LOCATION IrpSp, mount_t *zmo, ACCESS_MASK DesiredAccess = IrpSp->Parameters.Create.SecurityContext->DesiredAccess; zfs_ccb_t *zccb = NULL; + vattr_t *vap = &xvap->xva_vattr; if (zfsvfs == NULL) return (STATUS_OBJECT_PATH_NOT_FOUND); @@ -1311,9 +1312,17 @@ zfs_vnop_lookup_impl(PIRP Irp, PIO_STACK_LOCATION IrpSp, mount_t *zmo, vap->va_mode |= S_IFDIR; vap->va_mask |= (ATTR_MODE | ATTR_TYPE); + /* If parent is CaseSensitive, sub-Dir should be too */ + if (VTOZ(dvp)->z_pflags & ZFS_CASESENSITIVEDIR) { + xoptattr_t *xoap; + xoap = xva_getxoptattr(xvap); + xoap->xoa_case_sensitive_dir = 1; + XVA_SET_REQ(xvap, XAT_CASESENSITIVEDIR); + } + ASSERT(strchr(finalname, '\\') == NULL); error = zfs_mkdir(VTOZ(dvp), finalname, vap, &zp, NULL, - 0, NULL, NULL); + flags, NULL, NULL); if (error == 0) { vp = ZTOV(zp); zfs_couplefileobject(vp, NULL, FileObject, 0ULL, @@ -1572,7 +1581,7 @@ zfs_vnop_lookup_impl(PIRP Irp, PIO_STACK_LOCATION IrpSp, mount_t *zmo, // O_EXCL only if FILE_CREATE error = zfs_create(VTOZ(dvp), finalname, vap, CreateDisposition == FILE_CREATE, vap->va_mode, - &zp, NULL, 0, NULL, NULL); + &zp, NULL, flags, NULL, NULL); if (error == 0) { boolean_t reenter_for_xattr = B_FALSE; @@ -1827,7 +1836,7 @@ zfs_vnop_lookup(PIRP Irp, PIO_STACK_LOCATION IrpSp, mount_t *zmo) do { // Call ZFS - status = zfs_vnop_lookup_impl(Irp, IrpSp, zmo, filename, vap); + status = zfs_vnop_lookup_impl(Irp, IrpSp, zmo, filename, &xva); } while (status == EAGAIN); @@ -4441,6 +4450,10 @@ set_information(PDEVICE_OBJECT DeviceObject, PIRP Irp, Status = set_file_valid_data_length_information(DeviceObject, Irp, IrpSp); break; + case FileCaseSensitiveInformation: + Status = set_file_case_sensitive_information(DeviceObject, + Irp, IrpSp); + break; default: dprintf("* %s: unknown type NOTIMPLEMENTED\n", __func__); break; diff --git a/module/os/windows/zfs/zfs_vnops_windows_lib.c b/module/os/windows/zfs/zfs_vnops_windows_lib.c index c51d742a950e..ab14d4c00682 100644 --- a/module/os/windows/zfs/zfs_vnops_windows_lib.c +++ b/module/os/windows/zfs/zfs_vnops_windows_lib.c @@ -4021,7 +4021,6 @@ set_file_valid_data_length_information(PDEVICE_OBJECT DeviceObject, PIRP Irp, mount_t *zmo = DeviceObject->DeviceExtension; int error; CC_FILE_SIZES ccfs; - LIST_ENTRY rollback; boolean_t set_size = B_FALSE; dprintf("* FileValidDataLengthInformation: \n"); @@ -4105,6 +4104,65 @@ set_file_valid_data_length_information(PDEVICE_OBJECT DeviceObject, PIRP Irp, return (Status); } +NTSTATUS +set_file_case_sensitive_information(PDEVICE_OBJECT DeviceObject, PIRP Irp, + PIO_STACK_LOCATION IrpSp) +{ + NTSTATUS Status; + FILE_CASE_SENSITIVE_INFORMATION *fcsi = + Irp->AssociatedIrp.SystemBuffer; + mount_t *zmo = DeviceObject->DeviceExtension; + int error; + + dprintf("* FileCaseSensitiveInformation: \n"); + + if (IrpSp->Parameters.SetFile.Length < + sizeof (FILE_CASE_SENSITIVE_INFORMATION)) + return (STATUS_INFO_LENGTH_MISMATCH); + + if (IrpSp->FileObject == NULL || + IrpSp->FileObject->FsContext == NULL) + return (STATUS_INVALID_PARAMETER); + + struct vnode *vp = IrpSp->FileObject->FsContext; + zfs_ccb_t *ccb = IrpSp->FileObject->FsContext2; + znode_t *zp = VTOZ(vp); + + if (zmo == NULL || zp == NULL) + return (STATUS_INVALID_PARAMETER); + + if (!vnode_isdir(vp)) + return (STATUS_INVALID_PARAMETER); + + zfsvfs_t *zfsvfs = vfs_fsprivate(zmo); + if (zfsvfs == NULL) + return (STATUS_INVALID_PARAMETER); + + if ((error = zfs_enter(zfsvfs, FTAG)) != 0) + return (error); + + xvattr_t xva = { 0 }; + vattr_t *vap = &xva.xva_vattr; + xoptattr_t *xoap; + + xva_init(&xva); + xoap = xva_getxoptattr(&xva); + + /* + * We need to check if there are case issues in this dir, if + * the request is to make it case insensitive again. Return + * the code: STATUS_CASE_DIFFERING_NAMES_IN_DIR + */ + xoap->xoa_case_sensitive_dir = + (fcsi->Flags & FILE_CS_FLAG_CASE_SENSITIVE_DIR); + XVA_SET_REQ(&xva, XAT_CASESENSITIVEDIR); + + Status = zfs_setattr(zp, vap, 0, NULL, NULL); + + zfs_exit(zfsvfs, FTAG); + return (Status); +} + NTSTATUS set_file_position_information(PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) @@ -4677,13 +4735,9 @@ file_case_sensitive_information(PDEVICE_OBJECT DeviceObject, PIRP Irp, struct vnode *vp = FileObject->FsContext; if (vp != NULL) { znode_t *zp = VTOZ(vp); - if (zp != NULL) { - zfsvfs_t *zfsvfs = zp->z_zfsvfs; - if (zfsvfs->z_case == ZFS_CASE_SENSITIVE) + if (zp && (zp->z_pflags & ZFS_CASESENSITIVEDIR)) fcsi->Flags |= FILE_CS_FLAG_CASE_SENSITIVE_DIR; - - } } Irp->IoStatus.Information = sizeof (FILE_CASE_SENSITIVE_INFORMATION); diff --git a/module/os/windows/zfs/zfs_znode.c b/module/os/windows/zfs/zfs_znode.c index eff94188fffb..bd30a87b8dcb 100644 --- a/module/os/windows/zfs/zfs_znode.c +++ b/module/os/windows/zfs/zfs_znode.c @@ -1045,6 +1045,12 @@ zfs_xvattr_set(znode_t *zp, xvattr_t *xvap, dmu_tx_t *tx) zp->z_pflags, tx); XVA_SET_RTN(xvap, XAT_SPARSE); } + if (XVA_ISSET_REQ(xvap, XAT_CASESENSITIVEDIR)) { + ZFS_ATTR_SET(zp, ZFS_CASESENSITIVEDIR, + xoap->xoa_case_sensitive_dir, + zp->z_pflags, tx); + XVA_SET_RTN(xvap, XAT_CASESENSITIVEDIR); + } } int