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