EldoS | Feel safer!

Software components for data protection, secure storage and transfer

conflicting CbFsOpenFile() after CbfsRenameOrMoveFile()

Also by EldoS: CallbackProcess
A component to control process creation and termination in Windows and .NET applications.
#33746
Posted: 06/23/2015 11:57:06
by Todd Gleason (Standard support level)
Joined: 09/11/2014
Posts: 21

I can reproduce this info in the Debug window if I make some changes to the Mapper sample:

Moving file \\CBFS\Test\TestFileMove_Src.txt -> \\CBFS\Test\TestFileMove_Dst.txt
CbFsCleanupFile(): Y:\CBFSTest\TestFileMove_Src.txt): start
CbFsOpenFile(): Y:\CBFSTest\TestFileMove_Src.txt (DesiredAccess: READ_ATTRIBUTES; FileAttributes: Archive, OpenReparsePoint; ShareMode: ReadWrite, Delete): start
CbFsCleanupFile(): Y:\CBFSTest\TestFileMove_Src.txt): start
CbFsCloseFile(): Y:\CBFSTest\TestFileMove_Src.txt): start
CbFsOpenFile(): Y:\CBFSTest\TestFileMove_Src.txt (DesiredAccess: READ_ATTRIBUTES|SYNCHRONIZE|DELETE; FileAttributes: Archive, OpenReparsePoint; ShareMode: ReadWrite, Delete): start
CbFsOpenFile(): Y:\CBFSTest\ (DesiredAccess: ADD_FILE|SYNCHRONIZE; FileAttributes: Directory; ShareMode: ReadWrite): start
CbFsCleanupFile(): Y:\CBFSTest\TestFileMove_Src.txt): start
CbFsCloseFile(): Y:\CBFSTest\TestFileMove_Src.txt): start
CbFsCleanupFile(): Y:\CBFSTest\TestFileMove_Src.txt): start
CbFsCloseFile(): Y:\CBFSTest\TestFileMove_Src.txt): start
CbFsRenameOrMoveFile(): Y:\CBFSTest\TestFileMove_Src.txt: start
CbFsRenameOrMoveFile(): Y:\CBFSTest\TestFileMove_Src.txt: end
CbFsOpenFile(): Y:\CBFSTest\TestFileMove_Dst.txt (DesiredAccess: GENERIC_WRITE|READ_ATTRIBUTES; FileAttributes: Normal, OpenNoRecall, SequentialScan; ShareMode: Read): start
CbFsOpenFile(): Y:\CBFSTest\TestFileMove_Dst.txt (DesiredAccess: READ_ATTRIBUTES|SYNCHRONIZE|DELETE; FileAttributes: Archive, OpenReparsePoint; ShareMode: ReadWrite, Delete): start
CbFsCleanupFile(): Y:\CBFSTest\): start
CbFsCloseFile(): Y:\CBFSTest\): start
CbFsCleanupFile(): Y:\CBFSTest\TestFileMove_Dst.txt): start
CbFsCloseFile(): Y:\CBFSTest\TestFileMove_Dst.txt): start
Moved file \\CBFS\Test\TestFileMove_Src.txt -> \\CBFS\Test\TestFileMove_Dst.txt


Note the two CbFsOpenFile() calls immediately after CbFsRenameOrMoveFile().

The main changes that I think might show this are disabling of optimizations like caching, and calling all open/close callbacks. I tried to attach the modified source, but no .zip attachments are allowed here. I can send it if needed however.

The mapper code works without problems, because it ignores the permissions requested and asks for all permissions exclusively. But in our production code, we are instead opening using the requested permissions, and after the CbFsRenameOrMoveFile() call, the GENERIC_WRITE with ShareMode Read in the first CbFsOpenFile() call prevents the second CbFsOpenFile() call requesting DELETE access from functioning.

What I don't understand is why these open/close calls are even needed, nor whether they are called by the OS, or by CBFS, and if there is a way to prevent these if they are not necessary, or else some improvement in how we handle them. Right now we fail the second request and log the error.
#33763
Posted: 06/24/2015 08:30:31
by Volodymyr Zinin (EldoS Corp.)

Actually the OnClose and OnOpen callbacks around the OnRenameOrMove callback are because of the following:

During file renaming Windows works in the following way:
1. The file is opened.
2. The destination folder is opened.
3. The “rename or move” request is sent to the file.
4. The destination folder is closed.
5. The file either is closed immediately or it’s allowed to continue working with the renamed file (read, write, etc) and to close it later.

CBFS slightly modifies this algorithm:
1. The OnOpen callback is called (or OnCreate callback if the file is created).
2. The OnOpen callback is called for the destination folder.
--- until this moment algorithm is the same as Windows has---
3. The “rename or move” request comes to CBFS and…
a) CBFS (it’s high level code) calls the OnCleanup and OnClose callback for the file. So the file is closed completely on the "callback" level.
b) The OnRenameOrMove callback is called (for the completely closed file!!!).
c) The OnOpen callback is called for the renamed/moved file (the file has been reopened, but with the new name)
--- below the algorithm is the same as Windows has---
4. The OnCleanup and OnClose callbacks are called for the destination folder.
5. The OnCleanup and OnClose callbacks are called for the file. Although there can be other callbacks too (OnRead, OnWrite, etc).

