diff options
author | Volker Lendecke <vl@samba.org> | 2019-08-01 14:47:41 +0200 |
---|---|---|
committer | Jeremy Allison <jra@samba.org> | 2019-08-08 01:05:38 +0000 |
commit | 897c36f2cb7de561394ab15e8134fb6e5b91ae63 (patch) | |
tree | 7fc84441aaaa0eb9dd3daab4d235f244e09a70a1 /source3/torture | |
parent | 4c08043ee54350c7c66a963882d4e14c24472986 (diff) | |
download | samba-897c36f2cb7de561394ab15e8134fb6e5b91ae63.tar.gz |
torture: SMB1 unlink needs delay for a stream's SHARING_VIOLATION
Survives against W2k12R2
Signed-off-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
Autobuild-User(master): Jeremy Allison <jra@samba.org>
Autobuild-Date(master): Thu Aug 8 01:05:38 UTC 2019 on sn-devel-184
Diffstat (limited to 'source3/torture')
-rw-r--r-- | source3/torture/torture.c | 238 |
1 files changed, 238 insertions, 0 deletions
diff --git a/source3/torture/torture.c b/source3/torture/torture.c index 2779e8e3aa8..7ead71c644d 100644 --- a/source3/torture/torture.c +++ b/source3/torture/torture.c @@ -5643,6 +5643,240 @@ static bool run_deletetest(int dummy) return correct; } +struct delete_stream_state { + bool closed; +}; + +static void delete_stream_unlinked(struct tevent_req *subreq); +static void delete_stream_closed(struct tevent_req *subreq); + +static struct tevent_req *delete_stream_send( + TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct cli_state *cli, + const char *base_fname, + uint16_t stream_fnum) +{ + struct tevent_req *req = NULL, *subreq = NULL; + struct delete_stream_state *state = NULL; + + req = tevent_req_create( + mem_ctx, &state, struct delete_stream_state); + if (req == NULL) { + return NULL; + } + + subreq = cli_unlink_send( + state, + ev, + cli, + base_fname, + FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, delete_stream_unlinked, req); + + subreq = cli_close_send(state, ev, cli, stream_fnum); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, delete_stream_closed, req); + + return req; +} + +static void delete_stream_unlinked(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct delete_stream_state *state = tevent_req_data( + req, struct delete_stream_state); + NTSTATUS status; + + status = cli_unlink_recv(subreq); + TALLOC_FREE(subreq); + if (!NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) { + printf("cli_unlink returned %s\n", + nt_errstr(status)); + tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL); + return; + } + if (!state->closed) { + /* close reply should have come in first */ + printf("Not closed\n"); + tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL); + return; + } + tevent_req_done(req); +} + +static void delete_stream_closed(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct delete_stream_state *state = tevent_req_data( + req, struct delete_stream_state); + NTSTATUS status; + + status = cli_close_recv(subreq); + TALLOC_FREE(subreq); + if (tevent_req_nterror(req, status)) { + return; + } + /* also waiting for the unlink to come back */ + state->closed = true; +} + +static NTSTATUS delete_stream_recv(struct tevent_req *req) +{ + return tevent_req_simple_recv_ntstatus(req); +} + +static bool run_delete_stream(int dummy) +{ + struct tevent_context *ev = NULL; + struct tevent_req *req = NULL; + struct cli_state *cli = NULL; + const char fname[] = "delete_stream"; + const char fname_stream[] = "delete_stream:Zone.Identifier:$DATA"; + uint16_t fnum1, fnum2; + NTSTATUS status; + bool ok; + + printf("Starting stream delete test\n"); + + ok = torture_open_connection(&cli, 0); + if (!ok) { + return false; + } + + cli_setatr(cli, fname, 0, 0); + cli_unlink(cli, fname, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN); + + /* Create the file. */ + status = cli_ntcreate( + cli, + fname, + 0, + READ_CONTROL_ACCESS, + 0, + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, + FILE_CREATE, + 0x0, + 0x0, + &fnum1, + NULL); + if (!NT_STATUS_IS_OK(status)) { + d_fprintf(stderr, + "cli_ntcreate of %s failed (%s)\n", + fname, + nt_errstr(status)); + return false; + } + status = cli_close(cli, fnum1); + if (!NT_STATUS_IS_OK(status)) { + d_fprintf(stderr, + "cli_close of %s failed (%s)\n", + fname, + nt_errstr(status)); + return false; + } + + /* Now create the stream. */ + status = cli_ntcreate( + cli, + fname_stream, + 0, + FILE_WRITE_DATA, + 0, + FILE_SHARE_READ|FILE_SHARE_WRITE, + FILE_CREATE, + 0x0, + 0x0, + &fnum1, + NULL); + + if (!NT_STATUS_IS_OK(status)) { + d_fprintf(stderr, + "cli_ntcreate of %s failed (%s)\n", + fname_stream, + nt_errstr(status)); + return false; + } + + /* open it a second time */ + + status = cli_ntcreate( + cli, + fname_stream, + 0, + FILE_WRITE_DATA, + 0, + FILE_SHARE_READ|FILE_SHARE_WRITE, + FILE_OPEN, + 0x0, + 0x0, + &fnum2, + NULL); + + if (!NT_STATUS_IS_OK(status)) { + d_fprintf(stderr, + "2nd cli_ntcreate of %s failed (%s)\n", + fname_stream, + nt_errstr(status)); + return false; + } + + ev = samba_tevent_context_init(talloc_tos()); + if (ev == NULL) { + d_fprintf(stderr, "samba_tevent_context_init failed\n"); + return false; + } + + req = delete_stream_send(ev, ev, cli, fname, fnum1); + if (req == NULL) { + d_fprintf(stderr, "delete_stream_send failed\n"); + return false; + } + + ok = tevent_req_poll_ntstatus(req, ev, &status); + if (!ok) { + d_fprintf(stderr, + "tevent_req_poll_ntstatus failed: %s\n", + nt_errstr(status)); + return false; + } + + status = delete_stream_recv(req); + TALLOC_FREE(req); + if (!NT_STATUS_IS_OK(status)) { + d_fprintf(stderr, + "delete_stream failed: %s\n", + nt_errstr(status)); + return false; + } + + status = cli_close(cli, fnum2); + if (!NT_STATUS_IS_OK(status)) { + d_fprintf(stderr, + "close failed: %s\n", + nt_errstr(status)); + return false; + } + + status = cli_unlink( + cli, fname, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN); + if (!NT_STATUS_IS_OK(status)) { + d_fprintf(stderr, + "unlink failed: %s\n", + nt_errstr(status)); + return false; + } + + return true; +} + /* Exercise delete on close semantics - use on the PRINT1 share in torture testing. @@ -14139,6 +14373,10 @@ static struct { .fn = run_deletetest, }, { + .name = "DELETE-STREAM", + .fn = run_delete_stream, + }, + { .name = "DELETE-PRINT", .fn = run_delete_print_test, }, |