Forum Discussion
Can you check file size locally without hydrating?
Possibly a newbie question... I'm porting a C++ app which previously worked with a locally-synced Dropbox to work with locally-synced OneDrive. But I've found that when the app tries to check the file size, file index, last access time, or other info which you can get from a Windows GetFileInformationByHandle call -- the CreateFileW call (needed to get the file handle) immediately triggers a file hydration.
Is there any way to avoid this, and get a file handle to read information without triggering a download of the contents?
For the record, here's the relevant code:
HANDLE hff = CreateFileW(fn.c_str(), GENERIC_READ,
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
// hydration has happened by this point
if (hff == INVALID_HANDLE_VALUE) {
errno = ERRNO_FROM_WIN32(GetLastError());
return -1;
}
BY_HANDLE_FILE_INFORMATION wfd;
if (!GetFileInformationByHandle(hff, &wfd)) {
errno = ERRNO_FROM_WIN32(GetLastError());
return -1;
}
Yes. The first thing to change is GENERIC_READ: it requests access to file contents as well as metadata. For this query, request only FILE_READ_ATTRIBUTES.
HANDLE hff = CreateFileW( fn.c_str(), FILE_READ_ATTRIBUTES, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr ); if (hff == INVALID_HANDLE_VALUE) { const DWORD error = GetLastError(); errno = ERRNO_FROM_WIN32(error); return -1; } BY_HANDLE_FILE_INFORMATION info{}; if (!GetFileInformationByHandle(hff, &info)) { const DWORD error = GetLastError(); CloseHandle(hff); errno = ERRNO_FROM_WIN32(error); return -1; } CloseHandle(hff); const ULONGLONG fileSize = (static_cast<ULONGLONG>(info.nFileSizeHigh) << 32) | info.nFileSizeLow;
For a locally present OneDrive Files On-Demand placeholder, this metadata-only access should avoid downloading its contents. The reported size is the logical file size, not the space currently occupied on disk.
If you only need size and timestamps, GetFileAttributesExW is another option that doesn’t require opening a handle.
One caveat: the file index is a local filesystem identifier, not a persistent OneDrive cloud ID. Last-access timestamps also follow Windows filesystem update rules, so they aren’t a reliable record of when someone last viewed the cloud file.
Reference: CreateFileW access rights.
2 Replies
- LauraBennettIron Contributor
Yes. The first thing to change is GENERIC_READ: it requests access to file contents as well as metadata. For this query, request only FILE_READ_ATTRIBUTES.
HANDLE hff = CreateFileW( fn.c_str(), FILE_READ_ATTRIBUTES, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr ); if (hff == INVALID_HANDLE_VALUE) { const DWORD error = GetLastError(); errno = ERRNO_FROM_WIN32(error); return -1; } BY_HANDLE_FILE_INFORMATION info{}; if (!GetFileInformationByHandle(hff, &info)) { const DWORD error = GetLastError(); CloseHandle(hff); errno = ERRNO_FROM_WIN32(error); return -1; } CloseHandle(hff); const ULONGLONG fileSize = (static_cast<ULONGLONG>(info.nFileSizeHigh) << 32) | info.nFileSizeLow;
For a locally present OneDrive Files On-Demand placeholder, this metadata-only access should avoid downloading its contents. The reported size is the logical file size, not the space currently occupied on disk.
If you only need size and timestamps, GetFileAttributesExW is another option that doesn’t require opening a handle.
One caveat: the file index is a local filesystem identifier, not a persistent OneDrive cloud ID. Last-access timestamps also follow Windows filesystem update rules, so they aren’t a reliable record of when someone last viewed the cloud file.
Reference: CreateFileW access rights.
- jblum2000Copper Contributor
That's great news! For what it's worth, since I posted this, I found an alternate method which also works: open a handle to the parent folder, then use NtQueryDirectoryFileEx with the folder handle to iterate through the files and check their attributes. But your approach is obviously simpler in pretty much all cases!