Hi,
On at least MS-DOS 6.0 with SHARE.EXE installed, INT21 function 3CH,
"Create a File", fails if the file exists and is currently opened by
another program.
R:base 1.01, an old database program, relies on that behavior to protect
against simultaneous access to the same database.
However, DOSEMU allows the function to succeed.
Here is a patch that implements the MS-DOS behavior. It moves Maxim
Ruchko's file-sharing code into a separate function, and replaces
"open(O_TRUNC)" with "open(); check sharing; ftruncate()".
Nick Duffek
[EMAIL PROTECTED]
--- dosemu-0.99.11/src/dosext/mfs/mfs.c.orig Thu Apr 22 16:47:42 1999
+++ dosemu-0.99.11/src/dosext/mfs/mfs.c Sat May 1 17:03:37 1999
@@ -2531,6 +2531,59 @@
return (TRUE);
}
+static boolean_t
+share(int fd, boolean_t writing, sft_t sft)
+{
+ /*
+ * Return whether FD doesn't break any sharing rules. FD was opened for
+ * writing if WRITING and for reading otherwise.
+ *
+ * Written by Maxim Ruchko, and moved into a separate function by Nick
+ * Duffek <[EMAIL PROTECTED]>. Here are Maxim's original comments:
+ *
+ * IMHO, to handle sharing modes at this moment,
+ * it's impossible to know wether an other process already
+ * has been opened this file in shared mode.
+ * But DOS programs (FoxPro 2.6 for example) need ACCESS_DENIED
+ * as return code _at_ _this_ _point_, if they are opening
+ * the file exclusively and the file has been opened elsewhere.
+ * I place a lock in a predefined place at max possible lock length
+ * in order to emulate the exclusive lock feature of DOS.
+ * This lock is 'invisible' to DOS programs because the code
+ * (extracted from the Samba project) in mfs lock requires that the
+ * handler wrapps the locks below or equal 0x3fffffff (mask=0xC0000000)
+ * So, 0x3fffffff + 0x3fffffff = 0x7ffffffe
+ * and 0x7fffffff is my start position. --Maxim Ruchko
+ */
+ struct flock fl;
+ int share_mode = ( sft_open_mode( sft ) >> 4 ) & 0x7;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = 0x7fffffff;
+ fl.l_len = 1;
+ fl.l_pid = 0;
+ switch ( share_mode ) {
+ case COMPAT_MODE:
+ case DENY_ALL:
+ case DENY_WRITE:
+ case DENY_READ:
+ fl.l_type = !writing ? F_RDLCK : F_WRLCK;
+ break;
+ case DENY_ANY:
+ fl.l_type = F_RDLCK;
+ break;
+ default:
+ fl.l_type = F_WRLCK;
+ Debug0((dbg_fd, "internal SHARE: unknown sharing mode %x\n",
+ share_mode));
+ break;
+ }
+ if ( fcntl( fd, F_SETLK, &fl ) == 0 )
+ return (TRUE);
+
+ Debug0((dbg_fd, "internal SHARE: access denied by locks fd=%x\n", fd));
+ return (FALSE);
+}
+
static int
dos_fs_redirect(state)
state_t *state;
@@ -3103,49 +3156,10 @@
SETWORD(&(state->eax), ACCESS_DENIED);
return (FALSE);
}
- {
- /* IMHO, to handle sharing modes at this moment,
- * it's impossible to know wether an other process already
- * has been opened this file in shared mode.
- * But DOS programs (FoxPro 2.6 for example) need ACCESS_DENIED
- * as return code _at_ _this_ _point_, if they are opening
- * the file exclusively and the file has been opened elsewhere.
- * I place a lock in a predefined place at max possible lock length
- * in order to emulate the exclusive lock feature of DOS.
- * This lock is 'invisible' to DOS programs because the code
- * (extracted from the Samba project) in mfs lock requires that the
- * handler wrapps the locks below or equal 0x3fffffff (mask=0xC0000000)
- * So, 0x3fffffff + 0x3fffffff = 0x7ffffffe
- * and 0x7fffffff is my start position. --Maxim Ruchko
- */
- struct flock fl;
- int share_mode = ( sft_open_mode( sft ) >> 4 ) & 0x7;
- fl.l_whence = SEEK_SET;
- fl.l_start = 0x7fffffff;
- fl.l_len = 1;
- fl.l_pid = 0;
- switch ( share_mode ) {
- case COMPAT_MODE:
- case DENY_ALL:
- case DENY_WRITE:
- case DENY_READ:
- fl.l_type = ( unix_mode == O_RDONLY ) ? F_RDLCK : F_WRLCK;
- break;
- case DENY_ANY:
- fl.l_type = F_RDLCK;
- break;
- default:
- fl.l_type = F_WRLCK;
- Debug0((dbg_fd, "internal SHARE: unknown sharing mode %x opening %s\n",
- share_mode, fpath));
- break;
- }
- if ( fcntl( fd, F_SETLK, &fl ) ) {
- close( fd );
- Debug0((dbg_fd, "internal SHARE: access denied by locks fd=%x\n", fd));
- SETWORD(&(state->eax), ACCESS_DENIED);
- return (FALSE);
- }
+ if (!share(fd, unix_mode != O_RDONLY, sft)) {
+ close( fd );
+ SETWORD(&(state->eax), ACCESS_DENIED);
+ return (FALSE);
}
}
@@ -3243,14 +3257,14 @@
bs_pos = i;
}
- if ((fd = open(fpath, (O_RDWR | O_CREAT | O_TRUNC),
+ if ((fd = open(fpath, (O_RDWR | O_CREAT),
get_unix_attr(0664, attr))) < 0) {
strncpy(buf, fpath, bs_pos);
buf[bs_pos] = EOS;
find_file(buf, &st);
strncpy(fpath, buf, bs_pos);
Debug0((dbg_fd, "trying '%s'\n", fpath));
- if ((fd = open(fpath, (O_RDWR | O_CREAT | O_TRUNC),
+ if ((fd = open(fpath, (O_RDWR | O_CREAT),
get_unix_attr(0664, attr))) < 0) {
Debug0((dbg_fd, "can't open %s: %s (%d)\n",
fpath, strerror(errno), errno));
@@ -3261,6 +3275,14 @@
#endif
return (FALSE);
}
+ }
+
+ if (!share(fd, TRUE, sft) || ftruncate(fd, 0) != 0) {
+ Debug0((dbg_fd, "unable to truncate %s: %s (%d)\n",
+ fpath, strerror(errno), errno));
+ close(fd);
+ SETWORD(&(state->eax), ACCESS_DENIED);
+ return FALSE;
}
if (can_do_root_stuff) {