maharmstone / btrfs

WinBtrfs - an open-source btrfs driver for Windows
GNU Lesser General Public License v3.0
5.8k stars 222 forks source link

Need fallocate()-like preallocation functionality, and SetFileValidData() returns an Invalid Parameter error. #650

Open Davidebyzero opened 5 months ago

Davidebyzero commented 5 months ago

I'd really like to switch from NTFS to btrfs while still continuing to use Windows as my primary OS for a while longer, but there is one main problem standing in my way.

From what I know so far, Linux's fallocate() (or fallocate --length \<size> \<filename> from the command line) is even better than Windows's SetEndOfFile() (or Contig.exe -l -n \<filename> \<size> from the command line), because it doesn't require special permissions and virtually fills the file with zeroes. Apparently, fallocate offers the best of both worlds (sparse files and preallocated files), whereas SetEndOfFile() reveals the previous contents of the disk until they are overwritten.

I use SetFileValidData() in my custom recursive file copy program (which preserves most NTFS metadata, including hardlinks, junctions, symlinks, 8.3 shortnames*, alternate data streams, ACLs, and all timestamps including ChangeTime), to ensure that the target copy is optimally non-fragmented. But when used on a file in a btrfs volume, it returns ERROR_INVALID_PARAMETER. Note that I have set the SE_MANAGE_VOLUME_NAME privilege, and my recursive copy program has worked fine for years doing NTFS-to-NTFS copies.

* It looks like btrfs doesn't support shortnames, but I'm sure I'll be fine without them. I mainly implemented the preservation of them in my program because there wasn't a good reason not to.

Simply using SetEndOfFile() alone on a btrfs file merely virtually allocates it as a zero-filled sparse file, which is not desired here.

I have tried NtSetInformationFile(..., FileValidDataLengthInformation) and it too returns STATUS_INVALID_PARAMETER when used on btrfs files, while working properly on NTFS files (i.e., I've confirmed it does the same thing as SetFileValidData()).

Looking at the source code for drv_set_information(), there appear to be three things that can cause it to return STATUS_INVALID_PARAMETER: !Vcb || Vcb->type != VCB_TYPE_FS, !fcb, or !ccb. I have no idea if the driver is even reaching this part of the code when I call SetFileValidData(), as I have not compiled the driver myself, nor do I have a way set up to debug drivers, but at least from looking at the WinBtrfs source code it appears that it should be reaching this point.

Is preallocation of files actually implemented in WinBtrfs? It looks like it is, from my brief examination of the source code. If so, what reason could there be that the volume control block, file control block, or context control block checks would be failing, and causing this Invalid Parameter error? Is there anything else that could cause it?

If it is not actually currently intended for WinBtrfs to support SetFileValidData(), is there any other way to acheive fallocate()-like functionality when using it?

I found one other WinBtrfs issue which may be related, but it does not appear to be the same as the issue I am reporting.