Skip to content

Commit 0151db5

Browse files
committed
ReparsePoint math did not account for StreamName
When we come across a ReparsePoint we are to return the length of the "not-yet-parsed" section of the FileName, which may have had ":Zone.Identifier" at the end. Now we will add on the stream name length as well. Additionally, ":$DATA" can be omitted, if it is we have to remove that length, as internally we always add ":$DATA". Fix BSOD if non-existent streamname was attempted to be opened, without CREATE flag. VNRELE on NULL. Signed-off-by: Jorgen Lundman <lundman@lundman.net>
1 parent e1159c0 commit 0151db5

1 file changed

Lines changed: 36 additions & 5 deletions

File tree

module/os/windows/zfs/zfs_vnops_windows.c

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -476,14 +476,27 @@ zfs_decouplefileobject(vnode_t *vp, FILE_OBJECT *fileobject)
476476
vnode_decouplefileobject(vp, fileobject);
477477
}
478478

479+
static BOOLEAN
480+
ends_with_suffix(PUNICODE_STRING name, PCWSTR suffix)
481+
{
482+
size_t name_len = name->Length / sizeof (WCHAR);
483+
size_t suffix_len = wcslen(suffix);
484+
485+
if (name_len < suffix_len)
486+
return (FALSE);
487+
488+
return (_wcsnicmp(&name->Buffer[name_len - suffix_len], suffix,
489+
suffix_len) == 0);
490+
}
491+
479492
static void
480-
allocate_reparse(struct vnode *vp, char *finalname, PIRP Irp)
493+
allocate_reparse(struct vnode *vp, char *finalname, char *stream_name, PIRP Irp)
481494
{
482495
znode_t *zp;
483496
REPARSE_DATA_BUFFER *rpb;
484497
size_t size;
485498
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
486-
// PFILE_OBJECT FileObject = IrpSp->FileObject;
499+
PFILE_OBJECT FileObject = IrpSp->FileObject;
487500

488501
zp = VTOZ(vp);
489502
// fix me, direct vp access
@@ -499,11 +512,28 @@ allocate_reparse(struct vnode *vp, char *finalname, PIRP Irp)
499512
* associated file object.
500513
* Should include the leading "/", when finalname
501514
* here would be "lower".
515+
* Also note, if the looking was for filename:Zone.Identifier,
516+
* or similar stream name, we need to include the stream name
517+
* part. Ie, from the full FileObject->FileName, whatever that
518+
* may have been.
502519
*/
503520
ULONG len = 0;
504521
if (finalname && *finalname) {
505522
RtlUTF8ToUnicodeN(NULL, 0, &len,
506523
finalname, strlen(finalname));
524+
if (stream_name != NULL) {
525+
ULONG len2 = 0;
526+
RtlUTF8ToUnicodeN(NULL, 0, &len2,
527+
stream_name, strlen(stream_name));
528+
len += len2 + sizeof (WCHAR); // for ':'
529+
530+
// Sadly the ":$DATA" can be implied
531+
if (!ends_with_suffix(&IrpSp->FileObject->FileName,
532+
L":$DATA")) {
533+
len -= sizeof (WCHAR) * 6;
534+
}
535+
}
536+
507537
len += sizeof (WCHAR);
508538
}
509539
rpb->Reserved = len;
@@ -1692,7 +1722,7 @@ zfs_vnop_lookup_impl(PIRP Irp, PIO_STACK_LOCATION IrpSp, mount_t *zmo,
16921722
*/
16931723
Irp->IoStatus.Information = 0;
16941724
Irp->IoStatus.Status = 0;
1695-
allocate_reparse(vp, finalname, Irp);
1725+
allocate_reparse(vp, finalname, stream_name, Irp);
16961726

16971727
// should this only work on the final component?
16981728
#if 0
@@ -1772,8 +1802,9 @@ zfs_vnop_lookup_impl(PIRP Irp, PIO_STACK_LOCATION IrpSp, mount_t *zmo,
17721802
if ((error = zfs_get_xattrdir(zp, &dzp, cr,
17731803
CreateFile ? CREATE_XATTR_DIR : 0))) {
17741804
Irp->IoStatus.Information = FILE_DOES_NOT_EXIST;
1775-
VN_RELE(vp)
1776-
VN_RELE(dvp);
1805+
VN_RELE(vp);
1806+
if (dvp && !dvp_no_rele)
1807+
VN_RELE(dvp);
17771808
dprintf("No xattr dir - and not creating one\n");
17781809
return (STATUS_OBJECT_NAME_NOT_FOUND);
17791810
}

0 commit comments

Comments
 (0)