Skip to content

Commit

Permalink
Handle ReparsePoints trailing slash lookup
Browse files Browse the repository at this point in the history
Although it is unknown why, it expects just the
unparsed length to be only the slash in this case.

This makes listing from powershell, and freefilesync
work.

Signed-off-by: Jorgen Lundman <[email protected]>
  • Loading branch information
lundman committed Feb 29, 2024
1 parent f886377 commit ce0494b
Showing 1 changed file with 61 additions and 33 deletions.
94 changes: 61 additions & 33 deletions module/os/windows/zfs/zfs_vnops_windows.c
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,51 @@ zfs_decouplefileobject(vnode_t *vp, FILE_OBJECT *fileobject)

}

static void
allocate_reparse(struct vnode *vp, char *finalname, PIRP Irp)
{
znode_t *zp;
REPARSE_DATA_BUFFER *rpb;
size_t size;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
PFILE_OBJECT FileObject = IrpSp->FileObject;

zp = VTOZ(vp);
// fix me, direct vp access
size = zfsctl_is_node(zp) ? vp->v_reparse_size :
zp->z_size;
rpb = ExAllocatePoolWithTag(PagedPool,
size, '!FSZ');
get_reparse_point_impl(zp, (char *)rpb, size);

/*
* Length, in bytes, of the unparsed portion of the
* file name pointed to by the FileName member of the
* associated file object.
* Should include the leading "/", when finalname
* here would be "lower".
*/
ULONG len = 0;
if (finalname && *finalname) {
RtlUTF8ToUnicodeN(NULL, 0, &len,
finalname, strlen(finalname));
len += sizeof (WCHAR);
}
rpb->Reserved = len;

dprintf("%s: returning REPARSE (remainder %d)\n",
__func__, rpb->Reserved);
Irp->IoStatus.Information = rpb->ReparseTag;
Irp->Tail.Overlay.AuxiliaryBuffer = (void *)rpb;

/* Unknown why, but btrfs does this */
if (FileObject) {
UNICODE_STRING *fn = &FileObject->FileName;
if (fn->Buffer[(fn->Length / sizeof (WCHAR)) - 1] == '\\')
rpb->Reserved = sizeof (WCHAR);
}
}

void
check_and_set_stream_parent(char *stream_name, PFILE_OBJECT FileObject,
uint64_t id)
Expand Down Expand Up @@ -1121,35 +1166,9 @@ zfs_vnop_lookup_impl(PIRP Irp, PIO_STACK_LOCATION IrpSp, mount_t *zmo,
* translation for us.
* - maharmstone
*/
zp = VTOZ(vp);
REPARSE_DATA_BUFFER *rpb;
size_t size;
// fix me, direct vp access
size = zfsctl_is_node(zp) ? vp->v_reparse_size :
zp->z_size;
rpb = ExAllocatePoolWithTag(PagedPool,
size, '!FSZ');
get_reparse_point_impl(zp, (char *)rpb, size);

/*
* Length, in bytes, of the unparsed portion of the
* file name pointed to by the FileName member of the
* associated file object.
* Should include the leading "/", when finalname
* here would be "lower".
*/
ULONG len = 0;
if (finalname && *finalname) {
RtlUTF8ToUnicodeN(NULL, 0, &len,
finalname, strlen(finalname));
len += sizeof (WCHAR);
}
rpb->Reserved = len;

dprintf("%s: returning REPARSE (remainder %d)\n",
__func__, rpb->Reserved);
Irp->IoStatus.Information = rpb->ReparseTag;
Irp->Tail.Overlay.AuxiliaryBuffer = (void *)rpb;
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = 0;
allocate_reparse(vp, finalname, Irp);

// should this only work on the final component?
#if 0
Expand Down Expand Up @@ -1206,7 +1225,7 @@ zfs_vnop_lookup_impl(PIRP Irp, PIO_STACK_LOCATION IrpSp, mount_t *zmo,
if ((dvp == NULL) || (error == ENOTDIR)) {
dprintf("%s: failed to find dvp - or dvp is a file\n",
__func__);
Irp->IoStatus.Information = 0;
Irp->IoStatus.Information = FILE_DOES_NOT_EXIST;
return (STATUS_OBJECT_NAME_NOT_FOUND);
}
dprintf("%s: failed to find vp in dvp\n", __func__);
Expand Down Expand Up @@ -8163,12 +8182,12 @@ fastio_query_open(PIRP Irp,
struct vnode *vp = NULL, *dvp = NULL;

PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);

#if 0
// If it has never been open, make it do that through full
// first, so vp is set.
if (IrpSp->FileObject->FsContext == NULL)
return (FALSE);

#endif
if (IrpSp->FileObject->FileName.Buffer != NULL &&
IrpSp->FileObject->FileName.Length > 0) {

Expand All @@ -8194,6 +8213,11 @@ fastio_query_open(PIRP Irp,
error = zfs_find_dvp_vp(zfsvfs, filename, 0, 0,
&lastname, &dvp, &vp, 0, 0);

// Handle reparse, or return FALSE/FAIL?
// if (error == STATUS_REPARSE)
// allocate_reparse(vp, lastname, Irp);
// But NTFS returns FALSE, so let's do same, so traces match.

kmem_free(filename, PATH_MAX);

if (dvp)
Expand All @@ -8219,8 +8243,12 @@ fastio_query_open(PIRP Irp,
}

/* Probably can skip setting these, we return FALSE */
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = error;
// if (error == STATUS_REPARSE)
// return (TRUE);

Irp->IoStatus.Information = 0;

return (FALSE);
}

Expand Down

0 comments on commit ce0494b

Please sign in to comment.