IStorage Commit Weirdness, Help!

Hi!

I’m having a problem in my FSD, trying to support StgOpenStorage. Basically I can create a store okay, but when I go to try and read it with another call to StgOpenStorage call I get the error (0x80030050, already exists). More specifically, I first create a store with STGM_TRANSACTED, STGM_READWRITE, STGM_SHARE_DENYWRITE and STGM_CREATE. The StgCreateStorageEx call works fine with these flags. But then when I try to get StgOpenStorage to work to open that already opened store, I get the error 0x80030050). This works on the FAT file system, but not in my own FSD.

I’ve spent quite a bit of time looking at the activity of StgOpenStorage. When STGM_TRANSACTED and STGM_READ is indicated for an existing open DocFile , it seems like there is a cache read for the existing data, then a bunch of lock ops and then another cache read of size 0x200 with data that starts out as 0xFD 0xFF 0xFF 0xFF… . Is this the two-phase commit process referred to here http:, where “a table is updated in the file using a single-sector operation to indicate that new data is to be used in place of the old”? When I try this on a regular FAT filesystem, filesys shows the second cache read to be the same as the first (after the StgmOpenStorage is called to open a store that is already opened). When I try this on my own FSD, the second cache read shows the 0xFD 0xFF 0xFF… for the first 512 bytes. The StgmOpenStorage call then fails with 0x80030050 (already exists). What might the StgOpenStrorage be looking at to determine if it can read the opened store, and why should it return the “already exists” error? Why would this first reference for data in 0xFD 0xFF 0xFF… for the first 0x200 bytes in cache happen for my FSD, and not for the FAT FSD (for example?). Please note, I see no additional actual writes that start with 0xFD 0xFF…, but what I see is that in the second cache read, this data mysteriously gets put there, which I interpret to perhaps be the “single-sector operation”. Thoughts?

Any help with this is greatly appreciated!!!

Best,

Steve

PS To recap, here is what happens in my FSD, and in FAT-pay attention to steps 4,12, and 18:

FAT My FSD
1) StgCreateStorageEx - returns OK, 1) StgCreateStorageEx - returns OK,
handle is left open (not closed before #2) handle is left open (not closed before #2)
2) StgOpenStorage call to open #1 2) StgOpenStorage call to open #1
3) IRP_MJ_CREATE returns OK 3) IRP_MJ_CREATE returns OK
4) IRP_MJ_READ first 0x200 bytes 4) IRP_MJ_READ first 0x200 bytes
buffer looks like 0xD0 CF 11 E0 A1… buffer looks like 0xD0 CF 11 D0 A1…
5) FileBasicInformation: Attrib ARCHIVE 5) FileBasicInformation: Attrib ARCHIVE
(I set the ARCHIVE bit cuz FAT does)
6) FASTIO_LOCK 6) FASTIO_LOCK
7) FASTIO_LOCK 7) FASTIO_LOCK
8) FASTIO_UNLOCK_SINGLE 8) FASTIO_UNLOCK_SINGLE
9) FASTIO_LOCK - 9) FASTIO_LOCK -
STATUS_LOCK_NOT_GRANTED STATUS_LOCK_NOT_GRANTED
10) 4 FASTIO_LOCKs 10) 4 FASTIO_LOCKs
11) 4 FASTIO_UNLOCK_SINGLEs 11) 4 FASTIO_UNLOCK_SINGLEs
12) IRP_MJ_READ with DATA the SAME 12) IRP_MJ_READ with DATA DIFFERENT!!!
as #4 Data starts with 0xFD 0xFF 0xFF
13) FASTIO_LOCK 13) FASTIO_LOCK
14) FASTIO_LOCK 14) FASTIO_LOCK
15) FASTIO_UNLOCK_SINGLE 15) FASTIO_UNLOCK_SINGLE
16) FileStandardInformation 16) FileStandardInformation
17) FileBasicInformation 17) FileBasicInformation
18) FastIORead - SAME as #4 and #12 18) IRP_MJ_READ, buffer starts with
“Root Entry”
19) IRP_MJ_READ offset 0x1000, all zeroes 19) IRP_MJ_READ, offset 0x1000, all zeroes
20) IRP_MJ_READ, offset 0x10000, EOF 20) IRP_MJ_READ, offset 0x10000, EOF
21) FASTIO_UNLOCK_SINGLE 21) FASTIO_UNLOCK_SINGLE</http:>

