Changeset 745 for trunk/server/source3/smbd/smb2_read.c
- Timestamp:
- Nov 27, 2012, 4:43:17 PM (13 years ago)
- Location:
- trunk/server
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/server
- Property svn:mergeinfo changed
/vendor/current merged: 581,587,591,594,597,600,615,618,740
- Property svn:mergeinfo changed
-
trunk/server/source3/smbd/smb2_read.c
r414 r745 20 20 21 21 #include "includes.h" 22 #include "system/filesys.h" 23 #include "smbd/smbd.h" 22 24 #include "smbd/globals.h" 23 25 #include "../libcli/smb/smb_common.h" 26 #include "libcli/security/security.h" 27 #include "../lib/util/tevent_ntstatus.h" 28 #include "rpc_server/srv_pipe_hnd.h" 24 29 25 30 static struct tevent_req *smbd_smb2_read_send(TALLOC_CTX *mem_ctx, … … 76 81 77 82 /* check the max read size */ 78 if (in_length > 0x00010000) {83 if (in_length > lp_smb2_max_read()) { 79 84 DEBUG(0,("here:%s: 0x%08X: 0x%08X\n", 80 __location__, in_length, 0x00010000));85 __location__, in_length, lp_smb2_max_read())); 81 86 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); 82 87 } … … 84 89 if (req->compat_chain_fsp) { 85 90 /* skip check */ 86 } else if (in_file_id_persistent != 0) {91 } else if (in_file_id_persistent != in_file_id_volatile) { 87 92 return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED); 88 93 } … … 171 176 struct smbd_smb2_read_state { 172 177 struct smbd_smb2_request *smb2req; 178 files_struct *fsp; 179 uint64_t in_file_id_volatile; 180 uint32_t in_length; 181 uint64_t in_offset; 182 uint32_t in_minimum; 173 183 DATA_BLOB out_data; 174 184 uint32_t out_remaining; 175 185 }; 176 186 187 /* struct smbd_smb2_read_state destructor. Send the SMB2_READ data. */ 188 static int smb2_sendfile_send_data(struct smbd_smb2_read_state *state) 189 { 190 struct lock_struct lock; 191 uint32_t in_length = state->in_length; 192 uint64_t in_offset = state->in_offset; 193 files_struct *fsp = state->fsp; 194 ssize_t nread; 195 196 nread = SMB_VFS_SENDFILE(fsp->conn->sconn->sock, 197 fsp, 198 NULL, 199 in_offset, 200 in_length); 201 DEBUG(10,("smb2_sendfile_send_data: SMB_VFS_SENDFILE returned %d on file %s\n", 202 (int)nread, 203 fsp_str_dbg(fsp) )); 204 205 if (nread == -1) { 206 if (errno == ENOSYS || errno == EINTR) { 207 /* 208 * Special hack for broken systems with no working 209 * sendfile. Fake this up by doing read/write calls. 210 */ 211 set_use_sendfile(SNUM(fsp->conn), false); 212 nread = fake_sendfile(fsp, in_offset, in_length); 213 if (nread == -1) { 214 DEBUG(0,("smb2_sendfile_send_data: " 215 "fake_sendfile failed for " 216 "file %s (%s).\n", 217 fsp_str_dbg(fsp), 218 strerror(errno))); 219 exit_server_cleanly("smb2_sendfile_send_data: " 220 "fake_sendfile failed"); 221 } 222 goto out; 223 } 224 225 DEBUG(0,("smb2_sendfile_send_data: sendfile failed for file " 226 "%s (%s). Terminating\n", 227 fsp_str_dbg(fsp), 228 strerror(errno))); 229 exit_server_cleanly("smb2_sendfile_send_data: sendfile failed"); 230 } else if (nread == 0) { 231 /* 232 * Some sendfile implementations return 0 to indicate 233 * that there was a short read, but nothing was 234 * actually written to the socket. In this case, 235 * fallback to the normal read path so the header gets 236 * the correct byte count. 237 */ 238 DEBUG(3, ("send_file_readX: sendfile sent zero bytes " 239 "falling back to the normal read: %s\n", 240 fsp_str_dbg(fsp))); 241 242 nread = fake_sendfile(fsp, in_offset, in_length); 243 if (nread == -1) { 244 DEBUG(0,("smb2_sendfile_send_data: " 245 "fake_sendfile failed for file " 246 "%s (%s). Terminating\n", 247 fsp_str_dbg(fsp), 248 strerror(errno))); 249 exit_server_cleanly("smb2_sendfile_send_data: " 250 "fake_sendfile failed"); 251 } 252 } 253 254 out: 255 256 if (nread < in_length) { 257 sendfile_short_send(fsp, nread, 0, in_length); 258 } 259 260 init_strict_lock_struct(fsp, 261 state->in_file_id_volatile, 262 in_offset, 263 in_length, 264 READ_LOCK, 265 &lock); 266 267 SMB_VFS_STRICT_UNLOCK(fsp->conn, fsp, &lock); 268 return 0; 269 } 270 271 static NTSTATUS schedule_smb2_sendfile_read(struct smbd_smb2_request *smb2req, 272 struct smbd_smb2_read_state *state) 273 { 274 struct smbd_smb2_read_state *state_copy = NULL; 275 files_struct *fsp = state->fsp; 276 277 /* 278 * We cannot use sendfile if... 279 * We were not configured to do so OR 280 * Signing is active OR 281 * This is a compound SMB2 operation OR 282 * fsp is a STREAM file OR 283 * We're using a write cache OR 284 * It's not a regular file OR 285 * Requested offset is greater than file size OR 286 * there's not enough data in the file. 287 * Phew :-). Luckily this means most 288 * reads on most normal files. JRA. 289 */ 290 291 if (!_lp_use_sendfile(SNUM(fsp->conn)) || 292 smb2req->do_signing || 293 smb2req->in.vector_count != 4 || 294 (fsp->base_fsp != NULL) || 295 (fsp->wcp != NULL) || 296 (!S_ISREG(fsp->fsp_name->st.st_ex_mode)) || 297 (state->in_offset >= fsp->fsp_name->st.st_ex_size) || 298 (fsp->fsp_name->st.st_ex_size < state->in_offset + 299 state->in_length)) { 300 return NT_STATUS_RETRY; 301 } 302 303 /* We've already checked there's this amount of data 304 to read. */ 305 state->out_data.length = state->in_length; 306 state->out_remaining = 0; 307 308 /* Make a copy of state attached to the smb2req. Attach 309 the destructor here as this will trigger the sendfile 310 call when the request is destroyed. */ 311 state_copy = TALLOC_P(smb2req, struct smbd_smb2_read_state); 312 if (!state_copy) { 313 return NT_STATUS_NO_MEMORY; 314 } 315 *state_copy = *state; 316 talloc_set_destructor(state_copy, smb2_sendfile_send_data); 317 return NT_STATUS_OK; 318 } 319 177 320 static void smbd_smb2_read_pipe_done(struct tevent_req *subreq); 321 322 /******************************************************************* 323 Common read complete processing function for both synchronous and 324 asynchronous reads. 325 *******************************************************************/ 326 327 NTSTATUS smb2_read_complete(struct tevent_req *req, ssize_t nread, int err) 328 { 329 struct smbd_smb2_read_state *state = tevent_req_data(req, 330 struct smbd_smb2_read_state); 331 files_struct *fsp = state->fsp; 332 333 if (nread < 0) { 334 NTSTATUS status = map_nt_error_from_unix(err); 335 336 DEBUG( 3,( "smb2_read_complete: file %s nread = %d. " 337 "Error = %s (NTSTATUS %s)\n", 338 fsp_str_dbg(fsp), 339 (int)nread, 340 strerror(err), 341 nt_errstr(status))); 342 343 return status; 344 } 345 if (nread == 0 && state->in_length != 0) { 346 DEBUG(5,("smb2_read_complete: read_file[%s] end of file\n", 347 fsp_str_dbg(fsp))); 348 return NT_STATUS_END_OF_FILE; 349 } 350 351 if (nread < state->in_minimum) { 352 DEBUG(5,("smb2_read_complete: read_file[%s] read less %d than " 353 "minimum requested %u. Returning end of file\n", 354 fsp_str_dbg(fsp), 355 (int)nread, 356 (unsigned int)state->in_minimum)); 357 return NT_STATUS_END_OF_FILE; 358 } 359 360 DEBUG(3,("smbd_smb2_read: fnum=[%d/%s] length=%lu offset=%lu read=%lu\n", 361 fsp->fnum, 362 fsp_str_dbg(fsp), 363 (unsigned long)state->in_length, 364 (unsigned long)state->in_offset, 365 (unsigned long)nread)); 366 367 state->out_data.length = nread; 368 state->out_remaining = 0; 369 370 return NT_STATUS_OK; 371 } 178 372 179 373 static struct tevent_req *smbd_smb2_read_send(TALLOC_CTX *mem_ctx, … … 187 381 uint32_t in_remaining) 188 382 { 189 struct tevent_req *req; 190 struct smbd_smb2_read_state *state; 191 struct smb_request *smbreq; 383 NTSTATUS status; 384 struct tevent_req *req = NULL; 385 struct smbd_smb2_read_state *state = NULL; 386 struct smb_request *smbreq = NULL; 192 387 connection_struct *conn = smb2req->tcon->compat_conn; 193 files_struct *fsp ;388 files_struct *fsp = NULL; 194 389 ssize_t nread = -1; 195 390 struct lock_struct lock; 391 int saved_errno; 196 392 197 393 req = tevent_req_create(mem_ctx, &state, … … 201 397 } 202 398 state->smb2req = smb2req; 399 state->in_length = in_length; 400 state->in_offset = in_offset; 401 state->in_minimum = in_minimum; 203 402 state->out_data = data_blob_null; 204 403 state->out_remaining = 0; … … 225 424 return tevent_req_post(req, ev); 226 425 } 227 228 state->out_data = data_blob_talloc(state, NULL, in_length); 229 if (in_length > 0 && tevent_req_nomem(state->out_data.data, req)) { 230 return tevent_req_post(req, ev); 231 } 426 if (fsp->is_directory) { 427 tevent_req_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST); 428 return tevent_req_post(req, ev); 429 } 430 431 state->fsp = fsp; 432 state->in_file_id_volatile = in_file_id_volatile; 232 433 233 434 if (IS_IPC(smbreq->conn)) { 234 struct tevent_req *subreq; 435 struct tevent_req *subreq = NULL; 436 437 state->out_data = data_blob_talloc(state, NULL, in_length); 438 if (in_length > 0 && tevent_req_nomem(state->out_data.data, req)) { 439 return tevent_req_post(req, ev); 440 } 235 441 236 442 if (!fsp_is_np(fsp)) { … … 257 463 } 258 464 465 status = schedule_smb2_aio_read(fsp->conn, 466 smbreq, 467 fsp, 468 state, 469 &state->out_data, 470 (SMB_OFF_T)in_offset, 471 (size_t)in_length); 472 473 if (NT_STATUS_IS_OK(status)) { 474 /* 475 * Doing an async read. Don't 476 * send a "gone async" message 477 * as we expect this to be less 478 * than the client timeout period. 479 * JRA. FIXME for offline files.. 480 * FIXME. Add cancel code.. 481 */ 482 smb2req->async = true; 483 return req; 484 } 485 486 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) { 487 /* Real error in setting up aio. Fail. */ 488 tevent_req_nterror(req, NT_STATUS_FILE_CLOSED); 489 return tevent_req_post(req, ev); 490 } 491 492 /* Fallback to synchronous. */ 493 259 494 init_strict_lock_struct(fsp, 260 in_ smbpid,495 in_file_id_volatile, 261 496 in_offset, 262 497 in_length, … … 269 504 } 270 505 506 /* Try sendfile in preference. */ 507 status = schedule_smb2_sendfile_read(smb2req, state); 508 if (NT_STATUS_IS_OK(status)) { 509 tevent_req_done(req); 510 return tevent_req_post(req, ev); 511 } else { 512 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) { 513 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock); 514 tevent_req_nterror(req, status); 515 return tevent_req_post(req, ev); 516 } 517 } 518 519 /* Ok, read into memory. Allocate the out buffer. */ 520 state->out_data = data_blob_talloc(state, NULL, in_length); 521 if (in_length > 0 && tevent_req_nomem(state->out_data.data, req)) { 522 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock); 523 return tevent_req_post(req, ev); 524 } 525 271 526 nread = read_file(fsp, 272 527 (char *)state->out_data.data, … … 274 529 in_length); 275 530 531 saved_errno = errno; 532 276 533 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock); 277 534 278 if (nread < 0) { 279 DEBUG(5,("smbd_smb2_read: read_file[%s] nread[%lld]\n", 280 fsp_str_dbg(fsp), (long long)nread)); 281 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED); 282 return tevent_req_post(req, ev); 283 } 284 if (nread == 0 && in_length != 0) { 285 DEBUG(5,("smbd_smb2_read: read_file[%s] end of file\n", 286 fsp_str_dbg(fsp))); 287 tevent_req_nterror(req, NT_STATUS_END_OF_FILE); 288 return tevent_req_post(req, ev); 289 } 290 291 state->out_data.length = nread; 292 state->out_remaining = 0; 293 tevent_req_done(req); 535 DEBUG(10,("smbd_smb2_read: file %s handle [0x%016llX] offset=%llu " 536 "len=%llu returned %lld\n", 537 fsp_str_dbg(fsp), 538 (unsigned long long)in_file_id_volatile, 539 (unsigned long long)in_offset, 540 (unsigned long long)in_length, 541 (long long)nread)); 542 543 status = smb2_read_complete(req, nread, saved_errno); 544 if (!NT_STATUS_IS_OK(status)) { 545 tevent_req_nterror(req, status); 546 } else { 547 /* Success. */ 548 tevent_req_done(req); 549 } 294 550 return tevent_req_post(req, ev); 295 551 } … … 320 576 state->out_remaining = 0; 321 577 578 /* 579 * TODO: add STATUS_BUFFER_OVERFLOW handling, once we also 580 * handle it in SMB1 pipe_read_andx_done(). 581 */ 582 322 583 tevent_req_done(req); 323 584 }
Note:
See TracChangeset
for help on using the changeset viewer.