Skip to content

Commit

Permalink
Add support for FILE_CS_FLAG_CASE_SENSITIVE_DIR
Browse files Browse the repository at this point in the history
Signed-off-by: Jorgen Lundman <lundman@lundman.net>
  • Loading branch information
lundman committed Nov 25, 2023
1 parent 8c2f46c commit 817afbd
Show file tree
Hide file tree
Showing 8 changed files with 128 additions and 12 deletions.
2 changes: 2 additions & 0 deletions include/os/windows/zfs/sys/zfs_windows.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
2 changes: 2 additions & 0 deletions include/os/windows/zfs/sys/zfs_znode_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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]

Expand Down
18 changes: 16 additions & 2 deletions include/sys/xvattr.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/*
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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
Expand Down
12 changes: 12 additions & 0 deletions module/os/windows/zfs/zfs_dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
13 changes: 13 additions & 0 deletions module/os/windows/zfs/zfs_vnops_os.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand Down Expand Up @@ -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);
Expand Down
21 changes: 17 additions & 4 deletions module/os/windows/zfs/zfs_vnops_windows.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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;
Expand Down
66 changes: 60 additions & 6 deletions module/os/windows/zfs/zfs_vnops_windows_lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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);
Expand Down
6 changes: 6 additions & 0 deletions module/os/windows/zfs/zfs_znode.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 817afbd

Please sign in to comment.