Did you try to create compound doc on FAT, copy it to your FSD and open it on it (and vice versa)?

Can you paste your test code here, so I can try it on our FSD?

-bg

Hi!

Here is the test code I use to generate this problem. I have no problem creating the doc initially, and then the first StgOpenStorage call returns a lock error (which is correct), and then the second StgOpenStorage call is the one that returns the 0x80030050 error, which is the Already Exists error.

I will go ahead and try to create a compound doc on FAT, and try to open it on my FSD.

Thanks for your help!

SCODE sc = ::StgCreateDocfile(L"X:\test123\test125.txt",
STGM_READWRITE|STGM_TRANSACTED|STGM_SHARE_DENY_WRITE|STGM_CREATE,
//STGM_CREATE | STGM_TRANSACTED | STGM_READWRITE | STGM_SHARE_DENY_NONE,
0, &lpStorage);

//SCODE sc = ::StgCreateStorageEx(L"X:\test123\test17.txt",
//STGM_READWRITE|STGM_TRANSACTED|STGM_SHARE_DENY_WRITE|STGM_CREATE,
//STGFMT_STORAGE, 0, NULL, NULL, IID_IStorage, (void**)&lpStorage);

// Use OLE compound files
// EnableCompoundFile();
// IStorage* pStgRoot;
// IStorage* pSubStg;
// if (::StgCreateDocfile(L"MyStore.stg",
// STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE, 0, &pStgRoot) == S_OK)
// {
// if (pStgRoot->CreateStorage(L"MySubstorageName",
// STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE,
// 0, 0, &pSubStg) == S_OK) {
// // Do something with pSubStg
// pSubStg->Release();
// }
// pStgRoot->Release();
// }
// TODO: add one-time construction code here
LPSTORAGE pStgRoot2 = NULL;
HRESULT result = 0x00, result2;
// doesn’t work without STGM_SHARE_EXCLUSIVE
result = ::StgOpenStorage(L"X:\test123\test125.txt", NULL,
STGM_READWRITE | STGM_TRANSACTED | STGM_SHARE_DENY_WRITE,
// STGM_READ | STGM_TRANSACTED,
// STGM_READ,
NULL, 0, &pStgRoot2);
if (result == S_OK)
{
ASSERT(pStgRoot2!= NULL);
pStgRoot2->Release();
}
else
{
result2 = ::StgOpenStorage(L"X:\test123\test125.txt", NULL,
STGM_READ | STGM_TRANSACTED,
NULL, 0, &pStgRoot2);
if (result2 == S_OK)
{
ASSERT(pStgRoot2!= NULL);
pStgRoot2->Release();
}
}

Seeing you code…

I cannot see lpStorage->Release() before StgOpenStorage(). So there can be interference between StgCreateDocfile() and StgOpenStorage(). Maybe I would try lpStorage->Commit() before lpStorage->Release(). Right now I have to finish some work. I’ll get to it in several hours.

-bg

Well it works fine on our FSD. There must be a bug in your FSD. Is your FSD ready for paging writes after cleanup? It should be. Paging write at the end of file should be truncated according current end of file. Size of the file is 0x600 (which is less than page). I can see 2 writes during creation of the file.

IRP_MJ_WRITE Offset 00000000-000005FF ToWrite 1 Written: 1
and after IRP_MJ_CLEANUP !TRUNCATED! paging write
IRP_MJ_WRITE Offset 00000000-00000000 ToWrite 1000 Written: 600

If I were you I would double check handling of offsets and file size. I can see different offsets in reads then you. First read when cache is initialized is the same
IRP_MJ_READ Offset 00000000-00000000 ToRead 200 Read 200 Data:D0 CF 11 E0
But after lock twiddling I can see different offsets in FASTIO reads
FASTIO_READ Offset 00000000-00000000 ToRead 200 Read 200 Data:D0 CF 11 E0
FASTIO_READ Offset 00000000-00000200 ToRead 200 Read 200 Data:FD FF FF FF
FASTIO_READ Offset 00000000-00000400 ToRead 200 Read 200 Data:“Root Entry”

Good Luck
-bg

Hi Bronislav!

