microsoft / ProjFS-Managed-API

A managed-code API for the Windows Projected File System
Other
142 stars 34 forks source link

FILE_ATTRIBUTE_OFFLINE not preserved between provider and projection #42

Closed mylodeon closed 4 years ago

mylodeon commented 4 years ago

This is probably a ProjFS issue rather than an Managed API issue - I hope you can forward this to the appropriate owner.

If you return a directory or file with FILE_ATTRIBUTE_OFFLINE set inside your ProjFS provider, it seems to preserve that flag for a second and then removes it. You can see explorer.exe showing the offline x's for a second, and then it goes away again.

I think what happens is that once the file has been accessed once, ProjFS swaps it for placeholder files - or it does some sort of other update of the enumeration. However, there is no callback of any kind to the provider at this point when it does that. When it does this update it stops returning the FILE_ATTRIBUTE_OFFLINE that the provider added originally, and explorer.exe takes the x's away.

This means explorer.exe now has free reign on the files and start fetching thumbnails for everything in sight. This unfortunately makes the ProjFS unusable against a slow backing store.

Dokan / FUSE works fine for these cases - if you return FILE_ATTRIBUTE_OFFLINE, explorer.exe respects it and doesn't try and create thumbnails.

cgallred commented 4 years ago

If you are developing a provider for use with slow backing stores, you may instead consider using the Cloud Files API. It has support for recall progress indicators, indicating when files are remote, etc.

ProjFS is designed for use with fast backing data stores and to mostly hide the fact that the files may be virtual or not completely present (I'm working on getting the docs updated to clarify that). As such, suppressing the FILE_ATTRIBUTE_ONLINE bit is a deliberate design decision for application compatibility. There are several applications that simply refuse to work with files that have the OFFLINE bit set. Since our goal is to make the files look like they're not offline, we don't want that bit to show up and trip up those applications.

ProjFS does make use of two attribute bits to tell system components like Explorer and things like anti-virus scanners that touching files may incur additional cost:

//
// This attribute only appears in directory enumeration classes (FILE_DIRECTORY_INFORMATION,
// FILE_BOTH_DIR_INFORMATION, etc.).  When this attribute is set, it means that the file or
// directory has no physical representation on the local system; the item is virtual.  Opening the
// item will be more expensive than normal, e.g. it will cause at least some of it to be fetched
// from a remote store.
//
#define FILE_ATTRIBUTE_RECALL_ON_OPEN       0x00040000  // winnt

//
// When this attribute is set, it means that the file or directory is not fully present locally.
// For a file that means that not all of its data is on local storage (e.g. it is sparse with some
// data still in remote storage).  For a directory it means that some of the directory contents are
// being virtualized from another location.  Reading the file / enumerating the directory will be
// more expensive than normal, e.g. it will cause at least some of the file/directory content to be
// fetched from a remote store.  Only kernel-mode callers can set this bit.
//
#define FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS 0x00400000 // winnt

Explorer uses these bits for things like avoiding recursive scans of directory trees. Most applications shouldn't need to pay attention to them.

BTW, in ProjFS a placeholder is created only when the provider calls the VirtualizationInstance::WritePlaceholderInfo API. That's normally done in the provider's implementation of IRequiredCallbacks::GetPlaceholderInfoCallback. See Providing File Data for info on how placeholder creation and data recall work (that info is written in terms of the underlying Win32 API, but applies equally to the .NET API).