Regarding your problem:
Quote
toddgleason wrote:
after the CbFsRenameOrMoveFile() call, the GENERIC_WRITE with ShareMode Read in the first CbFsOpenFile() call prevents the second CbFsOpenFile() call requesting DELETE access from functioning.

It seems such sequence of the file open requests was before the renaming. CBFS saved this information and after the renaming calls the OnOpen callbacks several times with the same access rights as before. Could you please check it?

Quote
toddgleason wrote:
What I don't understand is why these open/close calls are even needed, nor whether they are called by the OS, or by CBFS, and if there is a way to prevent these if they are not necessary, or else some improvement in how we handle them.

We have an idea to make a property in CBFS which will allow to optionally change such behavior to be the same as Windows has (i.e. without forced closing of the file before renaming). But now there is only such algorithm.
#33766
Posted: 06/24/2015 08:56:05
by Todd Gleason (Standard support level)
Joined: 09/11/2014
Posts: 21

Quote
It seems such sequence of the file open requests was before the renaming. CBFS saved this information and after the renaming calls the OnOpen callbacks several times with the same access rights as before. Could you please check it?


I don't know of a way to check this; I think we'll just have to take your word for it, as it's consistent with the logged messages.

How do you recommend we handle this case? Should we set a flag that rename just occurred, and in CbFsOpenFile() actually open with wide-open share modes instead of what was requested?
#33769
Posted: 06/24/2015 10:44:48
by Volodymyr Zinin (EldoS Corp.)

In your case the file was opened several times in parallel and CBFS for each opening called the OnOpen callback with the requested access rights and then saved these access rights. Then right before the renaming (before to call OnRenameOrMove callback) the OnClose callback is called for each opening occurred before. And right after the renaming the OnOpen callback is called again the same number of times, in the same sequence, and with the same access rights as before.
For some reason before the renaming the file was opened without the problem, but after the renaming the same openings (with the same parameters as before) fail. The reason of it can be either in CBFS or in your callbacks.
BTW what version of CBFS are you using?

Quote
toddgleason wrote:
How do you recommend we handle this case? Should we set a flag that rename just occurred, and in CbFsOpenFile() actually open with wide-open share modes instead of what was requested?

Actually CBFS itself checks access and share rights before the OnOpen callback is called and return the "access denied" error if necessary. However the access rights attributes are passed in the OnOpen callback. Sometimes they are needed. For example if the "backend" file is located on some shareable resource and can be opened not only from the CBFS callbacks. On the other hand some kernel mode components (antivirus drivers, etc), in order to workaround "access right" mechanism, open a file with minimal rights (even with "zero" rights) and then perform read/write of the file.

As a variant always allow to open files (as the Mapper sample does). Or check your OnOpen callbacks for access rights before and after renaming. Perhaps modify the Mapper sample in order the problem to be reproducible and give it to me.

Thanks.
#33770
Posted: 06/24/2015 11:43:10
by Todd Gleason (Standard support level)
Joined: 09/11/2014
Posts: 21

Quote
In your case the file was opened several times in parallel and CBFS for each opening called the OnOpen callback with the requested access rights and then saved these access rights. Then right before the renaming (before to call OnRenameOrMove callback) the OnClose callback is called for each opening occurred before. And right after the renaming the OnOpen callback is called again the same number of times, in the same sequence, and with the same access rights as before.
For some reason before the renaming the file was opened without the problem, but after the renaming the same openings (with the same parameters as before) fail. The reason of it can be either in CBFS or in your callbacks.
BTW what version of CBFS are you using?


We're using the latest build (5.1.159 from May).

Look again at the pattern of opens and closes. Before CbFsRenameOrMoveFile, the file is opened twice and closed twice, just like afterward, EXCEPT FOR ONE THING. The pattern is like this before:

Open
Cleanup, Close
Open
Cleanup, Close

After it's like this:

Open
Open
Cleanup, Close
Cleanup, Close

Does that make the problem more clear? The original set of permissions was also conflicting, but the serialized usage pattern made it not so. Afterward though, these are executed in parallel, with the file opened twice before closing twice.

With this behavior, if you honored the requested open permissions, the file mapper sample would fail as well in the parallel opens/closes after the rename. I'm reluctant to modify it to do this though as we have a lot of context management code to allow for multiple open handles, with reference counting on each.

Also, there's a chicken-and-egg issue around the "always allow to open files". To do this you have to demand all rights to the file, while opening all sharing options. This mode allows multiple clients on a single system, or multiple systems sharing the same file to stomp on one another and corrupt files. It's also not backwards compatible with a physical view of the data. So we don't attempt to work that way.
#33771
Posted: 06/24/2015 12:13:04
by Volodymyr Zinin (EldoS Corp.)

