static void generic_blocking_lock_error(struct blocking_lock_record *blr, NTSTATUS status) { /* whenever a timeout is given w2k maps LOCK_NOT_GRANTED to FILE_LOCK_CONFLICT! (tridge) */ if (NT_STATUS_EQUAL(status, NT_STATUS_LOCK_NOT_GRANTED)) { status = NT_STATUS_FILE_LOCK_CONFLICT; } if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_LOCK_CONFLICT)) { /* Store the last lock error. */ files_struct *fsp = blr->fsp; if (fsp) { fsp->last_lock_failure.context.smbpid = blr->lock_pid; fsp->last_lock_failure.context.tid = fsp->conn->cnum; fsp->last_lock_failure.context.pid = procid_self(); fsp->last_lock_failure.start = blr->offset; fsp->last_lock_failure.size = blr->count; fsp->last_lock_failure.fnum = fsp->fnum; fsp->last_lock_failure.lock_type = READ_LOCK; /* Don't care. */ fsp->last_lock_failure.lock_flav = blr->lock_flav; } } reply_nterror(blr->req, status); if (!srv_send_smb(smbd_server_fd(), (char *)blr->req->outbuf, true, blr->req->seqnum+1, blr->req->encrypted, NULL)) { exit_server_cleanly("generic_blocking_lock_error: srv_send_smb failed."); } TALLOC_FREE(blr->req->outbuf); }
static void blocking_lock_reply_error(struct blocking_lock_record *blr, NTSTATUS status) { DEBUG(10, ("Replying with error=%s. BLR = %p\n", nt_errstr(status), blr)); switch(blr->req->cmd) { case SMBlockingX: reply_lockingX_error(blr, status); break; case SMBtrans2: case SMBtranss2: reply_nterror(blr->req, status); /* * construct_reply_common has done us the favor to pre-fill * the command field with SMBtranss2 which is wrong :-) */ SCVAL(blr->req->outbuf,smb_com,SMBtrans2); if (!srv_send_smb(smbd_server_fd(), (char *)blr->req->outbuf, true, blr->req->seqnum+1, IS_CONN_ENCRYPTED(blr->fsp->conn), NULL)) { exit_server_cleanly("blocking_lock_reply_error: " "srv_send_smb failed."); } TALLOC_FREE(blr->req->outbuf); break; default: DEBUG(0,("blocking_lock_reply_error: PANIC - unknown type on blocking lock queue - exiting.!\n")); exit_server("PANIC - unknown type on blocking lock queue"); } }
static void reply_lockingX_success(struct blocking_lock_record *blr) { struct smb_request *req = blr->req; reply_outbuf(req, 2, 0); SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */ SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */ /* * As this message is a lockingX call we must handle * any following chained message correctly. * This is normally handled in construct_reply(), * but as that calls switch_message, we can't use * that here and must set up the chain info manually. */ if (!srv_send_smb(req->sconn, (char *)req->outbuf, true, req->seqnum+1, IS_CONN_ENCRYPTED(req->conn)||req->encrypted, &req->pcd)) { exit_server_cleanly("construct_reply: srv_send_smb failed."); } TALLOC_FREE(req->outbuf); }
static void send_break_message_smb1(files_struct *fsp, int level) { char break_msg[SMB1_BREAK_MESSAGE_LENGTH]; new_break_message_smb1(fsp, level, break_msg); show_msg(break_msg); if (!srv_send_smb(fsp->conn->sconn, break_msg, false, 0, IS_CONN_ENCRYPTED(fsp->conn), NULL)) { exit_server_cleanly("send_break_message_smb1: " "srv_send_smb failed."); } }
static void blocking_lock_reply_error(struct blocking_lock_record *blr, NTSTATUS status) { DEBUG(10, ("Replying with error=%s. BLR = %p\n", nt_errstr(status), blr)); switch(blr->req->cmd) { case SMBlockingX: /* * This code can be called during the rundown of a * file after it was already closed. In that case, * blr->fsp==NULL and we do not need to undo any * locks, they are already gone. */ if (blr->fsp != NULL) { undo_locks_obtained(blr); } generic_blocking_lock_error(blr, status); break; case SMBtrans2: case SMBtranss2: reply_nterror(blr->req, status); /* * construct_reply_common has done us the favor to pre-fill * the command field with SMBtranss2 which is wrong :-) */ SCVAL(blr->req->outbuf,smb_com,SMBtrans2); if (!srv_send_smb(blr->req->sconn, (char *)blr->req->outbuf, true, blr->req->seqnum+1, IS_CONN_ENCRYPTED(blr->fsp->conn), NULL)) { exit_server_cleanly("blocking_lock_reply_error: " "srv_send_smb failed."); } TALLOC_FREE(blr->req->outbuf); break; default: DEBUG(0,("blocking_lock_reply_error: PANIC - unknown type on blocking lock queue - exiting.!\n")); exit_server("PANIC - unknown type on blocking lock queue"); } }
void send_trans_reply(connection_struct *conn, struct smb_request *req, char *rparam, int rparam_len, char *rdata, int rdata_len, bool buffer_too_large) { int this_ldata,this_lparam; int tot_data_sent = 0; int tot_param_sent = 0; int align; int ldata = rdata ? rdata_len : 0; int lparam = rparam ? rparam_len : 0; struct smbd_server_connection *sconn = req->sconn; int max_send = sconn->smb1.sessions.max_send; if (buffer_too_large) DEBUG(5,("send_trans_reply: buffer %d too large\n", ldata )); this_lparam = MIN(lparam,max_send - 500); /* hack */ this_ldata = MIN(ldata,max_send - (500+this_lparam)); align = ((this_lparam)%4); reply_outbuf(req, 10, 1+align+this_ldata+this_lparam); /* * We might have SMBtranss in req which was transferred to the outbuf, * fix that. */ SCVAL(req->outbuf, smb_com, SMBtrans); copy_trans_params_and_data((char *)req->outbuf, align, rparam, tot_param_sent, this_lparam, rdata, tot_data_sent, this_ldata); SSVAL(req->outbuf,smb_vwv0,lparam); SSVAL(req->outbuf,smb_vwv1,ldata); SSVAL(req->outbuf,smb_vwv3,this_lparam); SSVAL(req->outbuf,smb_vwv4, smb_offset(smb_buf(req->outbuf)+1, req->outbuf)); SSVAL(req->outbuf,smb_vwv5,0); SSVAL(req->outbuf,smb_vwv6,this_ldata); SSVAL(req->outbuf,smb_vwv7, smb_offset(smb_buf(req->outbuf)+1+this_lparam+align, req->outbuf)); SSVAL(req->outbuf,smb_vwv8,0); SSVAL(req->outbuf,smb_vwv9,0); if (buffer_too_large) { error_packet_set((char *)req->outbuf, ERRDOS, ERRmoredata, STATUS_BUFFER_OVERFLOW, __LINE__, __FILE__); } show_msg((char *)req->outbuf); if (!srv_send_smb(sconn, (char *)req->outbuf, true, req->seqnum+1, IS_CONN_ENCRYPTED(conn), &req->pcd)) { exit_server_cleanly("send_trans_reply: srv_send_smb failed."); } TALLOC_FREE(req->outbuf); tot_data_sent = this_ldata; tot_param_sent = this_lparam; while (tot_data_sent < ldata || tot_param_sent < lparam) { this_lparam = MIN(lparam-tot_param_sent, max_send - 500); /* hack */ this_ldata = MIN(ldata -tot_data_sent, max_send - (500+this_lparam)); if(this_lparam < 0) this_lparam = 0; if(this_ldata < 0) this_ldata = 0; align = (this_lparam%4); reply_outbuf(req, 10, 1+align+this_ldata+this_lparam); /* * We might have SMBtranss in req which was transferred to the * outbuf, fix that. */ SCVAL(req->outbuf, smb_com, SMBtrans); copy_trans_params_and_data((char *)req->outbuf, align, rparam, tot_param_sent, this_lparam, rdata, tot_data_sent, this_ldata); SSVAL(req->outbuf,smb_vwv0,lparam); SSVAL(req->outbuf,smb_vwv1,ldata); SSVAL(req->outbuf,smb_vwv3,this_lparam); SSVAL(req->outbuf,smb_vwv4, smb_offset(smb_buf(req->outbuf)+1,req->outbuf)); SSVAL(req->outbuf,smb_vwv5,tot_param_sent); SSVAL(req->outbuf,smb_vwv6,this_ldata); SSVAL(req->outbuf,smb_vwv7, smb_offset(smb_buf(req->outbuf)+1+this_lparam+align, req->outbuf)); SSVAL(req->outbuf,smb_vwv8,tot_data_sent); SSVAL(req->outbuf,smb_vwv9,0); if (buffer_too_large) { error_packet_set((char *)req->outbuf, ERRDOS, ERRmoredata, STATUS_BUFFER_OVERFLOW, __LINE__, __FILE__); } show_msg((char *)req->outbuf); if (!srv_send_smb(sconn, (char *)req->outbuf, true, req->seqnum+1, IS_CONN_ENCRYPTED(conn), &req->pcd)) exit_server_cleanly("send_trans_reply: srv_send_smb " "failed."); tot_data_sent += this_ldata; tot_param_sent += this_lparam; TALLOC_FREE(req->outbuf); } }
NTSTATUS schedule_aio_write_and_X(connection_struct *conn, struct smb_request *smbreq, files_struct *fsp, const char *data, SMB_OFF_T startpos, size_t numtowrite) { struct aio_extra *aio_ex; SMB_STRUCT_AIOCB *a; size_t bufsize; size_t min_aio_write_size = lp_aio_write_size(SNUM(conn)); int ret; /* Ensure aio is initialized. */ if (!initialize_async_io_handler()) { return NT_STATUS_RETRY; } if (fsp->base_fsp != NULL) { /* No AIO on streams yet */ DEBUG(10, ("AIO on streams not yet supported\n")); return NT_STATUS_RETRY; } if ((!min_aio_write_size || (numtowrite < min_aio_write_size)) && !SMB_VFS_AIO_FORCE(fsp)) { /* Too small a write for aio request. */ DEBUG(10,("schedule_aio_write_and_X: write size (%u) too " "small for minimum aio_write of %u\n", (unsigned int)numtowrite, (unsigned int)min_aio_write_size )); return NT_STATUS_RETRY; } /* Only do this on non-chained and non-chaining writes not using the * write cache. */ if (req_is_in_chain(smbreq) || (lp_write_cache_size(SNUM(conn)) != 0)) { return NT_STATUS_RETRY; } if (outstanding_aio_calls >= aio_pending_size) { DEBUG(3,("schedule_aio_write_and_X: Already have %d aio " "activities outstanding.\n", outstanding_aio_calls )); DEBUG(10,("schedule_aio_write_and_X: failed to schedule " "aio_write for file %s, offset %.0f, len = %u " "(mid = %u)\n", fsp_str_dbg(fsp), (double)startpos, (unsigned int)numtowrite, (unsigned int)smbreq->mid )); return NT_STATUS_RETRY; } bufsize = smb_size + 6*2; if (!(aio_ex = create_aio_extra(NULL, fsp, bufsize))) { DEBUG(0,("schedule_aio_write_and_X: malloc fail.\n")); return NT_STATUS_NO_MEMORY; } aio_ex->handle_completion = handle_aio_write_complete; aio_ex->write_through = BITSETW(smbreq->vwv+7,0); construct_reply_common_req(smbreq, (char *)aio_ex->outbuf.data); srv_set_message((char *)aio_ex->outbuf.data, 6, 0, True); SCVAL(aio_ex->outbuf.data,smb_vwv0,0xFF); /* Never a chained reply. */ init_strict_lock_struct(fsp, (uint64_t)smbreq->smbpid, (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK, &aio_ex->lock); /* Take the lock until the AIO completes. */ if (!SMB_VFS_STRICT_LOCK(conn, fsp, &aio_ex->lock)) { TALLOC_FREE(aio_ex); return NT_STATUS_FILE_LOCK_CONFLICT; } a = &aio_ex->acb; /* Now set up the aio record for the write call. */ a->aio_fildes = fsp->fh->fd; a->aio_buf = discard_const_p(char, data); a->aio_nbytes = numtowrite; a->aio_offset = startpos; a->aio_sigevent.sigev_notify = SIGEV_SIGNAL; a->aio_sigevent.sigev_signo = RT_SIGNAL_AIO; a->aio_sigevent.sigev_value.sival_ptr = aio_ex; ret = SMB_VFS_AIO_WRITE(fsp, a); if (ret == -1) { DEBUG(3,("schedule_aio_wrote_and_X: aio_write failed. " "Error %s\n", strerror(errno) )); SMB_VFS_STRICT_UNLOCK(conn, fsp, &aio_ex->lock); TALLOC_FREE(aio_ex); return NT_STATUS_RETRY; } outstanding_aio_calls++; aio_ex->smbreq = talloc_move(aio_ex, &smbreq); /* This should actually be improved to span the write. */ contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_WRITE); contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_WRITE); if (!aio_ex->write_through && !lp_syncalways(SNUM(fsp->conn)) && fsp->aio_write_behind) { /* Lie to the client and immediately claim we finished the * write. */ SSVAL(aio_ex->outbuf.data,smb_vwv2,numtowrite); SSVAL(aio_ex->outbuf.data,smb_vwv4,(numtowrite>>16)&1); show_msg((char *)aio_ex->outbuf.data); if (!srv_send_smb(aio_ex->smbreq->sconn, (char *)aio_ex->outbuf.data, true, aio_ex->smbreq->seqnum+1, IS_CONN_ENCRYPTED(fsp->conn), &aio_ex->smbreq->pcd)) { exit_server_cleanly("schedule_aio_write_and_X: " "srv_send_smb failed."); } DEBUG(10,("schedule_aio_write_and_X: scheduled aio_write " "behind for file %s\n", fsp_str_dbg(fsp))); }