1/* 2 Unix SMB/Netbios implementation. 3 Version 1.9. 4 read/write to a files_struct 5 Copyright (C) Andrew Tridgell 1992-1998 6 Copyright (C) Jeremy Allison 2000-2002. - write cache. 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 2 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program; if not, write to the Free Software 20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21*/ 22 23#include "includes.h" 24 25static BOOL setup_write_cache(files_struct *, SMB_OFF_T); 26 27/**************************************************************************** 28 Read from write cache if we can. 29****************************************************************************/ 30 31static BOOL read_from_write_cache(files_struct *fsp,char *data,SMB_OFF_T pos,size_t n) 32{ 33 write_cache *wcp = fsp->wcp; 34 35 if(!wcp) { 36 return False; 37 } 38 39 if( n > wcp->data_size || pos < wcp->offset || pos + n > wcp->offset + wcp->data_size) { 40 return False; 41 } 42 43 memcpy(data, wcp->data + (pos - wcp->offset), n); 44 45 DO_PROFILE_INC(writecache_read_hits); 46 47 return True; 48} 49 50/**************************************************************************** 51 Read from a file. 52****************************************************************************/ 53 54ssize_t read_file(files_struct *fsp,char *data,SMB_OFF_T pos,size_t n) 55{ 56 ssize_t ret=0,readret; 57 58 /* you can't read from print files */ 59 if (fsp->print_file) { 60 return -1; 61 } 62 63 /* 64 * Serve from write cache if we can. 65 */ 66 67 if(read_from_write_cache(fsp, data, pos, n)) { 68 fsp->fh->pos = pos + n; 69 fsp->fh->position_information = fsp->fh->pos; 70 return n; 71 } 72 73 flush_write_cache(fsp, READ_FLUSH); 74 75 fsp->fh->pos = pos; 76 77 if (n > 0) { 78#ifdef DMF_FIX 79 int numretries = 3; 80tryagain: 81 readret = SMB_VFS_PREAD(fsp,fsp->fh->fd,data,n,pos); 82 83 if (readret == -1) { 84 if ((errno == EAGAIN) && numretries) { 85 DEBUG(3,("read_file EAGAIN retry in 10 seconds\n")); 86 (void)sleep(10); 87 --numretries; 88 goto tryagain; 89 } 90 return -1; 91 } 92#else /* NO DMF fix. */ 93 readret = SMB_VFS_PREAD(fsp,fsp->fh->fd,data,n,pos); 94 95 if (readret == -1) { 96 return -1; 97 } 98#endif 99 if (readret > 0) { 100 ret += readret; 101 } 102 } 103 104 DEBUG(10,("read_file (%s): pos = %.0f, size = %lu, returned %lu\n", 105 fsp->fsp_name, (double)pos, (unsigned long)n, (long)ret )); 106 107 fsp->fh->pos += ret; 108 fsp->fh->position_information = fsp->fh->pos; 109 110 return(ret); 111} 112 113/* how many write cache buffers have been allocated */ 114static unsigned int allocated_write_caches; 115 116/**************************************************************************** 117 *Really* write to a file. 118****************************************************************************/ 119 120static ssize_t real_write_file(files_struct *fsp,const char *data, SMB_OFF_T pos, size_t n) 121{ 122 ssize_t ret; 123 124 if (pos == -1) { 125 ret = vfs_write_data(fsp, data, n); 126 } else { 127 fsp->fh->pos = pos; 128 if (pos && lp_strict_allocate(SNUM(fsp->conn))) { 129 if (vfs_fill_sparse(fsp, pos) == -1) { 130 return -1; 131 } 132 } 133 ret = vfs_pwrite_data(fsp, data, n, pos); 134 } 135 136 DEBUG(10,("real_write_file (%s): pos = %.0f, size = %lu, returned %ld\n", 137 fsp->fsp_name, (double)pos, (unsigned long)n, (long)ret )); 138 139 if (ret != -1) { 140 fsp->fh->pos += ret; 141 142 /* 143 * It turns out that setting the last write time from a Windows 144 * client stops any subsequent writes from updating the write time. 145 * Doing this after the write gives a race condition here where 146 * a stat may see the changed write time before we reset it here, 147 * but it's cheaper than having to store the write time in shared 148 * memory and look it up using dev/inode across all running smbd's. 149 * The 99% solution will hopefully be good enough in this case. JRA. 150 */ 151 152 if (!null_timespec(fsp->pending_modtime)) { 153 set_filetime(fsp->conn, fsp->fsp_name, fsp->pending_modtime); 154 155 /* If we didn't get the "set modtime" call ourselves, we must 156 store the last write time to restore on close. JRA. */ 157 if (!fsp->pending_modtime_owner) { 158 fsp->last_write_time = timespec_current(); 159 } 160 } 161 162/* Yes - this is correct - writes don't update this. JRA. */ 163/* Found by Samba4 tests. */ 164#if 0 165 fsp->position_information = fsp->pos; 166#endif 167 } 168 169 return ret; 170} 171 172/**************************************************************************** 173 File size cache change. 174 Updates size on disk but doesn't flush the cache. 175****************************************************************************/ 176 177static int wcp_file_size_change(files_struct *fsp) 178{ 179 int ret; 180 write_cache *wcp = fsp->wcp; 181 182 wcp->file_size = wcp->offset + wcp->data_size; 183 ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, wcp->file_size); 184 if (ret == -1) { 185 DEBUG(0,("wcp_file_size_change (%s): ftruncate of size %.0f error %s\n", 186 fsp->fsp_name, (double)wcp->file_size, strerror(errno) )); 187 } 188 return ret; 189} 190 191/**************************************************************************** 192 Write to a file. 193****************************************************************************/ 194 195ssize_t write_file(files_struct *fsp, const char *data, SMB_OFF_T pos, size_t n) 196{ 197 write_cache *wcp = fsp->wcp; 198 ssize_t total_written = 0; 199 int write_path = -1; 200 201 if (fsp->print_file) { 202 fstring sharename; 203 uint32 jobid; 204 205 if (!rap_to_pjobid(fsp->rap_print_jobid, sharename, &jobid)) { 206 DEBUG(3,("write_file: Unable to map RAP jobid %u to jobid.\n", 207 (unsigned int)fsp->rap_print_jobid )); 208 errno = EBADF; 209 return -1; 210 } 211 212 return print_job_write(SNUM(fsp->conn), jobid, data, pos, n); 213 } 214 215 if (!fsp->can_write) { 216 errno = EPERM; 217 return -1; 218 } 219 220 if (!fsp->modified) { 221 SMB_STRUCT_STAT st; 222 fsp->modified = True; 223 224 if (SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st) == 0) { 225 int dosmode = dos_mode(fsp->conn,fsp->fsp_name,&st); 226 if ((lp_store_dos_attributes(SNUM(fsp->conn)) || MAP_ARCHIVE(fsp->conn)) && !IS_DOS_ARCHIVE(dosmode)) { 227 file_set_dosmode(fsp->conn,fsp->fsp_name,dosmode | aARCH,&st, False); 228 } 229 230 /* 231 * If this is the first write and we have an exclusive oplock then setup 232 * the write cache. 233 */ 234 235 if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) && !wcp) { 236 setup_write_cache(fsp, st.st_size); 237 wcp = fsp->wcp; 238 } 239 } 240 } 241 242#ifdef WITH_PROFILE 243 DO_PROFILE_INC(writecache_total_writes); 244 if (!fsp->oplock_type) { 245 DO_PROFILE_INC(writecache_non_oplock_writes); 246 } 247#endif 248 249 /* 250 * If this file is level II oplocked then we need 251 * to grab the shared memory lock and inform all 252 * other files with a level II lock that they need 253 * to flush their read caches. We keep the lock over 254 * the shared memory area whilst doing this. 255 */ 256 257 release_level_2_oplocks_on_change(fsp); 258 259#ifdef WITH_PROFILE 260 if (profile_p && profile_p->writecache_total_writes % 500 == 0) { 261 DEBUG(3,("WRITECACHE: initwrites=%u abutted=%u total=%u \ 262nonop=%u allocated=%u active=%u direct=%u perfect=%u readhits=%u\n", 263 profile_p->writecache_init_writes, 264 profile_p->writecache_abutted_writes, 265 profile_p->writecache_total_writes, 266 profile_p->writecache_non_oplock_writes, 267 profile_p->writecache_allocated_write_caches, 268 profile_p->writecache_num_write_caches, 269 profile_p->writecache_direct_writes, 270 profile_p->writecache_num_perfect_writes, 271 profile_p->writecache_read_hits )); 272 273 DEBUG(3,("WRITECACHE: Flushes SEEK=%d, READ=%d, WRITE=%d, READRAW=%d, OPLOCK=%d, CLOSE=%d, SYNC=%d\n", 274 profile_p->writecache_flushed_writes[SEEK_FLUSH], 275 profile_p->writecache_flushed_writes[READ_FLUSH], 276 profile_p->writecache_flushed_writes[WRITE_FLUSH], 277 profile_p->writecache_flushed_writes[READRAW_FLUSH], 278 profile_p->writecache_flushed_writes[OPLOCK_RELEASE_FLUSH], 279 profile_p->writecache_flushed_writes[CLOSE_FLUSH], 280 profile_p->writecache_flushed_writes[SYNC_FLUSH] )); 281 } 282#endif 283 284 if(!wcp) { 285 DO_PROFILE_INC(writecache_direct_writes); 286 total_written = real_write_file(fsp, data, pos, n); 287 return total_written; 288 } 289 290 DEBUG(9,("write_file (%s)(fd=%d pos=%.0f size=%u) wcp->offset=%.0f wcp->data_size=%u\n", 291 fsp->fsp_name, fsp->fh->fd, (double)pos, (unsigned int)n, (double)wcp->offset, (unsigned int)wcp->data_size)); 292 293 fsp->fh->pos = pos + n; 294 295 /* 296 * If we have active cache and it isn't contiguous then we flush. 297 * NOTE: There is a small problem with running out of disk .... 298 */ 299 300 if (wcp->data_size) { 301 BOOL cache_flush_needed = False; 302 303 if ((pos >= wcp->offset) && (pos <= wcp->offset + wcp->data_size)) { 304 305 /* ASCII art.... JRA. 306 307 +--------------+----- 308 | Cached data | Rest of allocated cache buffer.... 309 +--------------+----- 310 311 +-------------------+ 312 | Data to write | 313 +-------------------+ 314 315 */ 316 317 /* 318 * Start of write overlaps or abutts the existing data. 319 */ 320 321 size_t data_used = MIN((wcp->alloc_size - (pos - wcp->offset)), n); 322 323 memcpy(wcp->data + (pos - wcp->offset), data, data_used); 324 325 /* 326 * Update the current buffer size with the new data. 327 */ 328 329 if(pos + data_used > wcp->offset + wcp->data_size) { 330 wcp->data_size = pos + data_used - wcp->offset; 331 } 332 333 /* 334 * Update the file size if changed. 335 */ 336 337 if (wcp->offset + wcp->data_size > wcp->file_size) { 338 if (wcp_file_size_change(fsp) == -1) { 339 return -1; 340 } 341 } 342 343 /* 344 * If we used all the data then 345 * return here. 346 */ 347 348 if(n == data_used) { 349 return n; 350 } else { 351 cache_flush_needed = True; 352 } 353 /* 354 * Move the start of data forward by the amount used, 355 * cut down the amount left by the same amount. 356 */ 357 358 data += data_used; 359 pos += data_used; 360 n -= data_used; 361 362 DO_PROFILE_INC(writecache_abutted_writes); 363 total_written = data_used; 364 365 write_path = 1; 366 367 } else if ((pos < wcp->offset) && (pos + n > wcp->offset) && 368 (pos + n <= wcp->offset + wcp->alloc_size)) { 369 370 /* ASCII art.... JRA. 371 372 +---------------+ 373 | Cache buffer | 374 +---------------+ 375 376 +-------------------+ 377 | Data to write | 378 +-------------------+ 379 380 */ 381 382 /* 383 * End of write overlaps the existing data. 384 */ 385 386 size_t data_used = pos + n - wcp->offset; 387 388 memcpy(wcp->data, data + n - data_used, data_used); 389 390 /* 391 * Update the current buffer size with the new data. 392 */ 393 394 if(pos + n > wcp->offset + wcp->data_size) { 395 wcp->data_size = pos + n - wcp->offset; 396 } 397 398 /* 399 * Update the file size if changed. 400 */ 401 402 if (wcp->offset + wcp->data_size > wcp->file_size) { 403 if (wcp_file_size_change(fsp) == -1) { 404 return -1; 405 } 406 } 407 408 /* 409 * We don't need to move the start of data, but we 410 * cut down the amount left by the amount used. 411 */ 412 413 n -= data_used; 414 415 /* 416 * We cannot have used all the data here. 417 */ 418 419 cache_flush_needed = True; 420 421 DO_PROFILE_INC(writecache_abutted_writes); 422 total_written = data_used; 423 424 write_path = 2; 425 426 } else if ( (pos >= wcp->file_size) && 427 (wcp->offset + wcp->data_size == wcp->file_size) && 428 (pos > wcp->offset + wcp->data_size) && 429 (pos < wcp->offset + wcp->alloc_size) ) { 430 431 /* ASCII art.... JRA. 432 433 End of file ---->| 434 435 +---------------+---------------+ 436 | Cached data | Cache buffer | 437 +---------------+---------------+ 438 439 +-------------------+ 440 | Data to write | 441 +-------------------+ 442 443 */ 444 445 /* 446 * Non-contiguous write part of which fits within 447 * the cache buffer and is extending the file 448 * and the cache contents reflect the current 449 * data up to the current end of the file. 450 */ 451 452 size_t data_used; 453 454 if(pos + n <= wcp->offset + wcp->alloc_size) { 455 data_used = n; 456 } else { 457 data_used = wcp->offset + wcp->alloc_size - pos; 458 } 459 460 /* 461 * Fill in the non-continuous area with zeros. 462 */ 463 464 memset(wcp->data + wcp->data_size, '\0', 465 pos - (wcp->offset + wcp->data_size) ); 466 467 memcpy(wcp->data + (pos - wcp->offset), data, data_used); 468 469 /* 470 * Update the current buffer size with the new data. 471 */ 472 473 if(pos + data_used > wcp->offset + wcp->data_size) { 474 wcp->data_size = pos + data_used - wcp->offset; 475 } 476 477 /* 478 * Update the file size if changed. 479 */ 480 481 if (wcp->offset + wcp->data_size > wcp->file_size) { 482 if (wcp_file_size_change(fsp) == -1) { 483 return -1; 484 } 485 } 486 487 /* 488 * If we used all the data then 489 * return here. 490 */ 491 492 if(n == data_used) { 493 return n; 494 } else { 495 cache_flush_needed = True; 496 } 497 498 /* 499 * Move the start of data forward by the amount used, 500 * cut down the amount left by the same amount. 501 */ 502 503 data += data_used; 504 pos += data_used; 505 n -= data_used; 506 507 DO_PROFILE_INC(writecache_abutted_writes); 508 total_written = data_used; 509 510 write_path = 3; 511 512 } else if ( (pos >= wcp->file_size) && 513 (n == 1) && 514 (pos < wcp->offset + 2*wcp->alloc_size) && 515 (wcp->file_size == wcp->offset + wcp->data_size)) { 516 517 /* 518 +---------------+ 519 | Cached data | 520 +---------------+ 521 522 +--------+ 523 | 1 Byte | 524 +--------+ 525 526 MS-Office seems to do this a lot to determine if there's enough 527 space on the filesystem to write a new file. 528 */ 529 530 SMB_BIG_UINT new_start = wcp->offset + wcp->data_size; 531 532 flush_write_cache(fsp, WRITE_FLUSH); 533 wcp->offset = new_start; 534 wcp->data_size = pos - new_start + 1; 535 memset(wcp->data, '\0', wcp->data_size); 536 memcpy(wcp->data + wcp->data_size-1, data, 1); 537 538 /* 539 * Update the file size if changed. 540 */ 541 542 if (wcp->offset + wcp->data_size > wcp->file_size) { 543 if (wcp_file_size_change(fsp) == -1) { 544 return -1; 545 } 546 } 547 548 return n; 549 550 } else { 551 552 /* ASCII art..... JRA. 553 554 Case 1). 555 556 +---------------+---------------+ 557 | Cached data | Cache buffer | 558 +---------------+---------------+ 559 560 +-------------------+ 561 | Data to write | 562 +-------------------+ 563 564 Case 2). 565 566 +---------------+---------------+ 567 | Cached data | Cache buffer | 568 +---------------+---------------+ 569 570 +-------------------+ 571 | Data to write | 572 +-------------------+ 573 574 Case 3). 575 576 +---------------+---------------+ 577 | Cached data | Cache buffer | 578 +---------------+---------------+ 579 580 +-----------------------------------------------------+ 581 | Data to write | 582 +-----------------------------------------------------+ 583 584 */ 585 586 /* 587 * Write is bigger than buffer, or there is no overlap on the 588 * low or high ends. 589 */ 590 591 DEBUG(9,("write_file: non cacheable write : fd = %d, pos = %.0f, len = %u, current cache pos = %.0f \ 592len = %u\n",fsp->fh->fd, (double)pos, (unsigned int)n, (double)wcp->offset, (unsigned int)wcp->data_size )); 593 594 /* 595 * If write would fit in the cache, and is larger than 596 * the data already in the cache, flush the cache and 597 * preferentially copy the data new data into it. Otherwise 598 * just write the data directly. 599 */ 600 601 if ( n <= wcp->alloc_size && n > wcp->data_size) { 602 cache_flush_needed = True; 603 } else { 604 ssize_t ret = real_write_file(fsp, data, pos, n); 605 606 /* 607 * If the write overlaps the entire cache, then 608 * discard the current contents of the cache. 609 * Fix from Rasmus Borup Hansen rbh@math.ku.dk. 610 */ 611 612 if ((pos <= wcp->offset) && 613 (pos + n >= wcp->offset + wcp->data_size) ) { 614 DEBUG(9,("write_file: discarding overwritten write \ 615cache: fd = %d, off=%.0f, size=%u\n", fsp->fh->fd, (double)wcp->offset, (unsigned int)wcp->data_size )); 616 wcp->data_size = 0; 617 } 618 619 DO_PROFILE_INC(writecache_direct_writes); 620 if (ret == -1) { 621 return ret; 622 } 623 624 if (pos + ret > wcp->file_size) { 625 wcp->file_size = pos + ret; 626 } 627 628 return ret; 629 } 630 631 write_path = 4; 632 633 } 634 635 if (cache_flush_needed) { 636 DEBUG(3,("WRITE_FLUSH:%d: due to noncontinuous write: fd = %d, size = %.0f, pos = %.0f, \ 637n = %u, wcp->offset=%.0f, wcp->data_size=%u\n", 638 write_path, fsp->fh->fd, (double)wcp->file_size, (double)pos, (unsigned int)n, 639 (double)wcp->offset, (unsigned int)wcp->data_size )); 640 641 flush_write_cache(fsp, WRITE_FLUSH); 642 } 643 } 644 645 /* 646 * If the write request is bigger than the cache 647 * size, write it all out. 648 */ 649 650 if (n > wcp->alloc_size ) { 651 ssize_t ret = real_write_file(fsp, data, pos, n); 652 if (ret == -1) { 653 return -1; 654 } 655 656 if (pos + ret > wcp->file_size) { 657 wcp->file_size = pos + n; 658 } 659 660 DO_PROFILE_INC(writecache_direct_writes); 661 return total_written + n; 662 } 663 664 /* 665 * If there's any data left, cache it. 666 */ 667 668 if (n) { 669#ifdef WITH_PROFILE 670 if (wcp->data_size) { 671 DO_PROFILE_INC(writecache_abutted_writes); 672 } else { 673 DO_PROFILE_INC(writecache_init_writes); 674 } 675#endif 676 memcpy(wcp->data+wcp->data_size, data, n); 677 if (wcp->data_size == 0) { 678 wcp->offset = pos; 679 DO_PROFILE_INC(writecache_num_write_caches); 680 } 681 wcp->data_size += n; 682 683 /* 684 * Update the file size if changed. 685 */ 686 687 if (wcp->offset + wcp->data_size > wcp->file_size) { 688 if (wcp_file_size_change(fsp) == -1) { 689 return -1; 690 } 691 } 692 DEBUG(9,("wcp->offset = %.0f wcp->data_size = %u cache return %u\n", 693 (double)wcp->offset, (unsigned int)wcp->data_size, (unsigned int)n)); 694 695 total_written += n; 696 return total_written; /* .... that's a write :) */ 697 } 698 699 return total_written; 700} 701 702/**************************************************************************** 703 Delete the write cache structure. 704****************************************************************************/ 705 706void delete_write_cache(files_struct *fsp) 707{ 708 write_cache *wcp; 709 710 if(!fsp) { 711 return; 712 } 713 714 if(!(wcp = fsp->wcp)) { 715 return; 716 } 717 718 DO_PROFILE_DEC(writecache_allocated_write_caches); 719 allocated_write_caches--; 720 721 SMB_ASSERT(wcp->data_size == 0); 722 723 SAFE_FREE(wcp->data); 724 SAFE_FREE(fsp->wcp); 725 726 DEBUG(10,("delete_write_cache: File %s deleted write cache\n", fsp->fsp_name )); 727} 728 729/**************************************************************************** 730 Setup the write cache structure. 731****************************************************************************/ 732 733static BOOL setup_write_cache(files_struct *fsp, SMB_OFF_T file_size) 734{ 735 ssize_t alloc_size = lp_write_cache_size(SNUM(fsp->conn)); 736 write_cache *wcp; 737 738 if (allocated_write_caches >= MAX_WRITE_CACHES) { 739 return False; 740 } 741 742 if(alloc_size == 0 || fsp->wcp) { 743 return False; 744 } 745 746 if((wcp = SMB_MALLOC_P(write_cache)) == NULL) { 747 DEBUG(0,("setup_write_cache: malloc fail.\n")); 748 return False; 749 } 750 751 wcp->file_size = file_size; 752 wcp->offset = 0; 753 wcp->alloc_size = alloc_size; 754 wcp->data_size = 0; 755 if((wcp->data = (char *)SMB_MALLOC(wcp->alloc_size)) == NULL) { 756 DEBUG(0,("setup_write_cache: malloc fail for buffer size %u.\n", 757 (unsigned int)wcp->alloc_size )); 758 SAFE_FREE(wcp); 759 return False; 760 } 761 762 memset(wcp->data, '\0', wcp->alloc_size ); 763 764 fsp->wcp = wcp; 765 DO_PROFILE_INC(writecache_allocated_write_caches); 766 allocated_write_caches++; 767 768 DEBUG(10,("setup_write_cache: File %s allocated write cache size %lu\n", 769 fsp->fsp_name, (unsigned long)wcp->alloc_size )); 770 771 return True; 772} 773 774/**************************************************************************** 775 Cope with a size change. 776****************************************************************************/ 777 778void set_filelen_write_cache(files_struct *fsp, SMB_OFF_T file_size) 779{ 780 if(fsp->wcp) { 781 /* The cache *must* have been flushed before we do this. */ 782 if (fsp->wcp->data_size != 0) { 783 pstring msg; 784 slprintf(msg, sizeof(msg)-1, "set_filelen_write_cache: size change \ 785on file %s with write cache size = %lu\n", fsp->fsp_name, (unsigned long)fsp->wcp->data_size ); 786 smb_panic(msg); 787 } 788 fsp->wcp->file_size = file_size; 789 } 790} 791 792/******************************************************************* 793 Flush a write cache struct to disk. 794********************************************************************/ 795 796ssize_t flush_write_cache(files_struct *fsp, enum flush_reason_enum reason) 797{ 798 write_cache *wcp = fsp->wcp; 799 size_t data_size; 800 ssize_t ret; 801 802 if(!wcp || !wcp->data_size) { 803 return 0; 804 } 805 806 data_size = wcp->data_size; 807 wcp->data_size = 0; 808 809 DO_PROFILE_DEC_INC(writecache_num_write_caches,writecache_flushed_writes[reason]); 810 811 DEBUG(9,("flushing write cache: fd = %d, off=%.0f, size=%u\n", 812 fsp->fh->fd, (double)wcp->offset, (unsigned int)data_size)); 813 814#ifdef WITH_PROFILE 815 if(data_size == wcp->alloc_size) { 816 DO_PROFILE_INC(writecache_num_perfect_writes); 817 } 818#endif 819 820 ret = real_write_file(fsp, wcp->data, wcp->offset, data_size); 821 822 /* 823 * Ensure file size if kept up to date if write extends file. 824 */ 825 826 if ((ret != -1) && (wcp->offset + ret > wcp->file_size)) { 827 wcp->file_size = wcp->offset + ret; 828 } 829 830 return ret; 831} 832 833/******************************************************************* 834sync a file 835********************************************************************/ 836 837NTSTATUS sync_file(connection_struct *conn, files_struct *fsp, BOOL write_through) 838{ 839 if (fsp->fh->fd == -1) 840 return NT_STATUS_INVALID_HANDLE; 841 842 if (lp_strict_sync(SNUM(conn)) && 843 (lp_syncalways(SNUM(conn)) || write_through)) { 844 int ret = flush_write_cache(fsp, SYNC_FLUSH); 845 if (ret == -1) { 846 return map_nt_error_from_unix(errno); 847 } 848 ret = SMB_VFS_FSYNC(fsp,fsp->fh->fd); 849 if (ret == -1) { 850 return map_nt_error_from_unix(errno); 851 } 852 } 853 return NT_STATUS_OK; 854} 855 856/************************************************************ 857 Perform a stat whether a valid fd or not. 858************************************************************/ 859 860int fsp_stat(files_struct *fsp, SMB_STRUCT_STAT *pst) 861{ 862 if (fsp->fh->fd == -1) { 863 return SMB_VFS_STAT(fsp->conn, fsp->fsp_name, pst); 864 } else { 865 return SMB_VFS_FSTAT(fsp,fsp->fh->fd, pst); 866 } 867} 868