From 0e255bb542b1f79c32e9295617199ea8d60753d4 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 12 Nov 2004 09:37:59 +0000 Subject: r3699: - split the delayed write testing out of RAW-WRITE, as it is not yet clear what the correct behaviour is for delayed stat info update. - use a common torture_setup_dir() function for setting up a test directory in torture tests. (This used to be commit f7fb34715b7d6ea3c35ddd684cfb27459a420339) --- source4/torture/basic/charset.c | 7 +- source4/torture/basic/delaywrite.c | 284 ++++++++++++++++++++++++++++++++++++ source4/torture/basic/dir.c | 7 +- source4/torture/basic/disconnect.c | 14 +- source4/torture/basic/mangle_test.c | 6 +- source4/torture/basic/utable.c | 9 +- 6 files changed, 293 insertions(+), 34 deletions(-) create mode 100644 source4/torture/basic/delaywrite.c (limited to 'source4/torture/basic') diff --git a/source4/torture/basic/charset.c b/source4/torture/basic/charset.c index 090303ac30..4f57eba64a 100644 --- a/source4/torture/basic/charset.c +++ b/source4/torture/basic/charset.c @@ -239,12 +239,7 @@ BOOL torture_charset(void) printf("Starting charset tests\n"); - if (smbcli_deltree(cli->tree, BASEDIR) == -1) { - printf("Failed to clean " BASEDIR "\n"); - return False; - } - if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, BASEDIR))) { - printf("Failed to create " BASEDIR " - %s\n", smbcli_errstr(cli->tree)); + if (!torture_setup_dir(cli, BASEDIR)) { return False; } diff --git a/source4/torture/basic/delaywrite.c b/source4/torture/basic/delaywrite.c new file mode 100644 index 0000000000..3a632c49ea --- /dev/null +++ b/source4/torture/basic/delaywrite.c @@ -0,0 +1,284 @@ +/* + Unix SMB/CIFS implementation. + + test suite for delayed write update + + Copyright (C) Volker Lendecke 2004 + Copyright (C) Andrew Tridgell 2004 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" +#include "libcli/raw/libcliraw.h" +#include "system/time.h" + +#define BASEDIR "\\delaywrite" + +static BOOL test_delayed_write_update(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) +{ + union smb_fileinfo finfo1, finfo2; + const char *fname = BASEDIR "\\torture_file.txt"; + NTSTATUS status; + int fnum1 = -1; + BOOL ret = True; + ssize_t written; + time_t t; + + printf("Testing delayed update of write time\n"); + + if (!torture_setup_dir(cli, BASEDIR)) { + return False; + } + + fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE); + if (fnum1 == -1) { + printf("Failed to open %s\n", fname); + return False; + } + + finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO; + finfo1.basic_info.in.fnum = fnum1; + finfo2 = finfo1; + + status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo1); + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status))); + return False; + } + + printf("Initial write time %s\n", + nt_time_string(mem_ctx, finfo1.basic_info.out.write_time)); + + /* 3 second delay to ensure we get past any 2 second time + granularity (older systems may have that) */ + sleep(3); + + written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1); + + if (written != 1) { + printf("write failed - wrote %d bytes (%s)\n", written, __location__); + return False; + } + + t = time(NULL); + + while (time(NULL) < t+120) { + status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo2); + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status))); + ret = False; + break; + } + printf("write time %s\n", + nt_time_string(mem_ctx, finfo2.basic_info.out.write_time)); + if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) { + printf("Server updated write_time after %d seconds\n", + (int)(time(NULL) - t)); + break; + } + sleep(1); + fflush(stdout); + } + + if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) { + printf("Server did not update write time?!\n"); + ret = False; + } + + + if (fnum1 != -1) + smbcli_close(cli->tree, fnum1); + smbcli_unlink(cli->tree, fname); + smbcli_deltree(cli->tree, BASEDIR); + + return ret; +} + + +/* Windows does obviously not update the stat info during a write call. I + * *think* this is the problem causing a spurious Excel 2003 on XP error + * message when saving a file. Excel does a setfileinfo, writes, and then does + * a getpath(!)info. Or so... For Samba sometimes it displays an error message + * that the file might have been changed in between. What i've been able to + * trace down is that this happens if the getpathinfo after the write shows a + * different last write time than the setfileinfo showed. This is really + * nasty.... + */ + +static BOOL test_finfo_after_write(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) +{ + union smb_fileinfo finfo1, finfo2; + const char *fname = BASEDIR "\\torture_file.txt"; + NTSTATUS status; + int fnum1 = -1; + int fnum2; + BOOL ret = True; + ssize_t written; + struct smbcli_state *cli2=NULL; + + printf("Testing finfo update on close\n"); + + if (!torture_setup_dir(cli, BASEDIR)) { + return False; + } + + fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE); + if (fnum1 == -1) { + ret = False; + goto done; + } + + finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO; + finfo1.basic_info.in.fnum = fnum1; + + status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo1); + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status))); + ret = False; + goto done; + } + + msleep(1000); + + written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1); + + if (written != 1) { + printf("(%s) written gave %d - should have been 1\n", + __location__, written); + ret = False; + goto done; + } + + if (!torture_open_connection(&cli2)) { + return False; + } + + fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE); + if (fnum2 == -1) { + printf("(%s) failed to open 2nd time - %s\n", + __location__, smbcli_errstr(cli2->tree)); + ret = False; + goto done; + } + + written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 1); + + if (written != 1) { + printf("(%s) written gave %d - should have been 1\n", + __location__, written); + ret = False; + goto done; + } + + finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO; + finfo2.basic_info.in.fname = fname; + + status = smb_raw_pathinfo(cli2->tree, mem_ctx, &finfo2); + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("(%s) fileinfo failed: %s\n", + __location__, nt_errstr(status))); + ret = False; + goto done; + } + + if (finfo1.basic_info.out.create_time != + finfo2.basic_info.out.create_time) { + printf("(%s) create_time changed\n", __location__); + ret = False; + goto done; + } + + if (finfo1.basic_info.out.access_time != + finfo2.basic_info.out.access_time) { + printf("(%s) access_time changed\n", __location__); + ret = False; + goto done; + } + + if (finfo1.basic_info.out.write_time != + finfo2.basic_info.out.write_time) { + printf("(%s) write_time changed\n", __location__); + ret = False; + goto done; + } + + if (finfo1.basic_info.out.change_time != + finfo2.basic_info.out.change_time) { + printf("(%s) change_time changed\n", __location__); + ret = False; + goto done; + } + + /* One of the two following calls updates the qpathinfo. */ + + /* If you had skipped the smbcli_write on fnum2, it would + * *not* have updated the stat on disk */ + + smbcli_close(cli2->tree, fnum2); + torture_close_connection(cli2); + cli2 = NULL; + + /* This call is only for the people looking at ethereal :-) */ + finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO; + finfo2.basic_info.in.fname = fname; + + status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo2); + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status))); + ret = False; + goto done; + } + + done: + if (fnum1 != -1) + smbcli_close(cli->tree, fnum1); + smbcli_unlink(cli->tree, fname); + smbcli_deltree(cli->tree, BASEDIR); + if (cli2 != NULL) { + torture_close_connection(cli2); + } + + return ret; +} + + +/* + testing of delayed update of write_time +*/ +BOOL torture_delay_write(void) +{ + struct smbcli_state *cli; + BOOL ret = True; + TALLOC_CTX *mem_ctx; + + if (!torture_open_connection(&cli)) { + return False; + } + + mem_ctx = talloc_init("torture_delay_write"); + + ret &= test_finfo_after_write(cli, mem_ctx); + ret &= test_delayed_write_update(cli, mem_ctx); + + torture_close_connection(cli); + talloc_destroy(mem_ctx); + return ret; +} diff --git a/source4/torture/basic/dir.c b/source4/torture/basic/dir.c index 7921b3eb03..6e2e21fc08 100644 --- a/source4/torture/basic/dir.c +++ b/source4/torture/basic/dir.c @@ -99,12 +99,7 @@ BOOL torture_dirtest2(void) return False; } - if (smbcli_deltree(cli->tree, "\\LISTDIR") == -1) { - fprintf(stderr,"Failed to deltree %s, error=%s\n", "\\LISTDIR", smbcli_errstr(cli->tree)); - return False; - } - if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, "\\LISTDIR"))) { - fprintf(stderr,"Failed to mkdir %s, error=%s\n", "\\LISTDIR", smbcli_errstr(cli->tree)); + if (!torture_setup_dir(cli, "\\LISTDIR")) { return False; } diff --git a/source4/torture/basic/disconnect.c b/source4/torture/basic/disconnect.c index 683cdb81c8..a225178b96 100644 --- a/source4/torture/basic/disconnect.c +++ b/source4/torture/basic/disconnect.c @@ -136,17 +136,8 @@ BOOL torture_disconnect(void) return False; } - /* cleanup */ - if (smbcli_deltree(cli->tree, BASEDIR) == -1) { - printf("(%s) Failed to cleanup " BASEDIR "\n", __location__); - ret = False; - goto done; - } - - if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, BASEDIR))) { - printf("Failed to create %s\n", BASEDIR); - ret = False; - goto done; + if (!torture_setup_dir(cli, BASEDIR)) { + return False; } for (i=0;i<100;i++) { @@ -161,7 +152,6 @@ BOOL torture_disconnect(void) } } -done: smb_raw_exit(cli->session); smbcli_deltree(cli->tree, BASEDIR); torture_close_connection(cli); diff --git a/source4/torture/basic/mangle_test.c b/source4/torture/basic/mangle_test.c index 8c4f5514a6..70a9227521 100644 --- a/source4/torture/basic/mangle_test.c +++ b/source4/torture/basic/mangle_test.c @@ -167,11 +167,7 @@ BOOL torture_mangle(void) return False; } - smbcli_unlink(cli->tree, "\\mangle_test\\*"); - smbcli_rmdir(cli->tree, "\\mangle_test"); - - if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, "\\mangle_test"))) { - printf("ERROR: Failed to make directory\n"); + if (!torture_setup_dir(cli, "\\mangle_test")) { return False; } diff --git a/source4/torture/basic/utable.c b/source4/torture/basic/utable.c index c09ef576a5..30d389dd92 100644 --- a/source4/torture/basic/utable.c +++ b/source4/torture/basic/utable.c @@ -42,8 +42,9 @@ BOOL torture_utable(void) memset(valid, 0, sizeof(valid)); - smbcli_mkdir(cli->tree, "\\utable"); - smbcli_unlink(cli->tree, "\\utable\\*"); + if (!torture_setup_dir(cli, "\\utable")) { + return False; + } for (c=1; c < 0x10000; c++) { char *p; @@ -133,9 +134,7 @@ BOOL torture_casetable(void) memset(equiv, 0, sizeof(equiv)); - smbcli_deltree(cli->tree, "\\utable"); - if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, "\\utable"))) { - printf("Failed to create utable directory!\n"); + if (!torture_setup_dir(cli, "\\utable")) { return False; } -- cgit