diff --git a/source/smbd/open.c b/source/smbd/open.c index f450e74e58c..cebb37ab291 100644 --- a/source/smbd/open.c +++ b/source/smbd/open.c @@ -48,8 +48,8 @@ static int fd_open(struct connection_struct *conn, char *fname, fd = conn->vfs_ops.open(conn,dos_to_unix(fname,False),flags,mode); } - DEBUG(10,("fd_open: name %s, mode = %d, fd = %d. %s\n", fname, (int)mode, fd, - (fd == -1) ? strerror(errno) : "" )); + DEBUG(10,("fd_open: name %s, flags = 0%o mode = 0%o, fd = %d. %s\n", fname, + flags, (int)mode, fd, (fd == -1) ? strerror(errno) : "" )); return fd; } @@ -647,7 +647,22 @@ files_struct *open_file_shared(connection_struct *conn,char *fname, SMB_STRUCT_S flags = O_RDWR; break; default: - flags = O_RDONLY; + /* + * This little piece of insanity is inspired by the + * fact that an NT client can open a file for O_RDONLY, + * but set the create disposition to FILE_EXISTS_TRUNCATE. + * If the client *can* write to the file, then it expects to + * truncate the file, even though it is opening for readonly. + * Quicken uses this stupid trick in backup file creation... + * Thanks *greatly* to "David W. Chapman Jr." + * for helping track this one down. It didn't bite us in 2.0.x + * as we always opened files read-write in that release. JRA. + */ + + if (flags2 & O_TRUNC) + flags = O_RDWR; + else + flags = O_RDONLY; break; } diff --git a/source/utils/torture.c b/source/utils/torture.c index 446bf7eaf22..871e2adfc34 100644 --- a/source/utils/torture.c +++ b/source/utils/torture.c @@ -2397,6 +2397,8 @@ static void run_opentest(int dummy) int fnum1, fnum2; uint8 eclass; uint32 errnum; + char buf[20]; + size_t fsize; printf("starting open test\n"); @@ -2470,11 +2472,76 @@ static void run_opentest(int dummy) printf("correct error code ERRDOS/ERRbadshare returned\n"); } + if (!cli_close(&cli1, fnum1)) { + printf("close2 failed (%s)\n", cli_errstr(&cli1)); + return; + } + + cli_unlink(&cli1, fname); + + printf("finished open test 2\n"); + + /* Test truncate open disposition on file opened for read. */ + + fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE); + if (fnum1 == -1) { + printf("(3) open (1) of %s failed (%s)\n", fname, cli_errstr(&cli1)); + return; + } + + /* write 20 bytes. */ + + memset(buf, '\0', 20); + + if (cli_write(&cli1, fnum1, 0, buf, 0, 20) != 20) { + printf("write failed (%s)\n", cli_errstr(&cli1)); + } + + if (!cli_close(&cli1, fnum1)) { + printf("(3) close1 failed (%s)\n", cli_errstr(&cli1)); + return; + } + + /* Ensure size == 20. */ + if (!cli_getatr(&cli1, fname, NULL, &fsize, NULL)) { + printf("(3) getatr failed (%s)\n", cli_errstr(&cli1)); + return; + } + + if (fsize != 20) { + printf("(3) file size != 20\n"); + return; + } + + /* Now test if we can truncate a file opened for readonly. */ + + fnum1 = cli_open(&cli1, fname, O_RDONLY|O_TRUNC, DENY_NONE); + if (fnum1 == -1) { + printf("(3) open (2) of %s failed (%s)\n", fname, cli_errstr(&cli1)); + return; + } + + if (!cli_close(&cli1, fnum1)) { + printf("close2 failed (%s)\n", cli_errstr(&cli1)); + return; + } + + /* Ensure size == 0. */ + if (!cli_getatr(&cli1, fname, NULL, &fsize, NULL)) { + printf("(3) getatr failed (%s)\n", cli_errstr(&cli1)); + return; + } + + if (fsize != 0) { + printf("(3) file size != 0\n"); + return; + } + printf("finished open test 3\n"); + cli_unlink(&cli1, fname); close_connection(&cli1); - printf("finished open test 2\n"); } static void list_fn(file_info *finfo, const char *name, void *state)