Try to implement the OF_SHARE_XXX options.
Move the mode translations to functions.
This commit is contained in:
parent
75175345ae
commit
e6b5e38bbc
349
files/file.c
349
files/file.c
|
@ -88,6 +88,7 @@ HFILE32 FILE_Alloc( FILE_OBJECT **file )
|
||||||
(*file)->unix_name = NULL;
|
(*file)->unix_name = NULL;
|
||||||
(*file)->type = FILE_TYPE_DISK;
|
(*file)->type = FILE_TYPE_DISK;
|
||||||
(*file)->pos = 0;
|
(*file)->pos = 0;
|
||||||
|
(*file)->mode = 0;
|
||||||
|
|
||||||
handle = HANDLE_Alloc( PROCESS_Current(), &(*file)->header,
|
handle = HANDLE_Alloc( PROCESS_Current(), &(*file)->header,
|
||||||
FILE_ALL_ACCESS | GENERIC_READ |
|
FILE_ALL_ACCESS | GENERIC_READ |
|
||||||
|
@ -228,6 +229,259 @@ int FILE_GetUnixHandle( HFILE32 hFile )
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* FILE_UnixToDosMode
|
||||||
|
*
|
||||||
|
* PARAMS
|
||||||
|
* unixmode[I]
|
||||||
|
* RETURNS
|
||||||
|
* dosmode
|
||||||
|
*/
|
||||||
|
static int FILE_UnixToDosMode(int unixMode)
|
||||||
|
{
|
||||||
|
int dosMode;
|
||||||
|
switch(unixMode & 3)
|
||||||
|
{
|
||||||
|
case O_WRONLY:
|
||||||
|
dosMode = OF_WRITE;
|
||||||
|
break;
|
||||||
|
case O_RDWR:
|
||||||
|
dosMode =OF_READWRITE;
|
||||||
|
break;
|
||||||
|
case O_RDONLY:
|
||||||
|
default:
|
||||||
|
dosMode = OF_READ;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return dosMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* FILE_DOSToUnixMode
|
||||||
|
*
|
||||||
|
* PARAMS
|
||||||
|
* dosMode[I]
|
||||||
|
* RETURNS
|
||||||
|
* unixmode
|
||||||
|
*/
|
||||||
|
static int FILE_DOSToUnixMode(int dosMode)
|
||||||
|
{
|
||||||
|
int unixMode;
|
||||||
|
switch(dosMode & 3)
|
||||||
|
{
|
||||||
|
case OF_WRITE:
|
||||||
|
unixMode = O_WRONLY; break;
|
||||||
|
case OF_READWRITE:
|
||||||
|
unixMode = O_RDWR; break;
|
||||||
|
case OF_READ:
|
||||||
|
default:
|
||||||
|
unixMode = O_RDONLY; break;
|
||||||
|
}
|
||||||
|
return unixMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* FILE_ShareDeny
|
||||||
|
*
|
||||||
|
* PARAMS
|
||||||
|
* oldmode[I] mode how file was first opened
|
||||||
|
* mode[I] mode how the file should get opened
|
||||||
|
* RETURNS
|
||||||
|
* TRUE: deny open
|
||||||
|
* FALSE: allow open
|
||||||
|
*
|
||||||
|
* Look what we have to do with the given SHARE modes
|
||||||
|
*
|
||||||
|
* Ralph Brown's interrupt list gives following explication, I guess
|
||||||
|
* the same holds for Windows, DENY ALL should be OF_SHARE_COMPAT
|
||||||
|
*
|
||||||
|
* FIXME: Validate this function
|
||||||
|
========from Ralph Brown's list =========
|
||||||
|
(Table 0750)
|
||||||
|
Values of DOS file sharing behavior:
|
||||||
|
| Second and subsequent Opens
|
||||||
|
First |Compat Deny Deny Deny Deny
|
||||||
|
Open | All Write Read None
|
||||||
|
|R W RW R W RW R W RW R W RW R W RW
|
||||||
|
- - - - -| - - - - - - - - - - - - - - - - -
|
||||||
|
Compat R |Y Y Y N N N 1 N N N N N 1 N N
|
||||||
|
W |Y Y Y N N N N N N N N N N N N
|
||||||
|
RW|Y Y Y N N N N N N N N N N N N
|
||||||
|
- - - - -|
|
||||||
|
Deny R |C C C N N N N N N N N N N N N
|
||||||
|
All W |C C C N N N N N N N N N N N N
|
||||||
|
RW|C C C N N N N N N N N N N N N
|
||||||
|
- - - - -|
|
||||||
|
Deny R |2 C C N N N Y N N N N N Y N N
|
||||||
|
Write W |C C C N N N N N N Y N N Y N N
|
||||||
|
RW|C C C N N N N N N N N N Y N N
|
||||||
|
- - - - -|
|
||||||
|
Deny R |C C C N N N N Y N N N N N Y N
|
||||||
|
Read W |C C C N N N N N N N Y N N Y N
|
||||||
|
RW|C C C N N N N N N N N N N Y N
|
||||||
|
- - - - -|
|
||||||
|
Deny R |2 C C N N N Y Y Y N N N Y Y Y
|
||||||
|
None W |C C C N N N N N N Y Y Y Y Y Y
|
||||||
|
RW|C C C N N N N N N N N N Y Y Y
|
||||||
|
Legend: Y = open succeeds, N = open fails with error code 05h
|
||||||
|
C = open fails, INT 24 generated
|
||||||
|
1 = open succeeds if file read-only, else fails with error code
|
||||||
|
2 = open succeeds if file read-only, else fails with INT 24
|
||||||
|
========end of description from Ralph Brown's List =====
|
||||||
|
For every "Y" in the table we return FALSE
|
||||||
|
For every "N" we set the DOS_ERROR and return TRUE
|
||||||
|
For all other cases we barf,set the DOS_ERROR and return TRUE
|
||||||
|
|
||||||
|
*/
|
||||||
|
static BOOL32 FILE_ShareDeny( int mode, int oldmode)
|
||||||
|
{
|
||||||
|
int oldsharemode = oldmode & 0x70;
|
||||||
|
int sharemode = mode & 0x70;
|
||||||
|
int oldopenmode = oldmode & 3;
|
||||||
|
int openmode = mode & 3;
|
||||||
|
|
||||||
|
switch (oldsharemode)
|
||||||
|
{
|
||||||
|
case OF_SHARE_COMPAT:
|
||||||
|
if (sharemode == OF_SHARE_COMPAT) return FALSE;
|
||||||
|
if (openmode == OF_READ) goto test_ro_err05 ;
|
||||||
|
goto fail_error05;
|
||||||
|
case OF_SHARE_EXCLUSIVE:
|
||||||
|
if (sharemode == OF_SHARE_COMPAT) goto fail_int24;
|
||||||
|
goto fail_error05;
|
||||||
|
case OF_SHARE_DENY_WRITE:
|
||||||
|
if (openmode != OF_READ)
|
||||||
|
{
|
||||||
|
if (sharemode == OF_SHARE_COMPAT) goto fail_int24;
|
||||||
|
goto fail_error05;
|
||||||
|
}
|
||||||
|
switch (sharemode)
|
||||||
|
{
|
||||||
|
case OF_SHARE_COMPAT:
|
||||||
|
if (oldopenmode == OF_READ) goto test_ro_int24 ;
|
||||||
|
goto fail_int24;
|
||||||
|
case OF_SHARE_DENY_NONE :
|
||||||
|
return FALSE;
|
||||||
|
case OF_SHARE_DENY_WRITE :
|
||||||
|
if (oldopenmode == OF_READ) return FALSE;
|
||||||
|
case OF_SHARE_DENY_READ :
|
||||||
|
if (oldopenmode == OF_WRITE) return FALSE;
|
||||||
|
case OF_SHARE_EXCLUSIVE:
|
||||||
|
default:
|
||||||
|
goto fail_error05;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OF_SHARE_DENY_READ:
|
||||||
|
if (openmode != OF_WRITE)
|
||||||
|
{
|
||||||
|
if (sharemode == OF_SHARE_COMPAT) goto fail_int24;
|
||||||
|
goto fail_error05;
|
||||||
|
}
|
||||||
|
switch (sharemode)
|
||||||
|
{
|
||||||
|
case OF_SHARE_COMPAT:
|
||||||
|
goto fail_int24;
|
||||||
|
case OF_SHARE_DENY_NONE :
|
||||||
|
return FALSE;
|
||||||
|
case OF_SHARE_DENY_WRITE :
|
||||||
|
if (oldopenmode == OF_READ) return FALSE;
|
||||||
|
case OF_SHARE_DENY_READ :
|
||||||
|
if (oldopenmode == OF_WRITE) return FALSE;
|
||||||
|
case OF_SHARE_EXCLUSIVE:
|
||||||
|
default:
|
||||||
|
goto fail_error05;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OF_SHARE_DENY_NONE:
|
||||||
|
switch (sharemode)
|
||||||
|
{
|
||||||
|
case OF_SHARE_COMPAT:
|
||||||
|
goto fail_int24;
|
||||||
|
case OF_SHARE_DENY_NONE :
|
||||||
|
return FALSE;
|
||||||
|
case OF_SHARE_DENY_WRITE :
|
||||||
|
if (oldopenmode == OF_READ) return FALSE;
|
||||||
|
case OF_SHARE_DENY_READ :
|
||||||
|
if (oldopenmode == OF_WRITE) return FALSE;
|
||||||
|
case OF_SHARE_EXCLUSIVE:
|
||||||
|
default:
|
||||||
|
goto fail_error05;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
ERR(file,"unknown mode\n");
|
||||||
|
}
|
||||||
|
ERR(file,"shouldn't happen\n");
|
||||||
|
ERR(file,"Please report to bon@elektron.ikp.physik.tu-darmstadt.de\n");
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
test_ro_int24:
|
||||||
|
FIXME(file,"test if file is RO missing\n");
|
||||||
|
/* Fall through */
|
||||||
|
fail_int24:
|
||||||
|
FIXME(file,"generate INT24 missing\n");
|
||||||
|
/* Is this the right error? */
|
||||||
|
DOS_ERROR( ER_AccessDenied, EC_AccessDenied, SA_Abort, EL_Disk );
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
test_ro_err05:
|
||||||
|
FIXME(file,"test if file is RO missing\n");
|
||||||
|
/* fall through */
|
||||||
|
fail_error05:
|
||||||
|
DOS_ERROR( ER_AccessDenied, EC_AccessDenied, SA_Abort, EL_Disk );
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Look if the File is in Use For the OF_SHARE_XXX options
|
||||||
|
*
|
||||||
|
* PARAMS
|
||||||
|
* name [I]: full unix name of the file that should be opened
|
||||||
|
* mode [O]: mode how the file was first opened
|
||||||
|
* RETURNS
|
||||||
|
* TRUE if the file was opened before
|
||||||
|
* FALSE if we open the file exclusive for this process
|
||||||
|
*
|
||||||
|
* Scope of the files we look for is only the current pdb
|
||||||
|
* Could we use /proc/self/? on Linux for this?
|
||||||
|
* Should we use flock? Should we create another structure?
|
||||||
|
* Searching through all files seem quite expensive for me, but
|
||||||
|
* I don't see any other way.
|
||||||
|
*
|
||||||
|
* FIXME: Extend scope to the whole Wine process
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static BOOL32 FILE_InUse(char * name, int * mode)
|
||||||
|
{
|
||||||
|
FILE_OBJECT *file;
|
||||||
|
int i;
|
||||||
|
HGLOBAL16 hPDB = GetCurrentPDB();
|
||||||
|
PDB *pdb = (PDB *)GlobalLock16( hPDB );
|
||||||
|
|
||||||
|
if (!pdb) return 0;
|
||||||
|
for (i=0;i<pdb->nbFiles;i++)
|
||||||
|
{
|
||||||
|
file =FILE_GetFile( (HFILE32) i);
|
||||||
|
if(file)
|
||||||
|
{
|
||||||
|
if(file->unix_name)
|
||||||
|
{
|
||||||
|
TRACE(file,"got %s at %d\n",file->unix_name,i);
|
||||||
|
if(!lstrcmp32A(file->unix_name,name))
|
||||||
|
{
|
||||||
|
*mode = file->mode;
|
||||||
|
FILE_ReleaseFile(file);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
FILE_ReleaseFile(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* FILE_SetDosError
|
* FILE_SetDosError
|
||||||
|
@ -354,6 +608,11 @@ HFILE32 FILE_Open( LPCSTR path, INT32 mode )
|
||||||
{
|
{
|
||||||
DOS_FULL_NAME full_name;
|
DOS_FULL_NAME full_name;
|
||||||
const char *unixName;
|
const char *unixName;
|
||||||
|
int oldMode, dosMode; /* FIXME: Do we really need unixmode as argument for
|
||||||
|
FILE_Open */
|
||||||
|
FILE_OBJECT *file;
|
||||||
|
HFILE32 hFileRet;
|
||||||
|
BOOL32 fileInUse = FALSE;
|
||||||
|
|
||||||
TRACE(file, "'%s' %04x\n", path, mode );
|
TRACE(file, "'%s' %04x\n", path, mode );
|
||||||
|
|
||||||
|
@ -380,7 +639,23 @@ HFILE32 FILE_Open( LPCSTR path, INT32 mode )
|
||||||
return HFILE_ERROR32;
|
return HFILE_ERROR32;
|
||||||
unixName = full_name.long_name;
|
unixName = full_name.long_name;
|
||||||
}
|
}
|
||||||
return FILE_OpenUnixFile( unixName, mode );
|
|
||||||
|
dosMode = FILE_UnixToDosMode(mode);
|
||||||
|
fileInUse = FILE_InUse(full_name.long_name,&oldMode);
|
||||||
|
if(fileInUse)
|
||||||
|
{
|
||||||
|
TRACE(file, "found another instance with mode 0x%02x\n",oldMode&0x70);
|
||||||
|
if (FILE_ShareDeny(dosMode,oldMode)) return HFILE_ERROR32;
|
||||||
|
}
|
||||||
|
hFileRet = FILE_OpenUnixFile( unixName, mode );
|
||||||
|
/* we need to save the mode, but only if it is not in use yet*/
|
||||||
|
if ((hFileRet) && (!fileInUse) && ((file =FILE_GetFile(hFileRet))))
|
||||||
|
{
|
||||||
|
file->mode=dosMode;
|
||||||
|
FILE_ReleaseFile(file);
|
||||||
|
}
|
||||||
|
return hFileRet;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -392,6 +667,9 @@ static HFILE32 FILE_Create( LPCSTR path, int mode, int unique )
|
||||||
HFILE32 handle;
|
HFILE32 handle;
|
||||||
FILE_OBJECT *file;
|
FILE_OBJECT *file;
|
||||||
DOS_FULL_NAME full_name;
|
DOS_FULL_NAME full_name;
|
||||||
|
BOOL32 fileInUse = FALSE;
|
||||||
|
int oldMode,dosMode; /* FIXME: Do we really need unixmode as argument for
|
||||||
|
FILE_Create */;
|
||||||
|
|
||||||
TRACE(file, "'%s' %04x %d\n", path, mode, unique );
|
TRACE(file, "'%s' %04x %d\n", path, mode, unique );
|
||||||
|
|
||||||
|
@ -412,6 +690,15 @@ static HFILE32 FILE_Create( LPCSTR path, int mode, int unique )
|
||||||
CloseHandle( handle );
|
CloseHandle( handle );
|
||||||
return INVALID_HANDLE_VALUE32;
|
return INVALID_HANDLE_VALUE32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dosMode = FILE_UnixToDosMode(mode);
|
||||||
|
fileInUse = FILE_InUse(full_name.long_name,&oldMode);
|
||||||
|
if(fileInUse)
|
||||||
|
{
|
||||||
|
TRACE(file, "found another instance with mode 0x%02x\n",oldMode&0x70);
|
||||||
|
if (FILE_ShareDeny(dosMode,oldMode)) return INVALID_HANDLE_VALUE32;
|
||||||
|
}
|
||||||
|
|
||||||
if ((file->unix_handle = open( full_name.long_name,
|
if ((file->unix_handle = open( full_name.long_name,
|
||||||
O_CREAT | O_TRUNC | O_RDWR | (unique ? O_EXCL : 0),
|
O_CREAT | O_TRUNC | O_RDWR | (unique ? O_EXCL : 0),
|
||||||
mode )) == -1)
|
mode )) == -1)
|
||||||
|
@ -424,6 +711,7 @@ static HFILE32 FILE_Create( LPCSTR path, int mode, int unique )
|
||||||
/* File created OK, now fill the FILE_OBJECT */
|
/* File created OK, now fill the FILE_OBJECT */
|
||||||
|
|
||||||
file->unix_name = HEAP_strdupA( SystemHeap, 0, full_name.long_name );
|
file->unix_name = HEAP_strdupA( SystemHeap, 0, full_name.long_name );
|
||||||
|
file->mode = dosMode;
|
||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -739,7 +1027,9 @@ static HFILE32 FILE_DoOpenFile( LPCSTR name, OFSTRUCT *ofs, UINT32 mode,
|
||||||
WORD filedatetime[2];
|
WORD filedatetime[2];
|
||||||
DOS_FULL_NAME full_name;
|
DOS_FULL_NAME full_name;
|
||||||
char *p;
|
char *p;
|
||||||
int unixMode;
|
int unixMode, oldMode;
|
||||||
|
FILE_OBJECT *file;
|
||||||
|
BOOL32 fileInUse = FALSE;
|
||||||
|
|
||||||
if (!ofs) return HFILE_ERROR32;
|
if (!ofs) return HFILE_ERROR32;
|
||||||
|
|
||||||
|
@ -805,20 +1095,33 @@ found:
|
||||||
lstrcpyn32A( ofs->szPathName, full_name.short_name,
|
lstrcpyn32A( ofs->szPathName, full_name.short_name,
|
||||||
sizeof(ofs->szPathName) );
|
sizeof(ofs->szPathName) );
|
||||||
|
|
||||||
|
fileInUse = FILE_InUse(full_name.long_name,&oldMode);
|
||||||
|
if(fileInUse)
|
||||||
|
{
|
||||||
|
TRACE(file, "found another instance with mode 0x%02x\n",oldMode&0x70);
|
||||||
|
if (FILE_ShareDeny(mode,oldMode)) return HFILE_ERROR32;
|
||||||
|
}
|
||||||
|
|
||||||
if (mode & OF_SHARE_EXCLUSIVE)
|
if (mode & OF_SHARE_EXCLUSIVE)
|
||||||
|
/* Some InstallShield version uses OF_SHARE_EXCLUSIVE
|
||||||
|
on the file <tempdir>/_ins0432._mp to determine how
|
||||||
|
far installation has proceeded.
|
||||||
|
_ins0432._mp is an executable and while running the
|
||||||
|
application expects the open with OF_SHARE_ to fail*/
|
||||||
|
/* Probable FIXME:
|
||||||
|
As our loader closes the files after loading the executable,
|
||||||
|
we can't find the running executable with FILE_InUse.
|
||||||
|
Perhaps the loader should keep the file open.
|
||||||
|
Recheck against how Win handles that case */
|
||||||
{
|
{
|
||||||
char *last = strrchr(full_name.long_name,'/');
|
char *last = strrchr(full_name.long_name,'/');
|
||||||
if (!last)
|
if (!last)
|
||||||
last = full_name.long_name - 1;
|
last = full_name.long_name - 1;
|
||||||
/* Some InstallShield version uses OF_SHARE_EXCLUSIVE
|
|
||||||
on the file <tempdir>/_ins0432._mp to determine how
|
|
||||||
far installation has proceeded*/
|
|
||||||
if (GetModuleHandle16(last+1))
|
if (GetModuleHandle16(last+1))
|
||||||
{
|
{
|
||||||
TRACE(file,"Denying shared open for %s\n",full_name.long_name);
|
TRACE(file,"Denying shared open for %s\n",full_name.long_name);
|
||||||
return HFILE_ERROR32;
|
return HFILE_ERROR32;
|
||||||
}
|
}
|
||||||
FIXME(file,"OF_SHARE_EXCLUSIVE only partial implemented\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mode & OF_DELETE)
|
if (mode & OF_DELETE)
|
||||||
|
@ -828,19 +1131,17 @@ found:
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(mode & 3)
|
unixMode=FILE_DOSToUnixMode(mode);
|
||||||
{
|
|
||||||
case OF_WRITE:
|
|
||||||
unixMode = O_WRONLY; break;
|
|
||||||
case OF_READWRITE:
|
|
||||||
unixMode = O_RDWR; break;
|
|
||||||
case OF_READ:
|
|
||||||
default:
|
|
||||||
unixMode = O_RDONLY; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
hFileRet = FILE_OpenUnixFile( full_name.long_name, unixMode );
|
hFileRet = FILE_OpenUnixFile( full_name.long_name, unixMode );
|
||||||
if (hFileRet == HFILE_ERROR32) goto not_found;
|
if (hFileRet == HFILE_ERROR32) goto not_found;
|
||||||
|
/* we need to save the mode, but only if it is not in use yet*/
|
||||||
|
if( (!fileInUse) &&(file =FILE_GetFile(hFileRet)))
|
||||||
|
{
|
||||||
|
file->mode=mode;
|
||||||
|
FILE_ReleaseFile(file);
|
||||||
|
}
|
||||||
|
|
||||||
GetFileTime( hFileRet, NULL, NULL, &filetime );
|
GetFileTime( hFileRet, NULL, NULL, &filetime );
|
||||||
FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
|
FileTimeToDosDateTime( &filetime, &filedatetime[0], &filedatetime[1] );
|
||||||
if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
|
if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
|
||||||
|
@ -1107,19 +1408,9 @@ HFILE32 WINAPI _lopen32( LPCSTR path, INT32 mode )
|
||||||
|
|
||||||
TRACE(file, "('%s',%04x)\n", path, mode );
|
TRACE(file, "('%s',%04x)\n", path, mode );
|
||||||
|
|
||||||
switch(mode & 3)
|
unixMode= FILE_DOSToUnixMode(mode);
|
||||||
{
|
unixMode |= (mode &0x70); /* transfer the OF_SHARE options to handle
|
||||||
case OF_WRITE:
|
them in FILE_Open*/
|
||||||
unixMode = O_WRONLY;
|
|
||||||
break;
|
|
||||||
case OF_READWRITE:
|
|
||||||
unixMode = O_RDWR;
|
|
||||||
break;
|
|
||||||
case OF_READ:
|
|
||||||
default:
|
|
||||||
unixMode = O_RDONLY;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return FILE_Open( path, unixMode );
|
return FILE_Open( path, unixMode );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue