Any suggestions for how to handle a difference in file access and sharing handling between Wine (20050830) and WinXP? A program demonstrating the problem is attached below.
A 3rd party installer program for a VST plugin is calling CreateFile with dwDesiredAccess = 0x1f01ff and dwSharedMode = FILE_SHARE_WRITE. It then calls ReadFile, which fails in Wine (error 5) but succeeds in WinXP.
My "solution" (polite term) was to force GENERIC_READ|GENERIC_WRITE access in ntdll/NtCreateFile if the sharing type is FILE_SHARE_WRITE.
I have not been able to figure out from the header files what named constants the program used for dwDesiredAccess, so I hard coded it with the values the program used in my example.
But I did notice that FILE_ALL_ACCESS is a different value in Wine and my VC98 headers from DevStudio 6. In Wine it is: (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x1ff) In VC98: (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3ff) Is this a Wine bug?
The "access" and "sharing" parameters to CreateFile are making me feel stupid. I read and read and read the docs at http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/fs/c... and still can't really figure out what they are supposed to do! I am pretty sure that my hack wouldn't stand and would love to hear the right way to fix this problem.
Thanks... mo
#include <stdio.h> // printf #include <windows.h>
int main(int argc, char *argv[]) { if (argc < 2) { puts("usage: wine file-access-test.exe.so PATH"); puts("Tests the access used by the Ivory Library Tools program that doesn't work with wine."); return(1); }
HANDLE file = ::CreateFile(argv[1], 0x1f01ff, FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (file != INVALID_HANDLE_VALUE) { DWORD bytesRead; char bufr[32];
// passes in winxp; fails (error 5) in wine if (::ReadFile(file, bufr, sizeof(bufr), &bytesRead, NULL)) printf("Read %ld bytes\n", bytesRead); else printf("ReadFile error: %d\n", ::GetLastError()); ::CloseHandle(file); } else printf("CreateFile error: %d\n", ::GetLastError());
return(0); }
On 03 Oct 2005 11:20:16 -0700, Michael Ost most@museresearch.com wrote:
Any suggestions for how to handle a difference in file access and sharing handling between Wine (20050830) and WinXP? A program demonstrating the problem is attached below.
Bless your soul. It ought to be pretty easy for someone to convert that little program from C++ into C and add it to the Wine test suite. (Would you consider doing that?) That will make life easier for whoever fixes the bug. - Dan
On Mon, 2005-10-03 at 12:14, Dan Kegel wrote:
On 03 Oct 2005 11:20:16 -0700, Michael Ost most@museresearch.com wrote:
Any suggestions for how to handle a difference in file access and sharing handling between Wine (20050830) and WinXP? A program demonstrating the problem is attached below.
Bless your soul. It ought to be pretty easy for someone to convert that little program from C++ into C and add it to the Wine test suite. (Would you consider doing that?) That will make life easier for whoever fixes the bug.
Sure, but I don't know where the tests are. Somehow I haven't run across that yet. Can you point me?
- mo
On 03 Oct 2005 20:59:13 -0700, Michael Ost most@museresearch.com wrote:
Bless your soul. It ought to be pretty easy for someone to convert that little program from C++ into C and add it to the Wine test suite. (Would you consider doing that?)
Sure, but I don't know where the tests are. Somehow I haven't run across that yet. Can you point me?
$ grep -l 'open(' dlls/*/tests/*.c dlls/kernel/tests/file.c dlls/msvcrt/tests/file.c dlls/msvcrt/tests/printf.c
Looking at the three, I'd say dlls/msvcrt/tests/file.c. To build a standalone Windows executable of that file, do
cd dlls\msvcrt\tests cl -DSTANDALONE -D_X86_ -I../../../include file.c
or, if dimi's patch isn't in yet, you need two more defines: cl -DSTANDALONE -D_X86_ -D__i386__ -Dinline=__inline -I../../../include file.c
Then you can run the same executable on both windows and linux. I'd build and run the test as is before changing it, just to make sure it works.
On October 3, 2005 11:20 am, Michael Ost wrote:
Any suggestions for how to handle a difference in file access and sharing handling between Wine (20050830) and WinXP? A program demonstrating the problem is attached below.
A 3rd party installer program for a VST plugin is calling CreateFile with dwDesiredAccess = 0x1f01ff and dwSharedMode = FILE_SHARE_WRITE. It then calls ReadFile, which fails in Wine (error 5) but succeeds in WinXP.
The "access" and "sharing" parameters to CreateFile are making me feel stupid. I read and read and read the docs at http://msdn.microsoft.com/library/default.asp?url=/library/en- us/fileio/fs/createfile.asp and still can't really figure out what they are supposed to do! I am pretty sure that my hack wouldn't stand and would love to hear the right way to fix this problem.
Thanks... mo
I think that maybe you/we are getting confused as a result of Microsoft trying to simplify the language and actually making it worse. I think the problem is with the FILE_SHARE_... descriptions. (There seems to be a disconnect between the designers and the linguists, especially when negatives become involved)
In the old days the description was possibly worse: "FILE_SHARE_READ - Subsequent open operations on the object will succeed only if read access is requested".
I think that the linguists are trying to put a positive spin on what is actually a negative construct.
As far as I am concerned this is what is meant.
"FILE_SHARE_READ - Enables subsequent open operations on an object to request read access. If this flag is not specified then any subsequent open operations specifying read access will fail. If this flag is specified then any subsequent operations specifying read access may succeed or fail, depening on other conditions".
Basically it all dates back to the old days of DOS. The sharing was to control how a file was shared; the first opening of the file is constraining what else may be done. By specifying FILE_SHARE_READ the caller is permitting other calls to open the file for reading.
We could (INCORRECTLY) read the bad current text to mean "During this call if the file is opened for reading but the FILE_SHARE_READ is not set then the call will fail."
Anyway, I'll have a quick look.
"Michael Ost" most@museresearch.com wrote:
A 3rd party installer program for a VST plugin is calling CreateFile with dwDesiredAccess = 0x1f01ff and dwSharedMode = FILE_SHARE_WRITE. It then calls ReadFile, which fails in Wine (error 5) but succeeds in WinXP.
My "solution" (polite term) was to force GENERIC_READ|GENERIC_WRITE access in ntdll/NtCreateFile if the sharing type is FILE_SHARE_WRITE.
Most likely sharing mode has nothing to do with access rights. The problem is that the app doesn't specify neither of GENERIC_xxxx flags. But it does specify STANDARD_RIGHTS_ALL == (DELETE|READ_CONTROL|WRITE_DAC|WRITE_OWNER|SYNCHRONIZE). It appears that Windows treats GENERIC_xxxx rights as an addition to the STANDARD_RIGHTS_xxx flags, and missing GENERIC_xxxx rights are normally ignored.
I have not been able to figure out from the header files what named constants the program used for dwDesiredAccess, so I hard coded it with the values the program used in my example.
But I did notice that FILE_ALL_ACCESS is a different value in Wine and my VC98 headers from DevStudio 6. In Wine it is: (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x1ff) In VC98: (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3ff) Is this a Wine bug?
Please send a patch for this.
Your test app needs to be extended to verify who is responsible for handling the dwDesiredAccess: CreateFileW ot NtCreateFile (I think it's the latter one, but it needs to be tested).
On Mon, 2005-10-03 at 21:08, Dmitry Timoshkov wrote:
But I did notice that FILE_ALL_ACCESS is a different value in Wine and my VC98 headers from DevStudio 6. In Wine it is: (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x1ff) In VC98: (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3ff) Is this a Wine bug?
Please send a patch for this.
--- wine-20050930/include/winnt.h 2005-09-22 03:58:04.000000000 -0700 +++ wine-20050930.new/include/winnt.h 2005-10-03 21:14:04.000000000 -0700 @@ -3509,7 +3509,7 @@ #define FILE_DELETE_CHILD 0x0040 /* directory */ #define FILE_READ_ATTRIBUTES 0x0080 /* all */ #define FILE_WRITE_ATTRIBUTES 0x0100 /* all */ -#define FILE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x1ff) +#define FILE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3ff)
#define FILE_GENERIC_READ (STANDARD_RIGHTS_READ | FILE_READ_DATA | \ FILE_READ_ATTRIBUTES | FILE_READ_EA | \
Or did you mean post it to wine-patches? I am totally new to wine-patches, but I can give it a go... mo
"Michael Ost" most@museresearch.com wrote:
Or did you mean post it to wine-patches? I am totally new to wine-patches, but I can give it a go... mo
Yes, wine-patches is what you need. Do not forget a changelog description for your change.
"Dan Kegel" daniel.r.kegel@gmail.com wrote:
$ grep -l 'open(' dlls/*/tests/*.c dlls/kernel/tests/file.c dlls/msvcrt/tests/file.c dlls/msvcrt/tests/printf.c
Looking at the three, I'd say dlls/msvcrt/tests/file.c.
It's dlls/kernel/tests/file.c, test_CreateFileA/W.
Monday, October 3, 2005, 10:08:24 PM, Dmitry Timoshkov wrote:
"Michael Ost" most@museresearch.com wrote:
A 3rd party installer program for a VST plugin is calling CreateFile with dwDesiredAccess = 0x1f01ff and dwSharedMode = FILE_SHARE_WRITE. It then calls ReadFile, which fails in Wine (error 5) but succeeds in WinXP.
My "solution" (polite term) was to force GENERIC_READ|GENERIC_WRITE access in ntdll/NtCreateFile if the sharing type is FILE_SHARE_WRITE.
Most likely sharing mode has nothing to do with access rights. The problem is that the app doesn't specify neither of GENERIC_xxxx flags. But it does specify STANDARD_RIGHTS_ALL == (DELETE|READ_CONTROL|WRITE_DAC|WRITE_OWNER|SYNCHRONIZE). It appears that Windows treats GENERIC_xxxx rights as an addition to the STANDARD_RIGHTS_xxx flags, and missing GENERIC_xxxx rights are normally ignored.
It is an additional flags to the rest of the file flags because they are transferred all the way to the kernel. And being translated into specific access rights by an object manager according to the object type. It has array of the generic attributes mappings.
Vitaliy
"Vitaliy Margolen" wine-devel@kievinfo.com wrote:
It is an additional flags to the rest of the file flags because they are transferred all the way to the kernel. And being translated into specific access rights by an object manager according to the object type. It has array of the generic attributes mappings.
Does the ntdll export RtlMapGenericMask have anything to do with mapping GENERIC_xxxx flags into STANDARD_RIGHTS_xxxx? Is there any information regarding that?
Monday, October 3, 2005, 11:21:37 PM, Dmitry Timoshkov wrote:
"Vitaliy Margolen" wine-devel@kievinfo.com wrote:
It is an additional flags to the rest of the file flags because they are transferred all the way to the kernel. And being translated into specific access rights by an object manager according to the object type. It has array of the generic attributes mappings.
Does the ntdll export RtlMapGenericMask have anything to do with mapping GENERIC_xxxx flags into STANDARD_RIGHTS_xxxx? Is there any information regarding that?
Hmm, I don't know nothing about that one. I did some reading about object manager and on of the functions of it is to translate those generic access flags into appropriate full attributes. What interesting is that it's not per object but per object type. So all files (real files, named pipes, etc) have the same mapping. I'm not sure how far should we go with this. But I have a big work cut out for me fixing wine's object manager.
Vitaliy
Vitaliy Margolen wrote:
Monday, October 3, 2005, 11:21:37 PM, Dmitry Timoshkov wrote:
"Vitaliy Margolen" wine-devel@kievinfo.com wrote:
It is an additional flags to the rest of the file flags because they are transferred all the way to the kernel. And being translated into specific access rights by an object manager according to the object type. It has array of the generic attributes mappings.
Does the ntdll export RtlMapGenericMask have anything to do with mapping GENERIC_xxxx flags into STANDARD_RIGHTS_xxxx? Is there any information regarding that?
Hmm, I don't know nothing about that one. I did some reading about object manager and on of the functions of it is to translate those generic access flags into appropriate full attributes. What interesting is that it's not per object but per object type. So all files (real files, named pipes, etc) have the same mapping. I'm not sure how far should we go with this. But I have a big work cut out for me fixing wine's object manager.
Basically I think that GENERIC_READ as to be mapped so a set of lower level defines (STANDARD_RIGHTS_READ, FILE_READ_DATA, FILE_READ_ATTRIBUTES, FILE_READ_EA, and SYNCHRONIZE), and actual permission to read the file is FILE_READ_DATA, not GENERIC_READ as we incorrectly do) A+
Dmitry Timoshkov wrote:
"Vitaliy Margolen" wine-devel@kievinfo.com wrote:
It is an additional flags to the rest of the file flags because they are transferred all the way to the kernel. And being translated into specific access rights by an object manager according to the object type. It has array of the generic attributes mappings.
Does the ntdll export RtlMapGenericMask have anything to do with mapping GENERIC_xxxx flags into STANDARD_RIGHTS_xxxx? Is there any information regarding that?
Yes, it is exactly that. There is a port of that function into wineserver in server/token.c called map_generic_mask that I used for the purpose of mapping generic access rights in the token functions. The problem with translating from generic access rights is that they don't map onto Unix access rights very well. I suspect that the best solution is to request read access if any of the NT read rights are requested and similarly for the write rights.
On October 5, 2005 03:56 pm, Robert Shearman wrote:
Dmitry Timoshkov wrote:
"Vitaliy Margolen" wine-devel@kievinfo.com wrote:
It is an additional flags to the rest of the file flags because they are transferred all the way to the kernel. And being translated into specific access rights by an object manager according to the object type. It has array of the generic attributes mappings.
Does the ntdll export RtlMapGenericMask have anything to do with mapping GENERIC_xxxx flags into STANDARD_RIGHTS_xxxx? Is there any information regarding that?
Yes, it is exactly that. There is a port of that function into wineserver in server/token.c called map_generic_mask that I used for the purpose of mapping generic access rights in the token functions. The problem with translating from generic access rights is that they don't map onto Unix access rights very well. I suspect that the best solution is to request read access if any of the NT read rights are requested and similarly for the write rights.
Except that is largely irrelevant in this particular case. It's the mapping from GENERIC to <OBJECT>_... (e.g. FILE_) that is relevant, and as Vitaliy pointed out, that is in the object area.
Bill Medland wrote:
On October 5, 2005 03:56 pm, Robert Shearman wrote:
There is a port of that function into
wineserver in server/token.c called map_generic_mask that I used for the purpose of mapping generic access rights in the token functions. The problem with translating from generic access rights is that they don't map onto Unix access rights very well. I suspect that the best solution is to request read access if any of the NT read rights are requested and similarly for the write rights.
Except that is largely irrelevant in this particular case. It's the mapping from GENERIC to <OBJECT>_... (e.g. FILE_) that is relevant, and as Vitaliy pointed out, that is in the object area.
It is not irrelevant. Yes, as Vitaliy pointed out the architecture needs to be changed so that all of the objects have a generic mapping and that mapping is done automatically, but we are in code freeze and I don't think those sorts of changes are acceptable. I think that adding in a mapping for the file object only in the wineserver is acceptable. The one line can be abstracted out later.
Just to make it clear, the question about NT rights mapping to Unix rights matters wherever the mapping is done.
Wednesday, October 5, 2005, 10:57:48 PM, Robert Shearman wrote:
Bill Medland wrote:
On October 5, 2005 03:56 pm, Robert Shearman wrote:
There is a port of that function into
wineserver in server/token.c called map_generic_mask that I used for the purpose of mapping generic access rights in the token functions. The problem with translating from generic access rights is that they don't map onto Unix access rights very well. I suspect that the best solution is to request read access if any of the NT read rights are requested and similarly for the write rights.
Except that is largely irrelevant in this particular case. It's the mapping from GENERIC to <OBJECT>_... (e.g. FILE_) that is relevant, and as Vitaliy pointed out, that is in the object area.
It is not irrelevant. Yes, as Vitaliy pointed out the architecture needs to be changed so that all of the objects have a generic mapping and that mapping is done automatically, but we are in code freeze and I don't think those sorts of changes are acceptable. I think that adding in a mapping for the file object only in the wineserver is acceptable. The one line can be abstracted out later.
Just to make it clear, the question about NT rights mapping to Unix rights matters wherever the mapping is done.
I think this is the way it might look like. It's a hack and not the real solution.
WARNING: I haven't tested this beyond notepad so it might not work at all or have some major problems. For all I know it might wipe out your entire hard drive especially if you running wine as a root. <g>
Vitaliy
On October 5, 2005 11:10 pm, Vitaliy Margolen wrote:
I think this is the way it might look like. It's a hack and not the real solution.
WARNING: I haven't tested this beyond notepad so it might not work at all or have some major problems. For all I know it might wipe out your entire hard drive especially if you running wine as a root. <g>
Vitaliy
Looks good to me. I would suggest also adding a comment as to why it is being done there rather than down in the object area, just so we don't forget.
The only remaining issue for Michael Ost's particular problem is to change that GENERIC_READ in ReadFile to FILE_READ_DATA (but not until this fix is in place).
On Mon, 2005-10-03 at 21:08, Dmitry Timoshkov wrote:
"Michael Ost" most@museresearch.com wrote:
My "solution" (polite term) was to force GENERIC_READ|GENERIC_WRITE access in ntdll/NtCreateFile if the sharing type is FILE_SHARE_WRITE.
Most likely sharing mode has nothing to do with access rights. The problem is that the app doesn't specify neither of GENERIC_xxxx flags. But it does specify STANDARD_RIGHTS_ALL == (DELETE|READ_CONTROL|WRITE_DAC|WRITE_OWNER|SYNCHRONIZE). It appears that Windows treats GENERIC_xxxx rights as an addition to the STANDARD_RIGHTS_xxx flags, and missing GENERIC_xxxx rights are normally ignored.
While I wait for a real solution, I need to hack wine 20050930 to get this app running. I tweaked my patch based on your feedback (thanks!) and included it below.
Does this patch look dangerous in any way to those of you who know your way around this code? It's done in NtCreateFile after a bunch of non-file types (like mail slots, etc) are handled.
--- wine-20050930/dlls/ntdll/file.c 2005-09-26 04:02:45.000000000 -0700 +++ wine-20050930.new/dlls/ntdll/file.c 2005-10-05 15:16:18.000000000 -0700 @@ -206,6 +206,14 @@
if (io->u.Status == STATUS_SUCCESS) { + /* hack for Ivory Library Installer - force GENERIC_xxx access on */ + if ((access & STANDARD_RIGHTS_ALL) == STANDARD_RIGHTS_ALL) { + if ((access & (GENERIC_READ|GENERIC_WRITE)) == 0) { + FIXME("Forcing GENERIC_xxx access\n"); + access |= (GENERIC_READ|GENERIC_WRITE); + } + } + SERVER_START_REQ( create_file ) { req->access = access;
Thanks... mo
"Michael Ost" most@museresearch.com wrote:
Does this patch look dangerous in any way to those of you who know your way around this code? It's done in NtCreateFile after a bunch of non-file types (like mail slots, etc) are handled.
While this patch may work for you it's certainly not correct. Access rights mapping should be performed by wineserver, see Rob's answer in this thread.
On Wed, 2005-10-05 at 20:05, Dmitry Timoshkov wrote:
"Michael Ost" most@museresearch.com wrote:
Does this patch look dangerous in any way to those of you who know your way around this code? It's done in NtCreateFile after a bunch of non-file types (like mail slots, etc) are handled.
While this patch may work for you it's certainly not correct. Access rights mapping should be performed by wineserver, see Rob's answer in this thread.
Right. I understand. I just wanted to avoid doing an ugly hack that causes unexpected problems elsewhere. I am not strong enough with Wine to _really_ fix the problem, but I need to do something temporary.
- mo