I’m a bit confused about your last entry-the last 3 FASTIO_READS are exactly what I see when it FAILS-in other words, on FAT, when it works, each successive FASTIO_READ seems to read the identical data each time, not the “Root Entry” as you show there. But I will look to my offsets-no doubt they are a bit different because of the FCB/File Object 3 size field values. It is true for me that I go ahead and allow the full Write to complete, and it isn’t truncated by the current end of file, so I will check that as well.

Best,

Steve

Hi!

Well, the idea of having the last paging write writing beyond the EOF certainly sounded like a good idea, until I looked at the log and I see a IRP_MJ_SET_INFORMATION call that sets the FileEndOfFileInformation to be 0x4000, well above what the last paging write tries to write to. Interestingly, in my test run, I see 2 calls that set the FileEndOfFileInformation field-the first at 0x200, and the second at 0x4000. Is there another mechanism that sets EOF that I’m missing?

Thanks!

Hi Bronislav again!

Oh, and as an additional piece of weirdness, when I look at the FAT file system delayed write when running this code snippet, it also does the delayed paging write of a full 0x1000 bytes, and has the EOF at 0x4000, and doesn’t seem to trim it as you do. Very curious… how many FileEndOfFile calls do you get? I see 2, both in running this code snippet on FAT and our own FSD, the first of which sets EOF to be 0x200, and the second which sets it to 0x4000, so by the time the paging write happens, the EOF is at 0x4000 and not 0x200…

Best,

Steve

>Is there another mechanism that sets EOF that I’m missing?
Non paging write behind EOF. Paging write not comming from lazy writer.

Very curious… how many FileEndOfFile calls do you get?
I don’t get any. There are two FASTIO writes which I didn’t notice last time. So sequence during creation is following. You can see exactly the same result as I have against SMB mapped drive.
IRP_MJ_WRITE Offset 00000000-000005FF ToWrite 1 Written: 1
FASTIO_WRITE Offset 00000000-00000200 ToWrite 400 Written: 400
FASTIO_WRITE Offset 00000000-00000000 ToWrite 200 Written: 200
and after IRP_MJ_CLEANUP !TRUNCATED! paging write
IRP_MJ_WRITE Offset 00000000-00000000 ToWrite 1000 Written: 600

On Ntfs I can see four FileEndOfFile(),
IRP_MJ_SET_INFORMATION FileEndOfFileInformation EndOfFile: 00000000-00000200
IRP_MJ_SET_INFORMATION FileEndOfFileInformation EndOfFile: 00000000-00000200
IRP_MJ_SET_INFORMATION FileEndOfFileInformation EndOfFile: 00000000-00004000 (PAGING)
IRP_MJ_SET_INFORMATION FileEndOfFileInformation EndOfFile: 00000000-00000600

Now I am not sure if paging IRP_MJ_SET_INFORMATION should be ignored.

Here is my test code.

int _tmain(int argc, _TCHAR* argv)
{
USES_CONVERSION;
IStorage * lpStorage = NULL;
IStorage * pStgRoot2 = NULL;
LPCWSTR sFilename = NULL;

if (argc !=2) return 1;

CoInitialize(NULL);
sFilename = T2CW(argv[1]);

HRESULT hr = ::StgCreateDocfile(sFilename,
STGM_READWRITE|STGM_TRANSACTED|STGM_SHARE_DENY_WRITE|STGM_CREATE,
0, &lpStorage);

if (FAILED(hr))
{
_tprintf(_TEXT(“StgCreateDocfile() failed with 0x%08x”), hr);
}

if (SUCCEEDED(hr))
{
//hr = lpStorage->Commit(STGC_OVERWRITE);
lpStorage->Release();

hr = ::StgOpenStorage(sFilename, NULL,
STGM_READWRITE | STGM_TRANSACTED | STGM_SHARE_DENY_WRITE,
NULL, 0, &pStgRoot2);
if (FAILED(hr))
{
_tprintf(_TEXT(“StgOpenStorage(1) failed with 0x%08x\n”), hr);
}
}
if (SUCCEEDED(hr))
{
pStgRoot2->Release();
}
else
{
hr = ::StgOpenStorage(sFilename, NULL, STGM_READ | STGM_TRANSACTED,
NULL, 0, &pStgRoot2);
if (FAILED(hr))
{
_tprintf(_TEXT(“StgOpenStorage(2) failed with 0x%08x\n”), hr);
}

if (SUCCEEDED(hr))
{
pStgRoot2->Release();
}

}
CoUninitialize();
}

Good luck.
-bg