In your first post I see:
Code
CbFsOpenFile(): Y:\CBFSTest\TestFileMove_Src.txt (DesiredAccess: READ_ATTRIBUTES|SYNCHRONIZE|DELETE; FileAttributes: Archive, OpenReparsePoint; ShareMode: ReadWrite, Delete): start
CbFsOpenFile(): Y:\CBFSTest\ (DesiredAccess: ADD_FILE|SYNCHRONIZE; FileAttributes: Directory; ShareMode: ReadWrite): start
CbFsCleanupFile(): Y:\CBFSTest\TestFileMove_Src.txt): start
CbFsCloseFile(): Y:\CBFSTest\TestFileMove_Src.txt): start
CbFsCleanupFile(): Y:\CBFSTest\TestFileMove_Src.txt): start
CbFsCloseFile(): Y:\CBFSTest\TestFileMove_Src.txt): start
CbFsRenameOrMoveFile(): Y:\CBFSTest\TestFileMove_Src.txt: start
CbFsRenameOrMoveFile(): Y:\CBFSTest\TestFileMove_Src.txt: end
CbFsOpenFile(): Y:\CBFSTest\TestFileMove_Dst.txt (DesiredAccess: GENERIC_WRITE|READ_ATTRIBUTES; FileAttributes: Normal, OpenNoRecall, SequentialScan; ShareMode: Read): start
CbFsOpenFile(): Y:\CBFSTest\TestFileMove_Dst.txt (DesiredAccess: READ_ATTRIBUTES|SYNCHRONIZE|DELETE; FileAttributes: Archive, OpenReparsePoint; ShareMode: ReadWrite, Delete): start


I.e. the attributes of the OnOpen callbacks before are not the same as the attributes of the OnOpen callbacks after the renaming. Can you tell me how to reproduce such behavior? Or even better it would be nice if you reproduce it yourself, give me this log again with the Process Monitor logs (saved in the native format) obtained at the same time. Perhaps there is a bug in CBFS for it.

Thanks.
#33772
Posted: 06/24/2015 16:25:28
by Todd Gleason (Standard support level)
Joined: 09/11/2014
Posts: 21

You quoted the wrong section; that second open call before the rename is for the owning directory, which is why it has different permissions. Here's a shortened version without the irrelevant bits:

Code
CbFsOpenFile(): Y:\CBFSTest\TestFileMove_Src.txt (DesiredAccess: READ_ATTRIBUTES; FileAttributes: Archive, OpenReparsePoint; ShareMode: ReadWrite, Delete): start
CbFsCleanupFile(): Y:\CBFSTest\TestFileMove_Src.txt): start
CbFsCloseFile(): Y:\CBFSTest\TestFileMove_Src.txt): start
CbFsOpenFile(): Y:\CBFSTest\TestFileMove_Src.txt (DesiredAccess: READ_ATTRIBUTES|SYNCHRONIZE|DELETE; FileAttributes: Archive, OpenReparsePoint; ShareMode: ReadWrite, Delete): start
...
CbFsCleanupFile(): Y:\CBFSTest\TestFileMove_Src.txt): start
CbFsCloseFile(): Y:\CBFSTest\TestFileMove_Src.txt): start
CbFsCleanupFile(): Y:\CBFSTest\TestFileMove_Src.txt): start
CbFsCloseFile(): Y:\CBFSTest\TestFileMove_Src.txt): start
CbFsRenameOrMoveFile(): Y:\CBFSTest\TestFileMove_Src.txt: start
CbFsRenameOrMoveFile(): Y:\CBFSTest\TestFileMove_Src.txt: end
CbFsOpenFile(): Y:\CBFSTest\TestFileMove_Dst.txt (DesiredAccess: GENERIC_WRITE|READ_ATTRIBUTES; FileAttributes: Normal, OpenNoRecall, SequentialScan; ShareMode: Read): start
CbFsOpenFile(): Y:\CBFSTest\TestFileMove_Dst.txt (DesiredAccess: READ_ATTRIBUTES|SYNCHRONIZE|DELETE; FileAttributes: Archive, OpenReparsePoint; ShareMode: ReadWrite, Delete): start
...
CbFsCleanupFile(): Y:\CBFSTest\TestFileMove_Dst.txt): start
CbFsCloseFile(): Y:\CBFSTest\TestFileMove_Dst.txt): start


But you're right that the open calls afterward aren't quite like the open calls beforehand. It looks like CBFS isn't closing and reopening with like permissions in this case; I'm really not sure what it's doing now that I'm looking closer at it.

I can send my copy of the FileMapper that logs all this if you like; just please tell me how (no .zip files allowed here).

For now what I have done is add special-case logic to save a flag on rename, and then the next series of open calls open with wider sharing than requested.
#33787
Posted: 06/25/2015 08:41:34
by Volodymyr Zinin (EldoS Corp.)

Moved to HelpDesk for further investigation.
Also by EldoS: Solid File System
A virtual file system that offers a feature-rich storage for application documents and data with built-in compression and encryption.

Reply

Statistics

Topic viewed 3137 times

Number of guests: 2, registered members: 0, in total hidden: 0




|

Back to top

As of July 15, 2016 EldoS Corporation will operate as a division of /n software inc. For more information, please read the announcement.

Got it!