Release 970720
Sat Jul 19 13:03:01 1997 Alexandre Julliard <julliard@lrc.epfl.ch>
* [tools/build.c] [include/stackframe.h]
Save the complete %ebp register in CallFrom16; fixes a crash with
LabView reported by Andreas Mohr.
* [loader/main.c]
Avoid executing a built-in DLL.
* [controls/static.c]
Converted static window procedure to Win32.
* [windows/message.c] [windows/queue.c] [include/queue.h]
Hacked SendMessage functions to support inter-task messages with
SendMessage32A/W.
Sun Jul 13 16:55:35 1997 Bernhard Rosenkraenzer <bero@bero-online.ml.org>
* [ipc/bit_array.c]
Don't use bitops.h in Linux 2.1.x (these versions do not return
the previous state for clear_bit and set_bit)
* [ipc/shm_main_blk.c]
Adapt to GLIBC's ipc_perm structure.
* [memory/ldt.c]
Include <asm/unistd.h> on Linux/GLIBC systems (required for
_syscall3).
Wed Jul 9 23:53:19 1997 David A. Cuthbert <dacut@henry.ece.cmu.edu>
* [include/options.h] [files/profile.c]
Added PROFILE_GetWineIniBool and PROFILE_EnumerateWineIniSection.
* [include/sysmetrics.h] [include/windows.h] [windows/sysmetrics.c]
All sysmetrics moved to array (no more constant macros). Added
MOUSEWHEELPRESENT metric.
* [include/bitmap.h] [objects/oembitmap.c]
Added OBM_Init() (see also loader/main.c) and more support for Win95
bitmaps; added size info to OEM bitmaps.
* [include/graphics.h] [windows/graphics.h]
Added GRAPH_DrawGenericReliefRect.
* [loader/main.c]
Added TWEAK_Init() and TWEAK_CheckConfiguration() calls (the
latter checks for invalid entries in wine.conf).
* [include/debug.h] [include/stddebug.h] [include/nonclient.h]
[include/tweak.h] [controls/menu.c] [misc/tweak.c]
[objects/gdiobj.c] [windows/syscolor.c] [windows/nonclient.c]
[BUGS] [documentation/win95look]
Added tweaks for Windows 95 interface support. See
documentation/win95look for more information.
* [controls/edit.c]
Fixed EDIT_MoveHome bug.
* [misc/ver.c]
Changed name of dprintf_ver_string to ver_dstring to fix
problem with tools/make_debug utility.
Wed Jul 9 21:31:54 1997 Marcus Meissner <msmeissn@cip.informatik.uni-erlangen.de>
* [objects/dib.c]
Don't use palettes with dibs with biBitCount > 8.
* [misc/ole2nls.c][misc/ver.c]
IsValidLocale, EnumSystemLocales fixed (winhlp32.exe works)
Some VerLanguage coded moved to ole2nls.c, some cleanups.
* [multimedia/mcistring.c]
Fixed "capabilities <dev> device type" crash (cool.exe).
* [misc/main.c]
SystemParametersInfo*: added stub option 41
(GETNONCLIENTMETRICS), duplicated some stuff away from SPI16
that writes 32bit vars.(one COMCTL32.DLL crash, freecell.exe)
Tue Jul 8 22:40:53 1997 Morten Welinder <terra@diku.dk>
* [if1632/shell32.spec]
Use Windows 95's ordinals. Help wanted, inquire within.
Mon Jul 7 11:20:36 1997 Philippe De Muyter <phdm@info.ucl.ac.be>
* [if1632/relay.c] [if1632/user.spec] [if1632/kernel.spec]
[tools/build-spec.txt] [tools/build.c]
Added type 'segstr' (segmented pointer to null-terminated string)
to .spec files.
* [windows/user.c] [if1632/user.spec]
ExitWindowsExec stub function added.
Mon Jul 7 01:18:25 1997 U. Bonnes <bon@elektron.ikp.physik.th-darmstadt.de>
* [files/file.c] [include/winbase.h] [if1632/kernel32.spec]
Implement MoveFileEx32, some enhancement for Movefile32.
Sat Jul 5 18:13:48 1997 Bruce Milner <Bruce.Milner@genetics.utah.edu.
* [files/file.c] [if1632/kernel32.spec] [include/winerror.h]
[msdos/int21.c] [win32/file.c]
Add LockFile/UnlockFile implementation.
Add back in int21 func(0x5c) Record locking functions.
* [files/file.c]
Fixed bug with OF_REOPEN in FILE_DoOpenFile.
Fri Jul 4 12:00:00 1997 Henrik Olsen <Henrik.Olsen@iaeste.dk>
* [misc/ole2nls.c] [programs/progman/Da.rc] [programs/winhelp/Da.rc]
[resources/sysres_Da.rc]
Added/updated Danish language support.
Thu Jul 3 13:04:20 1997 Claus Fischer <fischer@iue.tuwien.ac.at>
* [files/dos_fs.c]
Properly implemented DOSFS_UnixTimeToFileTime and
DOSFS_FileTimeToUnixTime.
* [documentation/wine.texinfo]
First version of texinfo documentation.
diff --git a/files/dos_fs.c b/files/dos_fs.c
index 5bb8b35..014b41e 100644
--- a/files/dos_fs.c
+++ b/files/dos_fs.c
@@ -1202,16 +1202,121 @@
*
* Convert a Unix time to FILETIME format.
* The FILETIME structure is a 64-bit value representing the number of
- * 100-nanosecond intervals since January 1, 1601.
- * 'remainder' is the fraction of 100-ns intervals smaller than 1 second
- * that couldn't be stored in the time_t value.
+ * 100-nanosecond intervals since January 1, 1601, 0:00.
+ * 'remainder' is the nonnegative number of 100-ns intervals
+ * corresponding to the time fraction smaller than 1 second that
+ * couldn't be stored in the time_t value.
*/
void DOSFS_UnixTimeToFileTime( time_t unix_time, FILETIME *filetime,
DWORD remainder )
{
- /* FIXME :-) */
- filetime->dwLowDateTime = unix_time;
- filetime->dwHighDateTime = 0;
+ /* NOTES:
+
+ CONSTANTS:
+ The time difference between 1 January 1601, 00:00:00 and
+ 1 January 1970, 00:00:00 is 369 years, plus the leap years
+ from 1604 to 1968, excluding 1700, 1800, 1900.
+ This makes (1968 - 1600) / 4 - 3 = 89 leap days, and a total
+ of 134774 days.
+
+ Any day in that period had 24 * 60 * 60 = 86400 seconds.
+
+ The time difference is 134774 * 86400 * 10000000, which can be written
+ 116444736000000000
+ 27111902 * 2^32 + 3577643008
+ 413 * 2^48 + 45534 * 2^32 + 54590 * 2^16 + 32768
+
+ If you find that these constants are buggy, please change them in all
+ instances in both conversion functions.
+
+ VERSIONS:
+ There are two versions, one of them uses long long variables and
+ is presumably faster but not ISO C. The other one uses standard C
+ data types and operations but relies on the assumption that negative
+ numbers are stored as 2's complement (-1 is 0xffff....). If this
+ assumption is violated, dates before 1970 will not convert correctly.
+ This should however work on any reasonable architecture where WINE
+ will run.
+
+ DETAILS:
+
+ Take care not to remove the casts. I have tested these functions
+ (in both versions) for a lot of numbers. I would be interested in
+ results on other compilers than GCC.
+
+ The operations have been designed to account for the possibility
+ of 64-bit time_t in future UNICES. Even the versions without
+ internal long long numbers will work if time_t only is 64 bit.
+ A 32-bit shift, which was necessary for that operation, turned out
+ not to work correctly in GCC, besides giving the warning. So I
+ used a double 16-bit shift instead. Numbers are in the ISO version
+ represented by three limbs, the most significant with 32 bit, the
+ other two with 16 bit each.
+
+ As the modulo-operator % is not well-defined for negative numbers,
+ negative divisors have been avoided in DOSFS_FileTimeToUnixTime.
+
+ There might be quicker ways to do this in C. Certainly so in
+ assembler.
+
+ Claus Fischer, fischer@iue.tuwien.ac.at
+ */
+
+#if __GNUC__
+# define USE_LONG_LONG 1
+#else
+# define USE_LONG_LONG 0
+#endif
+
+#if USE_LONG_LONG /* gcc supports long long type */
+
+ long long int t = unix_time;
+ t *= 10000000;
+ t += 116444736000000000LL;
+ t += remainder;
+ filetime->dwLowDateTime = (UINT32)t;
+ filetime->dwHighDateTime = (UINT32)(t >> 32);
+
+#else /* ISO version */
+
+ UINT32 a0; /* 16 bit, low bits */
+ UINT32 a1; /* 16 bit, medium bits */
+ UINT32 a2; /* 32 bit, high bits */
+
+ /* Copy the unix time to a2/a1/a0 */
+ a0 = unix_time & 0xffff;
+ a1 = (unix_time >> 16) & 0xffff;
+ /* This is obsolete if unix_time is only 32 bits, but it does not hurt.
+ Do not replace this by >> 32, it gives a compiler warning and it does
+ not work. */
+ a2 = (unix_time >= 0 ? (unix_time >> 16) >> 16 :
+ ~((~unix_time >> 16) >> 16));
+
+ /* Multiply a by 10000000 (a = a2/a1/a0)
+ Split the factor into 10000 * 1000 which are both less than 0xffff. */
+ a0 *= 10000;
+ a1 = a1 * 10000 + (a0 >> 16);
+ a2 = a2 * 10000 + (a1 >> 16);
+ a0 &= 0xffff;
+ a1 &= 0xffff;
+
+ a0 *= 1000;
+ a1 = a1 * 1000 + (a0 >> 16);
+ a2 = a2 * 1000 + (a1 >> 16);
+ a0 &= 0xffff;
+ a1 &= 0xffff;
+
+ /* Add the time difference and the remainder */
+ a0 += 32768 + (remainder & 0xffff);
+ a1 += 54590 + (remainder >> 16 ) + (a0 >> 16);
+ a2 += 27111902 + (a1 >> 16);
+ a0 &= 0xffff;
+ a1 &= 0xffff;
+
+ /* Set filetime */
+ filetime->dwLowDateTime = (a1 << 16) + a0;
+ filetime->dwHighDateTime = a2;
+#endif
}
@@ -1219,13 +1324,95 @@
* DOSFS_FileTimeToUnixTime
*
* Convert a FILETIME format to Unix time.
- * If not NULL, 'remainder' contains the fractional part of the filetime.
+ * If not NULL, 'remainder' contains the fractional part of the filetime,
+ * in the range of [0..9999999] (even if time_t is negative).
*/
time_t DOSFS_FileTimeToUnixTime( const FILETIME *filetime, DWORD *remainder )
{
- /* FIXME :-) */
- if (remainder) *remainder = 0;
- return filetime->dwLowDateTime;
+ /* Read the comment in the function DOSFS_UnixTimeToFileTime. */
+#if USE_LONG_LONG
+
+ long long int t = filetime->dwHighDateTime;
+ t <<= 32;
+ t += (UINT32)filetime->dwLowDateTime;
+ t -= 116444736000000000LL;
+ if (t < 0)
+ {
+ if (remainder) *remainder = 9999999 - (-t - 1) % 10000000;
+ return -1 - ((-t - 1) / 10000000);
+ }
+ else
+ {
+ if (remainder) *remainder = t % 10000000;
+ return t / 10000000;
+ }
+
+#else /* ISO version */
+
+ UINT32 a0; /* 16 bit, low bits */
+ UINT32 a1; /* 16 bit, medium bits */
+ UINT32 a2; /* 32 bit, high bits */
+ UINT32 r; /* remainder of division */
+ unsigned int carry; /* carry bit for subtraction */
+ int negative; /* whether a represents a negative value */
+
+ /* Copy the time values to a2/a1/a0 */
+ a2 = (UINT32)filetime->dwHighDateTime;
+ a1 = ((UINT32)filetime->dwLowDateTime ) >> 16;
+ a0 = ((UINT32)filetime->dwLowDateTime ) & 0xffff;
+
+ /* Subtract the time difference */
+ if (a0 >= 32768 ) a0 -= 32768 , carry = 0;
+ else a0 += (1 << 16) - 32768 , carry = 1;
+
+ if (a1 >= 54590 + carry) a1 -= 54590 + carry, carry = 0;
+ else a1 += (1 << 16) - 54590 - carry, carry = 1;
+
+ a2 -= 27111902 + carry;
+
+ /* If a is negative, replace a by (-1-a) */
+ negative = (a2 >= ((UINT32)1) << 31);
+ if (negative)
+ {
+ /* Set a to -a - 1 (a is a2/a1/a0) */
+ a0 = 0xffff - a0;
+ a1 = 0xffff - a1;
+ a2 = ~a2;
+ }
+
+ /* Divide a by 10000000 (a = a2/a1/a0), put the rest into r.
+ Split the divisor into 10000 * 1000 which are both less than 0xffff. */
+ a1 += (a2 % 10000) << 16;
+ a2 /= 10000;
+ a0 += (a1 % 10000) << 16;
+ a1 /= 10000;
+ r = a0 % 10000;
+ a0 /= 10000;
+
+ a1 += (a2 % 1000) << 16;
+ a2 /= 1000;
+ a0 += (a1 % 1000) << 16;
+ a1 /= 1000;
+ r += (a0 % 1000) * 10000;
+ a0 /= 1000;
+
+ /* If a was negative, replace a by (-1-a) and r by (9999999 - r) */
+ if (negative)
+ {
+ /* Set a to -a - 1 (a is a2/a1/a0) */
+ a0 = 0xffff - a0;
+ a1 = 0xffff - a1;
+ a2 = ~a2;
+
+ r = 9999999 - r;
+ }
+
+ if (remainder) *remainder = r;
+
+ /* Do not replace this by << 32, it gives a compiler warning and it does
+ not work. */
+ return ((((time_t)a2) << 16) << 16) + (a1 << 16) + a0;
+#endif
}
diff --git a/files/drive.c b/files/drive.c
index 3fb43c1..c4a88de 100644
--- a/files/drive.c
+++ b/files/drive.c
@@ -14,7 +14,7 @@
#if defined(__linux__) || defined(sun) || defined(hpux)
#include <sys/vfs.h>
#endif
-#if defined(__NetBSD__) || defined(__FreeBSD__)
+#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
#include <sys/param.h>
#include <sys/mount.h>
#include <sys/errno.h>
diff --git a/files/file.c b/files/file.c
index 1625f39..8b1c31e 100644
--- a/files/file.c
+++ b/files/file.c
@@ -38,6 +38,19 @@
#define MAP_ANON MAP_ANONYMOUS
#endif
+struct DOS_FILE_LOCK {
+ struct DOS_FILE_LOCK * next;
+ DWORD base;
+ DWORD len;
+ DWORD processId;
+ FILE_OBJECT * dos_file;
+ char * unix_name;
+};
+
+typedef struct DOS_FILE_LOCK DOS_FILE_LOCK;
+
+static DOS_FILE_LOCK *locks = NULL;
+static void DOS_RemoveFileLocks(FILE_OBJECT *file);
/***********************************************************************
* FILE_Alloc
@@ -75,6 +88,8 @@
FILE_OBJECT *file = (FILE_OBJECT *)ptr;
assert( ptr->type == K32OBJ_FILE );
+ DOS_RemoveFileLocks(file);
+
if (file->unix_handle != -1) close( file->unix_handle );
if (file->unix_name) HeapFree( SystemHeap, 0, file->unix_name );
ptr->type = K32OBJ_UNKNOWN;
@@ -621,16 +636,19 @@
char *p;
int unixMode;
- if (!name || !ofs) return HFILE_ERROR32;
+ if (!ofs) return HFILE_ERROR32;
+
+
+ ofs->cBytes = sizeof(OFSTRUCT);
+ ofs->nErrCode = 0;
+ if (mode & OF_REOPEN) name = ofs->szPathName;
if (!name) {
fprintf(stderr, "ERROR: FILE_DoOpenFile() called with `name' set to NULL ! Please debug.\n");
return HFILE_ERROR32;
}
- ofs->cBytes = sizeof(OFSTRUCT);
- ofs->nErrCode = 0;
- if (mode & OF_REOPEN) name = ofs->szPathName;
+
dprintf_file( stddeb, "OpenFile: %s %04x\n", name, mode );
/* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
@@ -1201,8 +1219,12 @@
if (!file)
{
/* Linux EINVAL's on us if we don't pass MAP_PRIVATE to an anon mmap */
+#ifdef MAP_SHARED
flags &= ~MAP_SHARED;
+#endif
+#ifdef MAP_PRIVATE
flags |= MAP_PRIVATE;
+#endif
#ifdef MAP_ANON
flags |= MAP_ANON;
#else
@@ -1238,24 +1260,148 @@
/**************************************************************************
+ * MoveFileEx32A (KERNEL32.???)
+ *
+ *
+ */
+BOOL32 MoveFileEx32A( LPCSTR fn1, LPCSTR fn2, DWORD flag )
+{
+ DOS_FULL_NAME full_name1, full_name2;
+ int mode=0; /* mode == 1: use copy */
+
+ dprintf_file( stddeb, "MoveFileEx32A(%s,%s,%04lx)\n", fn1, fn2, flag);
+
+ if (!DOSFS_GetFullName( fn1, TRUE, &full_name1 )) return FALSE;
+ if (fn2) { /* !fn2 means delete fn1 */
+ if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 )) return FALSE;
+ /* Source name and target path are valid */
+ if ( full_name1.drive != full_name2.drive)
+ /* use copy, if allowed */
+ if (!(flag & MOVEFILE_COPY_ALLOWED)) {
+ /* FIXME: Use right error code */
+ DOS_ERROR( ER_FileExists, EC_Exists, SA_Abort, EL_Disk );
+ return FALSE;
+ }
+ else mode =1;
+ if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
+ /* target exists, check if we may overwrite */
+ if (!(flag & MOVEFILE_REPLACE_EXISTING)) {
+ /* FIXME: Use right error code */
+ DOS_ERROR( ER_AccessDenied, EC_AccessDenied, SA_Abort, EL_Disk );
+ return FALSE;
+ }
+ }
+ else /* fn2 == NULL means delete source */
+ if (flag & MOVEFILE_DELAY_UNTIL_REBOOT) {
+ if (flag & MOVEFILE_COPY_ALLOWED) {
+ fprintf( stderr,
+ "MoveFileEx32A: Illegal flag\n");
+ DOS_ERROR( ER_GeneralFailure, EC_SystemFailure, SA_Abort,
+ EL_Unknown );
+ return FALSE;
+ }
+ /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
+ Perhaps we should queue these command and execute it
+ when exiting... What about using on_exit(2)
+ */
+ fprintf( stderr,"MoveFileEx32A: Please delete file %s\n",
+ full_name1.long_name);
+ fprintf( stderr," when Wine has finished\n");
+ fprintf( stderr," like \"rm %s\"\n",
+ full_name1.long_name);
+ return TRUE;
+ }
+ else if (unlink( full_name1.long_name ) == -1)
+ {
+ FILE_SetDosError();
+ return FALSE;
+ }
+ else return TRUE; /* successfully deleted */
+
+ if (flag & MOVEFILE_DELAY_UNTIL_REBOOT) {
+ /* FIXME: (bon@elektron.ikp.physik.th-darmstadt.de 970706)
+ Perhaps we should queue these command and execute it
+ when exiting... What about using on_exit(2)
+ */
+ fprintf( stderr,"MoveFileEx32A: Please move existing file %s\n"
+ ,full_name1.long_name);
+ fprintf( stderr," to file %s\n"
+ ,full_name2.long_name);
+ fprintf( stderr," when Wine has finished\n");
+ fprintf( stderr," like \" mv %s %s\"\n",
+ full_name1.long_name,full_name2.long_name);
+ return TRUE;
+ }
+
+ if (!mode) /* move the file */
+ if (rename( full_name1.long_name, full_name2.long_name ) == -1)
+ {
+ FILE_SetDosError();
+ return FALSE;
+ }
+ else return TRUE;
+ else /* copy File */
+ return CopyFile32A(fn1, fn2, (!(flag & MOVEFILE_REPLACE_EXISTING)));
+
+}
+
+/**************************************************************************
+ * MoveFileEx32W (KERNEL32.???)
+ */
+BOOL32 MoveFileEx32W( LPCWSTR fn1, LPCWSTR fn2, DWORD flag )
+{
+ LPSTR afn1 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn1 );
+ LPSTR afn2 = HEAP_strdupWtoA( GetProcessHeap(), 0, fn2 );
+ BOOL32 res = MoveFileEx32A( afn1, afn2, flag );
+ HeapFree( GetProcessHeap(), 0, afn1 );
+ HeapFree( GetProcessHeap(), 0, afn2 );
+ return res;
+}
+
+
+/**************************************************************************
* MoveFile32A (KERNEL32.387)
+ *
+ * Move file or directory
*/
BOOL32 MoveFile32A( LPCSTR fn1, LPCSTR fn2 )
{
DOS_FULL_NAME full_name1, full_name2;
+ struct stat fstat;
dprintf_file( stddeb, "MoveFile32A(%s,%s)\n", fn1, fn2 );
if (!DOSFS_GetFullName( fn1, TRUE, &full_name1 )) return FALSE;
+ if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
+ /* The new name must not already exist */
+ return FALSE;
if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 )) return FALSE;
- /* FIXME: should not replace an existing file */
- /* FIXME: should handle renaming across devices */
+
+ if (full_name1.drive == full_name2.drive) /* move */
if (rename( full_name1.long_name, full_name2.long_name ) == -1)
{
FILE_SetDosError();
return FALSE;
}
- return TRUE;
+ else return TRUE;
+ else /*copy */ {
+ if (stat( full_name1.long_name, &fstat ))
+ {
+ dprintf_file( stddeb, "Invalid source file %s\n",
+ full_name1.long_name);
+ FILE_SetDosError();
+ return FALSE;
+ }
+ if (S_ISDIR(fstat.st_mode)) {
+ /* No Move for directories across file systems */
+ /* FIXME: Use right error code */
+ DOS_ERROR( ER_GeneralFailure, EC_SystemFailure, SA_Abort,
+ EL_Unknown );
+ return FALSE;
+ }
+ else
+ return CopyFile32A(fn1, fn2, TRUE); /*fail, if exist */
+ }
}
@@ -1365,3 +1511,175 @@
FILE_ReleaseFile( file );
return TRUE;
}
+
+/* Locks need to be mirrored because unix file locking is based
+ * on the pid. Inside of wine there can be multiple WINE processes
+ * that share the same unix pid.
+ * Read's and writes should check these locks also - not sure
+ * how critical that is at this point (FIXME).
+ */
+
+static BOOL32 DOS_AddLock(FILE_OBJECT *file, struct flock *f)
+{
+ DOS_FILE_LOCK *curr;
+ DWORD processId;
+
+ processId = GetCurrentProcessId();
+
+ /* check if lock overlaps a current lock for the same file */
+ for (curr = locks; curr; curr = curr->next) {
+ if (strcmp(curr->unix_name, file->unix_name) == 0) {
+ if ((f->l_start < (curr->base + curr->len)) &&
+ ((f->l_start + f->l_len) > curr->base)) {
+ /* region overlaps */
+ return FALSE;
+ }
+ }
+ }
+
+ curr = HeapAlloc( SystemHeap, 0, sizeof(DOS_FILE_LOCK) );
+ curr->processId = GetCurrentProcessId();
+ curr->base = f->l_start;
+ curr->len = f->l_len;
+ curr->unix_name = HEAP_strdupA( SystemHeap, 0, file->unix_name);
+ curr->next = locks;
+ curr->dos_file = file;
+ locks = curr;
+ return TRUE;
+}
+
+static void DOS_RemoveFileLocks(FILE_OBJECT *file)
+{
+ DWORD processId;
+ DOS_FILE_LOCK **curr;
+ DOS_FILE_LOCK *rem;
+
+ processId = GetCurrentProcessId();
+ curr = &locks;
+ while (*curr) {
+ if ((*curr)->dos_file == file) {
+ rem = *curr;
+ *curr = (*curr)->next;
+ HeapFree( SystemHeap, 0, rem->unix_name );
+ HeapFree( SystemHeap, 0, rem );
+ }
+ else
+ curr = &(*curr)->next;
+ }
+}
+
+static BOOL32 DOS_RemoveLock(FILE_OBJECT *file, struct flock *f)
+{
+ DWORD processId;
+ DOS_FILE_LOCK **curr;
+ DOS_FILE_LOCK *rem;
+
+ processId = GetCurrentProcessId();
+ for (curr = &locks; *curr; curr = &(*curr)->next) {
+ if ((*curr)->processId == processId &&
+ (*curr)->dos_file == file &&
+ (*curr)->base == f->l_start &&
+ (*curr)->len == f->l_len) {
+ /* this is the same lock */
+ rem = *curr;
+ *curr = (*curr)->next;
+ HeapFree( SystemHeap, 0, rem->unix_name );
+ HeapFree( SystemHeap, 0, rem );
+ return TRUE;
+ }
+ }
+ /* no matching lock found */
+ return FALSE;
+}
+
+
+/**************************************************************************
+ * LockFile (KERNEL32.511)
+ */
+BOOL32 LockFile(
+ HFILE32 hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
+ DWORD nNumberOfBytesToLockLow,DWORD nNumberOfBytesToLockHigh )
+{
+ struct flock f;
+ FILE_OBJECT *file;
+
+ dprintf_file(stddeb, "LockFile32: handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
+ hFile, dwFileOffsetLow, dwFileOffsetHigh,
+ nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh);
+
+ if (dwFileOffsetHigh || nNumberOfBytesToLockHigh) {
+ dprintf_file(stddeb, "LockFile32: Unimplemented bytes > 32bits\n");
+ return FALSE;
+ }
+
+ f.l_start = dwFileOffsetLow;
+ f.l_len = nNumberOfBytesToLockLow;
+ f.l_whence = SEEK_SET;
+ f.l_pid = 0;
+ f.l_type = F_WRLCK;
+
+ if (!(file = FILE_GetFile(hFile))) return FALSE;
+
+ /* shadow locks internally */
+ if (!DOS_AddLock(file, &f)) {
+ DOS_ERROR( ER_LockViolation, EC_AccessDenied, SA_Ignore, EL_Disk );
+ return FALSE;
+ }
+
+ /* FIXME: Unix locking commented out for now, doesn't work with Excel */
+#ifdef USE_UNIX_LOCKS
+ if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
+ if (errno == EACCES || errno == EAGAIN) {
+ DOS_ERROR( ER_LockViolation, EC_AccessDenied, SA_Ignore, EL_Disk );
+ }
+ else {
+ FILE_SetDosError();
+ }
+ /* remove our internal copy of the lock */
+ DOS_RemoveLock(file, &f);
+ return FALSE;
+ }
+#endif
+ return TRUE;
+}
+
+
+/**************************************************************************
+ * UnlockFile (KERNEL32.703)
+ */
+BOOL32 UnlockFile(
+ HFILE32 hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
+ DWORD nNumberOfBytesToUnlockLow,DWORD nNumberOfBytesToUnlockHigh )
+{
+ FILE_OBJECT *file;
+ struct flock f;
+
+ dprintf_file(stddeb, "UnlockFile32: handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
+ hFile, dwFileOffsetLow, dwFileOffsetHigh,
+ nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh);
+
+ if (dwFileOffsetHigh || nNumberOfBytesToUnlockHigh) {
+ dprintf_file(stddeb, "UnlockFile32: Unimplemented bytes > 32bits\n");
+ return FALSE;
+ }
+
+ f.l_start = dwFileOffsetLow;
+ f.l_len = nNumberOfBytesToUnlockLow;
+ f.l_whence = SEEK_SET;
+ f.l_pid = 0;
+ f.l_type = F_UNLCK;
+
+ if (!(file = FILE_GetFile(hFile))) return FALSE;
+
+ DOS_RemoveLock(file, &f); /* ok if fails - may be another wine */
+
+ /* FIXME: Unix locking commented out for now, doesn't work with Excel */
+#ifdef USE_UNIX_LOCKS
+ if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
+ FILE_SetDosError();
+ return FALSE;
+ }
+#endif
+ return TRUE;
+}
+
diff --git a/files/profile.c b/files/profile.c
index d537a8e..6fac8eb 100644
--- a/files/profile.c
+++ b/files/profile.c
@@ -604,6 +604,118 @@
}
+/******************************************************************************
+ *
+ * int PROFILE_EnumerateWineIniSection(
+ * char const *section, // Name of the section to enumerate
+ * void (*cbfn)(char const *key, char const *value, void *user),
+ // Address of the callback function
+ * void *user ) // User-specified pointer.
+ *
+ * For each entry in a section in the wine.conf file, this function will
+ * call the specified callback function, informing it of each key and
+ * value. An optional user pointer may be passed to it (if this is not
+ * needed, pass NULL through it and ignore the value in the callback
+ * function).
+ *
+ * The callback function must accept three parameters:
+ * The name of the key (char const *)
+ * The value of the key (char const *)
+ * A user-specified parameter (void *)
+ * Note that the first two are char CONST *'s, not char *'s! The callback
+ * MUST not modify these strings!
+ *
+ * The return value indicates the number of times the callback function
+ * was called.
+ */
+int PROFILE_EnumerateWineIniSection(
+ char const *section,
+ void (*cbfn)(char const *, char const *, void *),
+ void *userptr )
+{
+ PROFILESECTION *scansect;
+ PROFILEKEY *scankey;
+ int calls = 0;
+
+ /* Search for the correct section */
+ for(scansect = WineProfile; scansect; scansect = scansect->next) {
+ if(scansect->name && !lstrcmpi32A(scansect->name, section)) {
+
+ /* Enumerate each key with the callback */
+ for(scankey = scansect->key; scankey; scankey = scankey->next) {
+
+ /* Ignore blank entries -- these shouldn't exist, but let's
+ be extra careful */
+ if(scankey->name[0]) {
+ cbfn(scankey->name, scankey->value, userptr);
+ ++calls;
+ }
+ }
+
+ break;
+ }
+ }
+
+ return calls;
+}
+
+
+/******************************************************************************
+ *
+ * int PROFILE_GetWineIniBool(
+ * char const *section,
+ * char const *key_name,
+ * int def )
+ *
+ * Reads a boolean value from the wine.ini file. This function attempts to
+ * be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
+ * (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
+ * true. Anything else results in the return of the default value.
+ *
+ * This function uses 1 to indicate true, and 0 for false. You can check
+ * for existence by setting def to something other than 0 or 1 and
+ * examining the return value.
+ */
+int PROFILE_GetWineIniBool(
+ char const *section,
+ char const *key_name,
+ int def )
+{
+ char key_value[2];
+ int retval;
+
+ PROFILE_GetWineIniString(section, key_name, "~", key_value, 2);
+
+ switch(key_value[0]) {
+ case 'n':
+ case 'N':
+ case 'f':
+ case 'F':
+ case '0':
+ retval = 0;
+ break;
+
+ case 'y':
+ case 'Y':
+ case 't':
+ case 'T':
+ case '1':
+ retval = 1;
+ break;
+
+ default:
+ retval = def;
+ }
+
+ dprintf_profile(stddeb, "PROFILE_GetWineIniBool(\"%s\", \"%s\", %s), "
+ "[%c], ret %s.\n", section, key_name,
+ def ? "TRUE" : "FALSE", key_value[0],
+ retval ? "TRUE" : "FALSE");
+
+ return retval;
+}
+
+
/***********************************************************************
* PROFILE_LoadWineIni
*