2 Unix SMB/CIFS implementation.
4 test suite for delayed write update
6 Copyright (C) Volker Lendecke 2004
7 Copyright (C) Andrew Tridgell 2004
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include "libcli/raw/libcliraw.h"
26 #include "system/time.h"
28 #define BASEDIR "\\delaywrite"
30 static BOOL test_delayed_write_update(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
32 union smb_fileinfo finfo1, finfo2;
33 const char *fname = BASEDIR "\\torture_file.txt";
40 printf("Testing delayed update of write time\n");
42 if (!torture_setup_dir(cli, BASEDIR)) {
46 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
48 printf("Failed to open %s\n", fname);
52 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
53 finfo1.basic_info.in.fnum = fnum1;
56 status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo1);
58 if (!NT_STATUS_IS_OK(status)) {
59 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
63 printf("Initial write time %s\n",
64 nt_time_string(mem_ctx, finfo1.basic_info.out.write_time));
66 /* 3 second delay to ensure we get past any 2 second time
67 granularity (older systems may have that) */
70 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
73 printf("write failed - wrote %d bytes (%s)\n", written, __location__);
79 while (time(NULL) < t+120) {
80 status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo2);
82 if (!NT_STATUS_IS_OK(status)) {
83 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
87 printf("write time %s\n",
88 nt_time_string(mem_ctx, finfo2.basic_info.out.write_time));
89 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
90 printf("Server updated write_time after %d seconds\n",
91 (int)(time(NULL) - t));
98 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
99 printf("Server did not update write time?!\n");
105 smbcli_close(cli->tree, fnum1);
106 smbcli_unlink(cli->tree, fname);
107 smbcli_deltree(cli->tree, BASEDIR);
113 * Do as above, but using 2 connections.
116 static BOOL test_delayed_write_update2(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
118 struct smbcli_state *cli2=NULL;
119 union smb_fileinfo finfo1, finfo2;
120 const char *fname = BASEDIR "\\torture_file.txt";
127 printf("Testing delayed update of write time using 2 connections\n");
129 if (!torture_open_connection(&cli2)) {
133 if (!torture_setup_dir(cli, BASEDIR)) {
137 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
139 printf("Failed to open %s\n", fname);
143 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
144 finfo1.basic_info.in.fnum = fnum1;
147 status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo1);
149 if (!NT_STATUS_IS_OK(status)) {
150 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
154 printf("Initial write time %s\n",
155 nt_time_string(mem_ctx, finfo1.basic_info.out.write_time));
157 /* 3 second delay to ensure we get past any 2 second time
158 granularity (older systems may have that) */
161 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
164 printf("write failed - wrote %d bytes (%s)\n", written, __location__);
170 while (time(NULL) < t+120) {
171 finfo2.basic_info.in.fname = fname;
173 status = smb_raw_pathinfo(cli2->tree, mem_ctx, &finfo2);
175 if (!NT_STATUS_IS_OK(status)) {
176 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
180 printf("write time %s\n",
181 nt_time_string(mem_ctx, finfo2.basic_info.out.write_time));
182 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
183 printf("Server updated write_time after %d seconds\n",
184 (int)(time(NULL) - t));
191 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
192 printf("Server did not update write time?!\n");
198 torture_close_connection(cli2);
201 smbcli_close(cli->tree, fnum1);
202 smbcli_unlink(cli->tree, fname);
203 smbcli_deltree(cli->tree, BASEDIR);
209 /* Windows does obviously not update the stat info during a write call. I
210 * *think* this is the problem causing a spurious Excel 2003 on XP error
211 * message when saving a file. Excel does a setfileinfo, writes, and then does
212 * a getpath(!)info. Or so... For Samba sometimes it displays an error message
213 * that the file might have been changed in between. What i've been able to
214 * trace down is that this happens if the getpathinfo after the write shows a
215 * different last write time than the setfileinfo showed. This is really
219 static BOOL test_finfo_after_write(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
221 union smb_fileinfo finfo1, finfo2;
222 const char *fname = BASEDIR "\\torture_file.txt";
228 struct smbcli_state *cli2=NULL;
230 printf("Testing finfo update on close\n");
232 if (!torture_setup_dir(cli, BASEDIR)) {
236 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
242 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
243 finfo1.basic_info.in.fnum = fnum1;
245 status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo1);
247 if (!NT_STATUS_IS_OK(status)) {
248 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
255 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
258 printf("(%s) written gave %d - should have been 1\n",
259 __location__, written);
264 if (!torture_open_connection(&cli2)) {
268 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
270 printf("(%s) failed to open 2nd time - %s\n",
271 __location__, smbcli_errstr(cli2->tree));
276 written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 1);
279 printf("(%s) written gave %d - should have been 1\n",
280 __location__, written);
285 finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
286 finfo2.basic_info.in.fname = fname;
288 status = smb_raw_pathinfo(cli2->tree, mem_ctx, &finfo2);
290 if (!NT_STATUS_IS_OK(status)) {
291 DEBUG(0, ("(%s) fileinfo failed: %s\n",
292 __location__, nt_errstr(status)));
297 if (finfo1.basic_info.out.create_time !=
298 finfo2.basic_info.out.create_time) {
299 printf("(%s) create_time changed\n", __location__);
304 if (finfo1.basic_info.out.access_time !=
305 finfo2.basic_info.out.access_time) {
306 printf("(%s) access_time changed\n", __location__);
311 if (finfo1.basic_info.out.write_time !=
312 finfo2.basic_info.out.write_time) {
313 printf("(%s) write_time changed\n", __location__);
318 if (finfo1.basic_info.out.change_time !=
319 finfo2.basic_info.out.change_time) {
320 printf("(%s) change_time changed\n", __location__);
325 /* One of the two following calls updates the qpathinfo. */
327 /* If you had skipped the smbcli_write on fnum2, it would
328 * *not* have updated the stat on disk */
330 smbcli_close(cli2->tree, fnum2);
331 torture_close_connection(cli2);
334 /* This call is only for the people looking at ethereal :-) */
335 finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
336 finfo2.basic_info.in.fname = fname;
338 status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo2);
340 if (!NT_STATUS_IS_OK(status)) {
341 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
348 smbcli_close(cli->tree, fnum1);
349 smbcli_unlink(cli->tree, fname);
350 smbcli_deltree(cli->tree, BASEDIR);
352 torture_close_connection(cli2);
360 testing of delayed update of write_time
362 BOOL torture_delay_write(void)
364 struct smbcli_state *cli;
368 if (!torture_open_connection(&cli)) {
372 mem_ctx = talloc_init("torture_delay_write");
374 ret &= test_finfo_after_write(cli, mem_ctx);
375 ret &= test_delayed_write_update(cli, mem_ctx);
376 ret &= test_delayed_write_update2(cli, mem_ctx);
378 torture_close_connection(cli);
379 talloc_destroy(mem_ctx);