static void unlock_byte(struct smbcli_state *cli, int fd, int offset) { union smb_lock io; struct smb_lock_entry lock; NTSTATUS status; ZERO_STRUCT(lock); io.lockx.in.ulock_cnt = 1; io.lockx.in.lock_cnt = 0; lock.count = 1; lock.offset = offset; lock.pid = cli->tree->session->pid; io.lockx.level = RAW_LOCK_LOCKX; io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; io.lockx.in.timeout = 100000; io.lockx.in.locks = &lock; io.lockx.in.file.fnum = fd; status = smb_raw_lock(cli->tree, &io); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("Unlock failed\n")); exit(1); } }
/* test disconnect with timed lock */ static bool test_disconnect_lock(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) { union smb_lock io; NTSTATUS status; int fnum; struct smbcli_request *req; struct smb_lock_entry lock[1]; printf("trying disconnect with async lock\n"); fnum = smbcli_open(cli->tree, BASEDIR "\\write.dat", O_RDWR | O_CREAT, DENY_NONE); if (fnum == -1) { printf("open failed in mux_write - %s\n", smbcli_errstr(cli->tree)); return false; } io.lockx.level = RAW_LOCK_LOCKX; io.lockx.in.file.fnum = fnum; io.lockx.in.mode = 0; io.lockx.in.timeout = 0; io.lockx.in.lock_cnt = 1; io.lockx.in.ulock_cnt = 0; lock[0].pid = 1; lock[0].offset = 0; lock[0].count = 4; io.lockx.in.locks = &lock[0]; status = smb_raw_lock(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); lock[0].pid = 2; io.lockx.in.timeout = 3000; req = smb_raw_lock_send(cli->tree, &io); if (!req) { printf("test_disconnect_lock: smb_raw_lock_send() " "returned NULL\n"); return false; } status = smbcli_chkpath(cli->tree, "\\"); CHECK_STATUS(status, NT_STATUS_OK); talloc_free(cli); return true; }
/* lock a byte range */ static NTSTATUS cvfs_lock(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_lock *io) { struct cvfs_private *p = ntvfs->private_data; struct smbcli_request *c_req; SETUP_PID; if (io->generic.level != RAW_LOCK_GENERIC && p->map_generic) { return ntvfs_map_lock(ntvfs, req, io); } SETUP_FILE; if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { return smb_raw_lock(p->tree, io); } c_req = smb_raw_lock_send(p->tree, io); SIMPLE_ASYNC_TAIL; }
static void lock_byte(struct smbcli_state *cli, int fd, int offset, int lock_timeout) { union smb_lock io; struct smb_lock_entry lock; NTSTATUS status; try_again: ZERO_STRUCT(lock); io.lockx.in.ulock_cnt = 0; io.lockx.in.lock_cnt = 1; lock.count = 1; lock.offset = offset; lock.pid = cli->tree->session->pid; io.lockx.level = RAW_LOCK_LOCKX; io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; io.lockx.in.timeout = lock_timeout; io.lockx.in.locks = &lock; io.lockx.in.file.fnum = fd; status = smb_raw_lock(cli->tree, &io); /* If we dont use timeouts and we got file lock conflict just try the lock again. */ if (lock_timeout==0) { if ( (NT_STATUS_EQUAL(NT_STATUS_FILE_LOCK_CONFLICT, status)) ||(NT_STATUS_EQUAL(NT_STATUS_LOCK_NOT_GRANTED, status)) ) { goto try_again; } } if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("Lock failed\n")); exit(1); } }
/* test a lock that conflicts with an existing lock */ static bool test_mux_lock(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) { union smb_lock io; NTSTATUS status; int fnum; bool ret = true; struct smbcli_request *req; struct smb_lock_entry lock[1]; struct timeval t; printf("TESTING MULTIPLEXED LOCK/LOCK/UNLOCK\n"); fnum = smbcli_open(cli->tree, BASEDIR "\\write.dat", O_RDWR | O_CREAT, DENY_NONE); if (fnum == -1) { printf("open failed in mux_write - %s\n", smbcli_errstr(cli->tree)); ret = false; goto done; } printf("establishing a lock\n"); io.lockx.level = RAW_LOCK_LOCKX; io.lockx.in.file.fnum = fnum; io.lockx.in.mode = 0; io.lockx.in.timeout = 0; io.lockx.in.lock_cnt = 1; io.lockx.in.ulock_cnt = 0; lock[0].pid = 1; lock[0].offset = 0; lock[0].count = 4; io.lockx.in.locks = &lock[0]; status = smb_raw_lock(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); printf("the second lock will conflict with the first\n"); lock[0].pid = 2; io.lockx.in.timeout = 1000; status = smb_raw_lock(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); printf("this will too, but we'll unlock while waiting\n"); t = timeval_current(); req = smb_raw_lock_send(cli->tree, &io); printf("unlock the first range\n"); lock[0].pid = 1; io.lockx.in.ulock_cnt = 1; io.lockx.in.lock_cnt = 0; io.lockx.in.timeout = 0; status = smb_raw_lock(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); printf("recv the async reply\n"); status = smbcli_request_simple_recv(req); CHECK_STATUS(status, NT_STATUS_OK); printf("async lock took %.2f msec\n", timeval_elapsed(&t) * 1000); if (timeval_elapsed(&t) > 0.1) { printf("failed to trigger early lock retry\n"); return false; } printf("reopening with an exit\n"); smb_raw_exit(cli->session); fnum = smbcli_open(cli->tree, BASEDIR "\\write.dat", O_RDWR | O_CREAT, DENY_NONE); printf("Now trying with a cancel\n"); io.lockx.level = RAW_LOCK_LOCKX; io.lockx.in.file.fnum = fnum; io.lockx.in.mode = 0; io.lockx.in.timeout = 0; io.lockx.in.lock_cnt = 1; io.lockx.in.ulock_cnt = 0; lock[0].pid = 1; lock[0].offset = 0; lock[0].count = 4; io.lockx.in.locks = &lock[0]; status = smb_raw_lock(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); lock[0].pid = 2; io.lockx.in.timeout = 1000; status = smb_raw_lock(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); req = smb_raw_lock_send(cli->tree, &io); /* cancel the blocking lock */ smb_raw_ntcancel(req); printf("sending 2nd cancel\n"); /* the 2nd cancel is totally harmless, but tests the server trying to cancel an already cancelled request */ smb_raw_ntcancel(req); printf("sent 2nd cancel\n"); lock[0].pid = 1; io.lockx.in.ulock_cnt = 1; io.lockx.in.lock_cnt = 0; io.lockx.in.timeout = 0; status = smb_raw_lock(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); status = smbcli_request_simple_recv(req); CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); printf("cancel a lock using exit to close file\n"); lock[0].pid = 1; io.lockx.in.ulock_cnt = 0; io.lockx.in.lock_cnt = 1; io.lockx.in.timeout = 1000; status = smb_raw_lock(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); t = timeval_current(); lock[0].pid = 2; req = smb_raw_lock_send(cli->tree, &io); smb_raw_exit(cli->session); smb_raw_exit(cli->session); smb_raw_exit(cli->session); smb_raw_exit(cli->session); printf("recv the async reply\n"); status = smbcli_request_simple_recv(req); CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED); printf("async lock exit took %.2f msec\n", timeval_elapsed(&t) * 1000); if (timeval_elapsed(&t) > 0.1) { printf("failed to trigger early lock failure\n"); return false; } done: return ret; }
bool torture_samba3_posixtimedlock(struct torture_context *tctx, struct smbcli_state *cli) { NTSTATUS status; bool ret = true; const char *dirname = "posixlock"; const char *fname = "locked"; const char *fpath; const char *localdir; const char *localname; int fnum = -1; int fd = -1; struct flock posix_lock; union smb_lock io; struct smb_lock_entry lock_entry; struct smbcli_request *req; struct lock_result_state lock_result; struct tevent_timer *te; torture_assert(tctx, torture_setup_dir(cli, dirname), "creating test directory"); if (!(fpath = talloc_asprintf(tctx, "%s\\%s", dirname, fname))) { torture_warning(tctx, "talloc failed\n"); ret = false; goto done; } fnum = smbcli_open(cli->tree, fpath, O_RDWR | O_CREAT, DENY_NONE); if (fnum == -1) { torture_warning(tctx, "Could not create file %s: %s\n", fpath, smbcli_errstr(cli->tree)); ret = false; goto done; } if (!(localdir = torture_setting_string(tctx, "localdir", NULL))) { torture_warning(tctx, "Need 'localdir' setting\n"); ret = false; goto done; } if (!(localname = talloc_asprintf(tctx, "%s/%s/%s", localdir, dirname, fname))) { torture_warning(tctx, "talloc failed\n"); ret = false; goto done; } /* * Lock a byte range from posix */ fd = open(localname, O_RDWR); if (fd == -1) { torture_warning(tctx, "open(%s) failed: %s\n", localname, strerror(errno)); goto done; } posix_lock.l_type = F_WRLCK; posix_lock.l_whence = SEEK_SET; posix_lock.l_start = 0; posix_lock.l_len = 1; if (fcntl(fd, F_SETLK, &posix_lock) == -1) { torture_warning(tctx, "fcntl failed: %s\n", strerror(errno)); ret = false; goto done; } /* * Try a cifs brlock without timeout to see if posix locking = yes */ io.lockx.in.ulock_cnt = 0; io.lockx.in.lock_cnt = 1; lock_entry.count = 1; lock_entry.offset = 0; lock_entry.pid = cli->tree->session->pid; io.lockx.level = RAW_LOCK_LOCKX; io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; io.lockx.in.timeout = 0; io.lockx.in.locks = &lock_entry; io.lockx.in.file.fnum = fnum; status = smb_raw_lock(cli->tree, &io); ret = true; CHECK_STATUS(tctx, status, NT_STATUS_FILE_LOCK_CONFLICT); if (!ret) { goto done; } /* * Now fire off a timed brlock, unlock the posix lock and see if the * timed lock gets through. */ io.lockx.in.timeout = 5000; req = smb_raw_lock_send(cli->tree, &io); if (req == NULL) { torture_warning(tctx, "smb_raw_lock_send failed\n"); ret = false; goto done; } lock_result.done = false; req->async.fn = receive_lock_result; req->async.private_data = &lock_result; te = tevent_add_timer(tctx->ev, tctx, timeval_current_ofs(1, 0), close_locked_file, &fd); if (te == NULL) { torture_warning(tctx, "tevent_add_timer failed\n"); ret = false; goto done; } while ((fd != -1) || (!lock_result.done)) { if (tevent_loop_once(tctx->ev) == -1) { torture_warning(tctx, "tevent_loop_once failed: %s\n", strerror(errno)); ret = false; goto done; } } CHECK_STATUS(tctx, lock_result.status, NT_STATUS_OK); done: if (fnum != -1) { smbcli_close(cli->tree, fnum); } if (fd != -1) { close(fd); } smbcli_deltree(cli->tree, dirname); return ret; }
static bool test_one(struct smbcli_state *cli[NSERVERS][NCONNECTIONS], int fnum[NSERVERS][NCONNECTIONS][NFILES], struct record *rec) { unsigned int conn = rec->conn; unsigned int f = rec->f; uint64_t start = rec->start; uint64_t len = rec->len; enum brl_type op = rec->lock_type; int server; bool ret[NSERVERS]; NTSTATUS status[NSERVERS]; switch (rec->lock_op) { case OP_LOCK: /* set a lock */ for (server=0;server<NSERVERS;server++) { NTSTATUS res; struct smbcli_tree *tree=cli[server][conn]->tree; int fn=fnum[server][conn][f]; if (!(tree->session->transport->negotiate.capabilities & CAP_LARGE_FILES)) { res=smbcli_lock(tree, fn, start, len, LOCK_TIMEOUT, rec->lock_op); } else { union smb_lock parms; int ltype; struct smb_lock_entry lock[1]; parms.lockx.level = RAW_LOCK_LOCKX; parms.lockx.in.file.fnum = fn; ltype = (rec->lock_op == READ_LOCK? 1 : 0); ltype |= LOCKING_ANDX_LARGE_FILES; parms.lockx.in.mode = ltype; parms.lockx.in.timeout = LOCK_TIMEOUT; parms.lockx.in.ulock_cnt = 0; parms.lockx.in.lock_cnt = 1; lock[0].pid = rec->pid; lock[0].offset = start; lock[0].count = len; parms.lockx.in.locks = &lock[0]; res = smb_raw_lock(tree, &parms); } ret[server] = NT_STATUS_IS_OK(res); status[server] = smbcli_nt_error(cli[server][conn]->tree); if (!exact_error_codes && NT_STATUS_EQUAL(status[server], NT_STATUS_FILE_LOCK_CONFLICT)) { status[server] = NT_STATUS_LOCK_NOT_GRANTED; } } if (showall || !NT_STATUS_EQUAL(status[0],status[1])) { printf("lock conn=%u f=%u range=%.0f(%.0f) op=%s -> %s:%s\n", conn, f, (double)start, (double)len, op==READ_LOCK?"READ_LOCK":"WRITE_LOCK", nt_errstr(status[0]), nt_errstr(status[1])); } if (!NT_STATUS_EQUAL(status[0],status[1])) return false; break; case OP_UNLOCK: /* unset a lock */ for (server=0;server<NSERVERS;server++) { NTSTATUS res; struct smbcli_tree *tree=cli[server][conn]->tree; int fn=fnum[server][conn][f]; if (!(tree->session->transport->negotiate.capabilities & CAP_LARGE_FILES)) { res=smbcli_unlock(tree, fn, start, len); } else { union smb_lock parms; struct smb_lock_entry lock[1]; parms.lockx.level = RAW_LOCK_LOCKX; parms.lockx.in.file.fnum = fn; parms.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; parms.lockx.in.timeout = 0; parms.lockx.in.ulock_cnt = 1; parms.lockx.in.lock_cnt = 0; lock[0].pid = rec->pid; lock[0].count = len; lock[0].offset = start; parms.lockx.in.locks = &lock[0]; res = smb_raw_lock(tree, &parms); } ret[server] = NT_STATUS_IS_OK(res); status[server] = smbcli_nt_error(cli[server][conn]->tree); } if (showall || (!hide_unlock_fails && !NT_STATUS_EQUAL(status[0],status[1]))) { printf("unlock conn=%u f=%u range=%.0f(%.0f) -> %s:%s\n", conn, f, (double)start, (double)len, nt_errstr(status[0]), nt_errstr(status[1])); } if (!hide_unlock_fails && !NT_STATUS_EQUAL(status[0],status[1])) return false; break; case OP_REOPEN: /* reopen the file */ for (server=0;server<NSERVERS;server++) { smbcli_close(cli[server][conn]->tree, fnum[server][conn][f]); fnum[server][conn][f] = -1; } for (server=0;server<NSERVERS;server++) { fnum[server][conn][f] = smbcli_open(cli[server][conn]->tree, FILENAME, O_RDWR|O_CREAT, DENY_NONE); if (fnum[server][conn][f] == -1) { printf("failed to reopen on share%d\n", server); return false; } } if (showall) { printf("reopen conn=%u f=%u\n", conn, f); } break; } return true; }