root/source3/smbd/fileio.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. read_from_write_cache
  2. read_file
  3. real_write_file
  4. wcp_file_size_change
  5. update_write_time_handler
  6. trigger_write_time_update
  7. trigger_write_time_update_immediate
  8. write_file
  9. delete_write_cache
  10. setup_write_cache
  11. set_filelen_write_cache
  12. flush_write_cache
  13. sync_file
  14. fsp_stat

   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 3 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, see <http://www.gnu.org/licenses/>.
  20 */
  21 
  22 #include "includes.h"
  23 #include "smbd/globals.h"
  24 
  25 static bool setup_write_cache(files_struct *, SMB_OFF_T);
  26 
  27 /****************************************************************************
  28  Read from write cache if we can.
  29 ****************************************************************************/
  30 
  31 static bool read_from_write_cache(files_struct *fsp,char *data,SMB_OFF_T pos,size_t n)
     /* [<][>][^][v][top][bottom][index][help] */
  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 
  54 ssize_t read_file(files_struct *fsp,char *data,SMB_OFF_T pos,size_t n)
     /* [<][>][^][v][top][bottom][index][help] */
  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;
  80 tryagain:
  81                 readret = SMB_VFS_PREAD(fsp,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,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 /****************************************************************************
 114  *Really* write to a file.
 115 ****************************************************************************/
 116 
 117 static ssize_t real_write_file(struct smb_request *req,
     /* [<][>][^][v][top][bottom][index][help] */
 118                                 files_struct *fsp,
 119                                 const char *data,
 120                                 SMB_OFF_T pos,
 121                                 size_t n)
 122 {
 123         ssize_t ret;
 124 
 125         if (pos == -1) {
 126                 ret = vfs_write_data(req, fsp, data, n);
 127         } else {
 128                 fsp->fh->pos = pos;
 129                 if (pos && lp_strict_allocate(SNUM(fsp->conn))) {
 130                         if (vfs_fill_sparse(fsp, pos) == -1) {
 131                                 return -1;
 132                         }
 133                 }
 134                 ret = vfs_pwrite_data(req, fsp, data, n, pos);
 135         }
 136 
 137         DEBUG(10,("real_write_file (%s): pos = %.0f, size = %lu, returned %ld\n",
 138                 fsp->fsp_name, (double)pos, (unsigned long)n, (long)ret ));
 139 
 140         if (ret != -1) {
 141                 fsp->fh->pos += ret;
 142 
 143 /* Yes - this is correct - writes don't update this. JRA. */
 144 /* Found by Samba4 tests. */
 145 #if 0
 146                 fsp->position_information = fsp->pos;
 147 #endif
 148         }
 149 
 150         return ret;
 151 }
 152 
 153 /****************************************************************************
 154  File size cache change.
 155  Updates size on disk but doesn't flush the cache.
 156 ****************************************************************************/
 157 
 158 static int wcp_file_size_change(files_struct *fsp)
     /* [<][>][^][v][top][bottom][index][help] */
 159 {
 160         int ret;
 161         write_cache *wcp = fsp->wcp;
 162 
 163         wcp->file_size = wcp->offset + wcp->data_size;
 164         ret = SMB_VFS_FTRUNCATE(fsp, wcp->file_size);
 165         if (ret == -1) {
 166                 DEBUG(0,("wcp_file_size_change (%s): ftruncate of size %.0f error %s\n",
 167                         fsp->fsp_name, (double)wcp->file_size, strerror(errno) ));
 168         }
 169         return ret;
 170 }
 171 
 172 static void update_write_time_handler(struct event_context *ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 173                                       struct timed_event *te,
 174                                       struct timeval now,
 175                                       void *private_data)
 176 {
 177         files_struct *fsp = (files_struct *)private_data;
 178 
 179         /* Remove the timed event handler. */
 180         TALLOC_FREE(fsp->update_write_time_event);
 181         DEBUG(5, ("Update write time on %s\n", fsp->fsp_name));
 182 
 183         /* change the write time if not already changed by someone else */
 184         update_write_time(fsp);
 185 }
 186 
 187 /*********************************************************
 188  Schedule a write time update for WRITE_TIME_UPDATE_USEC_DELAY
 189  in the future.
 190 *********************************************************/
 191 
 192 void trigger_write_time_update(struct files_struct *fsp)
     /* [<][>][^][v][top][bottom][index][help] */
 193 {
 194         int delay;
 195 
 196         if (fsp->write_time_forced) {
 197                 /* No point - "sticky" write times
 198                  * in effect.
 199                  */
 200                 return;
 201         }
 202 
 203         if (fsp->update_write_time_triggered) {
 204                 /*
 205                  * We only update the write time
 206                  * on the first write. After that
 207                  * no other writes affect this.
 208                  */
 209                 return;
 210         }
 211         fsp->update_write_time_triggered = true;
 212 
 213         delay = lp_parm_int(SNUM(fsp->conn),
 214                             "smbd", "writetimeupdatedelay",
 215                             WRITE_TIME_UPDATE_USEC_DELAY);
 216 
 217         /* trigger the update 2 seconds later */
 218         fsp->update_write_time_on_close = true;
 219         fsp->update_write_time_event =
 220                 event_add_timed(smbd_event_context(), NULL,
 221                                 timeval_current_ofs(0, delay),
 222                                 update_write_time_handler, fsp);
 223 }
 224 
 225 void trigger_write_time_update_immediate(struct files_struct *fsp)
     /* [<][>][^][v][top][bottom][index][help] */
 226 {
 227         if (fsp->write_time_forced) {
 228                 /*
 229                  * No point - "sticky" write times
 230                  * in effect.
 231                  */
 232                 return;
 233         }
 234 
 235         TALLOC_FREE(fsp->update_write_time_event);
 236         DEBUG(5, ("Update write time immediate on %s\n", fsp->fsp_name));
 237 
 238         fsp->update_write_time_triggered = true;
 239 
 240         fsp->update_write_time_on_close = false;
 241         update_write_time(fsp);
 242 }
 243 
 244 /****************************************************************************
 245  Write to a file.
 246 ****************************************************************************/
 247 
 248 ssize_t write_file(struct smb_request *req,
     /* [<][>][^][v][top][bottom][index][help] */
 249                         files_struct *fsp,
 250                         const char *data,
 251                         SMB_OFF_T pos,
 252                         size_t n)
 253 {
 254         write_cache *wcp = fsp->wcp;
 255         ssize_t total_written = 0;
 256         int write_path = -1;
 257 
 258         if (fsp->print_file) {
 259                 uint32 jobid;
 260 
 261                 if (!rap_to_pjobid(fsp->rap_print_jobid, NULL, &jobid)) {
 262                         DEBUG(3,("write_file: Unable to map RAP jobid %u to jobid.\n",
 263                                                 (unsigned int)fsp->rap_print_jobid ));
 264                         errno = EBADF;
 265                         return -1;
 266                 }
 267 
 268                 return print_job_write(SNUM(fsp->conn), jobid, data, pos, n);
 269         }
 270 
 271         if (!fsp->can_write) {
 272                 errno = EPERM;
 273                 return -1;
 274         }
 275 
 276         if (!fsp->modified) {
 277                 SMB_STRUCT_STAT st;
 278                 fsp->modified = True;
 279 
 280                 if (SMB_VFS_FSTAT(fsp, &st) == 0) {
 281                         int dosmode;
 282                         trigger_write_time_update(fsp);
 283                         dosmode = dos_mode(fsp->conn,fsp->fsp_name,&st);
 284                         if ((lp_store_dos_attributes(SNUM(fsp->conn)) ||
 285                                         MAP_ARCHIVE(fsp->conn)) &&
 286                                         !IS_DOS_ARCHIVE(dosmode)) {
 287                                 file_set_dosmode(fsp->conn,fsp->fsp_name,
 288                                                 dosmode | aARCH,&st,
 289                                                 NULL,
 290                                                 false);
 291                         }
 292 
 293                         /*
 294                          * If this is the first write and we have an exclusive oplock then setup
 295                          * the write cache.
 296                          */
 297 
 298                         if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) && !wcp) {
 299                                 setup_write_cache(fsp, st.st_size);
 300                                 wcp = fsp->wcp;
 301                         }
 302                 }
 303         }
 304 
 305 #ifdef WITH_PROFILE
 306         DO_PROFILE_INC(writecache_total_writes);
 307         if (!fsp->oplock_type) {
 308                 DO_PROFILE_INC(writecache_non_oplock_writes);
 309         }
 310 #endif
 311 
 312         /*
 313          * If this file is level II oplocked then we need
 314          * to grab the shared memory lock and inform all
 315          * other files with a level II lock that they need
 316          * to flush their read caches. We keep the lock over
 317          * the shared memory area whilst doing this.
 318          */
 319 
 320         /* This should actually be improved to span the write. */
 321         contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_WRITE);
 322         contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_WRITE);
 323 
 324 #ifdef WITH_PROFILE
 325         if (profile_p && profile_p->writecache_total_writes % 500 == 0) {
 326                 DEBUG(3,("WRITECACHE: initwrites=%u abutted=%u total=%u \
 327 nonop=%u allocated=%u active=%u direct=%u perfect=%u readhits=%u\n",
 328                         profile_p->writecache_init_writes,
 329                         profile_p->writecache_abutted_writes,
 330                         profile_p->writecache_total_writes,
 331                         profile_p->writecache_non_oplock_writes,
 332                         profile_p->writecache_allocated_write_caches,
 333                         profile_p->writecache_num_write_caches,
 334                         profile_p->writecache_direct_writes,
 335                         profile_p->writecache_num_perfect_writes,
 336                         profile_p->writecache_read_hits ));
 337 
 338                 DEBUG(3,("WRITECACHE: Flushes SEEK=%d, READ=%d, WRITE=%d, READRAW=%d, OPLOCK=%d, CLOSE=%d, SYNC=%d\n",
 339                         profile_p->writecache_flushed_writes[SEEK_FLUSH],
 340                         profile_p->writecache_flushed_writes[READ_FLUSH],
 341                         profile_p->writecache_flushed_writes[WRITE_FLUSH],
 342                         profile_p->writecache_flushed_writes[READRAW_FLUSH],
 343                         profile_p->writecache_flushed_writes[OPLOCK_RELEASE_FLUSH],
 344                         profile_p->writecache_flushed_writes[CLOSE_FLUSH],
 345                         profile_p->writecache_flushed_writes[SYNC_FLUSH] ));
 346         }
 347 #endif
 348 
 349         if (wcp && req->unread_bytes) {
 350                 /* If we're using receivefile don't
 351                  * deal with a write cache.
 352                  */
 353                 flush_write_cache(fsp, WRITE_FLUSH);
 354                 delete_write_cache(fsp);
 355                 wcp = NULL;
 356         }
 357 
 358         if(!wcp) {
 359                 DO_PROFILE_INC(writecache_direct_writes);
 360                 total_written = real_write_file(req, fsp, data, pos, n);
 361                 return total_written;
 362         }
 363 
 364         DEBUG(9,("write_file (%s)(fd=%d pos=%.0f size=%u) wcp->offset=%.0f wcp->data_size=%u\n",
 365                 fsp->fsp_name, fsp->fh->fd, (double)pos, (unsigned int)n, (double)wcp->offset, (unsigned int)wcp->data_size));
 366 
 367         fsp->fh->pos = pos + n;
 368 
 369         /*
 370          * If we have active cache and it isn't contiguous then we flush.
 371          * NOTE: There is a small problem with running out of disk ....
 372          */
 373 
 374         if (wcp->data_size) {
 375                 bool cache_flush_needed = False;
 376 
 377                 if ((pos >= wcp->offset) && (pos <= wcp->offset + wcp->data_size)) {
 378       
 379                         /* ASCII art.... JRA.
 380 
 381       +--------------+-----
 382       | Cached data  | Rest of allocated cache buffer....
 383       +--------------+-----
 384 
 385             +-------------------+
 386             | Data to write     |
 387             +-------------------+
 388 
 389                         */
 390 
 391                         /*
 392                          * Start of write overlaps or abutts the existing data.
 393                          */
 394 
 395                         size_t data_used = MIN((wcp->alloc_size - (pos - wcp->offset)), n);
 396 
 397                         memcpy(wcp->data + (pos - wcp->offset), data, data_used);
 398 
 399                         /*
 400                          * Update the current buffer size with the new data.
 401                          */
 402 
 403                         if(pos + data_used > wcp->offset + wcp->data_size) {
 404                                 wcp->data_size = pos + data_used - wcp->offset;
 405                         }
 406 
 407                         /*
 408                          * Update the file size if changed.
 409                          */
 410 
 411                         if (wcp->offset + wcp->data_size > wcp->file_size) {
 412                                 if (wcp_file_size_change(fsp) == -1) {
 413                                         return -1;
 414                                 }
 415                         }
 416 
 417                         /*
 418                          * If we used all the data then
 419                          * return here.
 420                          */
 421 
 422                         if(n == data_used) {
 423                                 return n;
 424                         } else {
 425                                 cache_flush_needed = True;
 426                         }
 427                         /*
 428                          * Move the start of data forward by the amount used,
 429                          * cut down the amount left by the same amount.
 430                          */
 431 
 432                         data += data_used;
 433                         pos += data_used;
 434                         n -= data_used;
 435 
 436                         DO_PROFILE_INC(writecache_abutted_writes);
 437                         total_written = data_used;
 438 
 439                         write_path = 1;
 440 
 441                 } else if ((pos < wcp->offset) && (pos + n > wcp->offset) && 
 442                                         (pos + n <= wcp->offset + wcp->alloc_size)) {
 443 
 444                         /* ASCII art.... JRA.
 445 
 446                         +---------------+
 447                         | Cache buffer  |
 448                         +---------------+
 449 
 450             +-------------------+
 451             | Data to write     |
 452             +-------------------+
 453 
 454                         */
 455 
 456                         /*
 457                          * End of write overlaps the existing data.
 458                          */
 459 
 460                         size_t data_used = pos + n - wcp->offset;
 461 
 462                         memcpy(wcp->data, data + n - data_used, data_used);
 463 
 464                         /*
 465                          * Update the current buffer size with the new data.
 466                          */
 467 
 468                         if(pos + n > wcp->offset + wcp->data_size) {
 469                                 wcp->data_size = pos + n - wcp->offset;
 470                         }
 471 
 472                         /*
 473                          * Update the file size if changed.
 474                          */
 475 
 476                         if (wcp->offset + wcp->data_size > wcp->file_size) {
 477                                 if (wcp_file_size_change(fsp) == -1) {
 478                                         return -1;
 479                                 }
 480                         }
 481 
 482                         /*
 483                          * We don't need to move the start of data, but we
 484                          * cut down the amount left by the amount used.
 485                          */
 486 
 487                         n -= data_used;
 488 
 489                         /*
 490                          * We cannot have used all the data here.
 491                          */
 492 
 493                         cache_flush_needed = True;
 494 
 495                         DO_PROFILE_INC(writecache_abutted_writes);
 496                         total_written = data_used;
 497 
 498                         write_path = 2;
 499 
 500                 } else if ( (pos >= wcp->file_size) && 
 501                                         (wcp->offset + wcp->data_size == wcp->file_size) &&
 502                                         (pos > wcp->offset + wcp->data_size) && 
 503                                         (pos < wcp->offset + wcp->alloc_size) ) {
 504 
 505                         /* ASCII art.... JRA.
 506 
 507                        End of file ---->|
 508 
 509                         +---------------+---------------+
 510                         | Cached data   | Cache buffer  |
 511                         +---------------+---------------+
 512 
 513                                               +-------------------+
 514                                               | Data to write     |
 515                                               +-------------------+
 516 
 517                         */
 518 
 519                         /*
 520                          * Non-contiguous write part of which fits within
 521                          * the cache buffer and is extending the file
 522                          * and the cache contents reflect the current
 523                          * data up to the current end of the file.
 524                          */
 525 
 526                         size_t data_used;
 527 
 528                         if(pos + n <= wcp->offset + wcp->alloc_size) {
 529                                 data_used = n;
 530                         } else {
 531                                 data_used = wcp->offset + wcp->alloc_size - pos;
 532                         }
 533 
 534                         /*
 535                          * Fill in the non-continuous area with zeros.
 536                          */
 537 
 538                         memset(wcp->data + wcp->data_size, '\0',
 539                                 pos - (wcp->offset + wcp->data_size) );
 540 
 541                         memcpy(wcp->data + (pos - wcp->offset), data, data_used);
 542 
 543                         /*
 544                          * Update the current buffer size with the new data.
 545                          */
 546 
 547                         if(pos + data_used > wcp->offset + wcp->data_size) {
 548                                 wcp->data_size = pos + data_used - wcp->offset;
 549                         }
 550 
 551                         /*
 552                          * Update the file size if changed.
 553                          */
 554 
 555                         if (wcp->offset + wcp->data_size > wcp->file_size) {
 556                                 if (wcp_file_size_change(fsp) == -1) {
 557                                         return -1;
 558                                 }
 559                         }
 560 
 561                         /*
 562                          * If we used all the data then
 563                          * return here.
 564                          */
 565 
 566                         if(n == data_used) {
 567                                 return n;
 568                         } else {
 569                                 cache_flush_needed = True;
 570                         }
 571 
 572                         /*
 573                          * Move the start of data forward by the amount used,
 574                          * cut down the amount left by the same amount.
 575                          */
 576 
 577                         data += data_used;
 578                         pos += data_used;
 579                         n -= data_used;
 580 
 581                         DO_PROFILE_INC(writecache_abutted_writes);
 582                         total_written = data_used;
 583 
 584                         write_path = 3;
 585 
 586                 } else if ( (pos >= wcp->file_size) &&
 587                             (n == 1) &&
 588                             (wcp->file_size == wcp->offset + wcp->data_size) &&
 589                             (pos < wcp->file_size + wcp->alloc_size)) {
 590 
 591                         /*
 592 
 593                 End of file ---->|
 594 
 595                  +---------------+---------------+
 596                  | Cached data   | Cache buffer  |
 597                  +---------------+---------------+
 598 
 599                                  |<------- allocated size ---------------->|
 600 
 601                                                          +--------+
 602                                                          | 1 Byte |
 603                                                          +--------+
 604 
 605                         MS-Office seems to do this a lot to determine if there's enough
 606                         space on the filesystem to write a new file.
 607 
 608                         Change to :
 609 
 610                 End of file ---->|
 611                                  +-----------------------+--------+
 612                                  | Zeroed Cached data    | 1 Byte |
 613                                  +-----------------------+--------+
 614                         */
 615 
 616                         flush_write_cache(fsp, WRITE_FLUSH);
 617                         wcp->offset = wcp->file_size;
 618                         wcp->data_size = pos - wcp->file_size + 1;
 619                         memset(wcp->data, '\0', wcp->data_size);
 620                         memcpy(wcp->data + wcp->data_size-1, data, 1);
 621 
 622                         /*
 623                          * Update the file size if changed.
 624                          */
 625 
 626                         if (wcp->offset + wcp->data_size > wcp->file_size) {
 627                                 if (wcp_file_size_change(fsp) == -1) {
 628                                         return -1;
 629                                 }
 630                         }
 631 
 632                         return n;
 633 
 634                 } else {
 635 
 636                         /* ASCII art..... JRA.
 637 
 638    Case 1).
 639 
 640                         +---------------+---------------+
 641                         | Cached data   | Cache buffer  |
 642                         +---------------+---------------+
 643 
 644                                                               +-------------------+
 645                                                               | Data to write     |
 646                                                               +-------------------+
 647 
 648    Case 2).
 649 
 650                            +---------------+---------------+
 651                            | Cached data   | Cache buffer  |
 652                            +---------------+---------------+
 653 
 654    +-------------------+
 655    | Data to write     |
 656    +-------------------+
 657 
 658     Case 3).
 659 
 660                            +---------------+---------------+
 661                            | Cached data   | Cache buffer  |
 662                            +---------------+---------------+
 663 
 664                   +-----------------------------------------------------+
 665                   | Data to write                                       |
 666                   +-----------------------------------------------------+
 667 
 668                   */
 669 
 670                         /*
 671                          * Write is bigger than buffer, or there is no overlap on the
 672                          * low or high ends.
 673                          */
 674 
 675                         DEBUG(9,("write_file: non cacheable write : fd = %d, pos = %.0f, len = %u, current cache pos = %.0f \
 676 len = %u\n",fsp->fh->fd, (double)pos, (unsigned int)n, (double)wcp->offset, (unsigned int)wcp->data_size ));
 677 
 678                         /*
 679                          * If write would fit in the cache, and is larger than
 680                          * the data already in the cache, flush the cache and
 681                          * preferentially copy the data new data into it. Otherwise
 682                          * just write the data directly.
 683                          */
 684 
 685                         if ( n <= wcp->alloc_size && n > wcp->data_size) {
 686                                 cache_flush_needed = True;
 687                         } else {
 688                                 ssize_t ret = real_write_file(NULL,fsp, data, pos, n);
 689 
 690                                 /*
 691                                  * If the write overlaps the entire cache, then
 692                                  * discard the current contents of the cache.
 693                                  * Fix from Rasmus Borup Hansen rbh@math.ku.dk.
 694                                  */
 695 
 696                                 if ((pos <= wcp->offset) &&
 697                                                 (pos + n >= wcp->offset + wcp->data_size) ) {
 698                                         DEBUG(9,("write_file: discarding overwritten write \
 699 cache: fd = %d, off=%.0f, size=%u\n", fsp->fh->fd, (double)wcp->offset, (unsigned int)wcp->data_size ));
 700                                         wcp->data_size = 0;
 701                                 }
 702 
 703                                 DO_PROFILE_INC(writecache_direct_writes);
 704                                 if (ret == -1) {
 705                                         return ret;
 706                                 }
 707 
 708                                 if (pos + ret > wcp->file_size) {
 709                                         wcp->file_size = pos + ret;
 710                                 }
 711 
 712                                 return ret;
 713                         }
 714 
 715                         write_path = 4;
 716 
 717                 }
 718 
 719                 if (cache_flush_needed) {
 720                         DEBUG(3,("WRITE_FLUSH:%d: due to noncontinuous write: fd = %d, size = %.0f, pos = %.0f, \
 721 n = %u, wcp->offset=%.0f, wcp->data_size=%u\n",
 722                                 write_path, fsp->fh->fd, (double)wcp->file_size, (double)pos, (unsigned int)n,
 723                                 (double)wcp->offset, (unsigned int)wcp->data_size ));
 724 
 725                         flush_write_cache(fsp, WRITE_FLUSH);
 726                 }
 727         }
 728 
 729         /*
 730          * If the write request is bigger than the cache
 731          * size, write it all out.
 732          */
 733 
 734         if (n > wcp->alloc_size ) {
 735                 ssize_t ret = real_write_file(NULL,fsp, data, pos, n);
 736                 if (ret == -1) {
 737                         return -1;
 738                 }
 739 
 740                 if (pos + ret > wcp->file_size) {
 741                         wcp->file_size = pos + n;
 742                 }
 743 
 744                 DO_PROFILE_INC(writecache_direct_writes);
 745                 return total_written + n;
 746         }
 747 
 748         /*
 749          * If there's any data left, cache it.
 750          */
 751 
 752         if (n) {
 753 #ifdef WITH_PROFILE
 754                 if (wcp->data_size) {
 755                         DO_PROFILE_INC(writecache_abutted_writes);
 756                 } else {
 757                         DO_PROFILE_INC(writecache_init_writes);
 758                 }
 759 #endif
 760                 memcpy(wcp->data+wcp->data_size, data, n);
 761                 if (wcp->data_size == 0) {
 762                         wcp->offset = pos;
 763                         DO_PROFILE_INC(writecache_num_write_caches);
 764                 }
 765                 wcp->data_size += n;
 766 
 767                 /*
 768                  * Update the file size if changed.
 769                  */
 770 
 771                 if (wcp->offset + wcp->data_size > wcp->file_size) {
 772                         if (wcp_file_size_change(fsp) == -1) {
 773                                 return -1;
 774                         }
 775                 }
 776                 DEBUG(9,("wcp->offset = %.0f wcp->data_size = %u cache return %u\n",
 777                         (double)wcp->offset, (unsigned int)wcp->data_size, (unsigned int)n));
 778 
 779                 total_written += n;
 780                 return total_written; /* .... that's a write :) */
 781         }
 782   
 783         return total_written;
 784 }
 785 
 786 /****************************************************************************
 787  Delete the write cache structure.
 788 ****************************************************************************/
 789 
 790 void delete_write_cache(files_struct *fsp)
     /* [<][>][^][v][top][bottom][index][help] */
 791 {
 792         write_cache *wcp;
 793 
 794         if(!fsp) {
 795                 return;
 796         }
 797 
 798         if(!(wcp = fsp->wcp)) {
 799                 return;
 800         }
 801 
 802         DO_PROFILE_DEC(writecache_allocated_write_caches);
 803         allocated_write_caches--;
 804 
 805         SMB_ASSERT(wcp->data_size == 0);
 806 
 807         SAFE_FREE(wcp->data);
 808         SAFE_FREE(fsp->wcp);
 809 
 810         DEBUG(10,("delete_write_cache: File %s deleted write cache\n", fsp->fsp_name ));
 811 }
 812 
 813 /****************************************************************************
 814  Setup the write cache structure.
 815 ****************************************************************************/
 816 
 817 static bool setup_write_cache(files_struct *fsp, SMB_OFF_T file_size)
     /* [<][>][^][v][top][bottom][index][help] */
 818 {
 819         ssize_t alloc_size = lp_write_cache_size(SNUM(fsp->conn));
 820         write_cache *wcp;
 821 
 822         if (allocated_write_caches >= MAX_WRITE_CACHES) {
 823                 return False;
 824         }
 825 
 826         if(alloc_size == 0 || fsp->wcp) {
 827                 return False;
 828         }
 829 
 830         if((wcp = SMB_MALLOC_P(write_cache)) == NULL) {
 831                 DEBUG(0,("setup_write_cache: malloc fail.\n"));
 832                 return False;
 833         }
 834 
 835         wcp->file_size = file_size;
 836         wcp->offset = 0;
 837         wcp->alloc_size = alloc_size;
 838         wcp->data_size = 0;
 839         if((wcp->data = (char *)SMB_MALLOC(wcp->alloc_size)) == NULL) {
 840                 DEBUG(0,("setup_write_cache: malloc fail for buffer size %u.\n",
 841                         (unsigned int)wcp->alloc_size ));
 842                 SAFE_FREE(wcp);
 843                 return False;
 844         }
 845 
 846         memset(wcp->data, '\0', wcp->alloc_size );
 847 
 848         fsp->wcp = wcp;
 849         DO_PROFILE_INC(writecache_allocated_write_caches);
 850         allocated_write_caches++;
 851 
 852         DEBUG(10,("setup_write_cache: File %s allocated write cache size %lu\n",
 853                 fsp->fsp_name, (unsigned long)wcp->alloc_size ));
 854 
 855         return True;
 856 }
 857 
 858 /****************************************************************************
 859  Cope with a size change.
 860 ****************************************************************************/
 861 
 862 void set_filelen_write_cache(files_struct *fsp, SMB_OFF_T file_size)
     /* [<][>][^][v][top][bottom][index][help] */
 863 {
 864         if(fsp->wcp) {
 865                 /* The cache *must* have been flushed before we do this. */
 866                 if (fsp->wcp->data_size != 0) {
 867                         char *msg;
 868                         if (asprintf(&msg, "set_filelen_write_cache: size change "
 869                                  "on file %s with write cache size = %lu\n",
 870                                  fsp->fsp_name,
 871                                  (unsigned long)fsp->wcp->data_size) != -1) {
 872                                 smb_panic(msg);
 873                         } else {
 874                                 smb_panic("set_filelen_write_cache");
 875                         }
 876                 }
 877                 fsp->wcp->file_size = file_size;
 878         }
 879 }
 880 
 881 /*******************************************************************
 882  Flush a write cache struct to disk.
 883 ********************************************************************/
 884 
 885 ssize_t flush_write_cache(files_struct *fsp, enum flush_reason_enum reason)
     /* [<][>][^][v][top][bottom][index][help] */
 886 {
 887         write_cache *wcp = fsp->wcp;
 888         size_t data_size;
 889         ssize_t ret;
 890 
 891         if(!wcp || !wcp->data_size) {
 892                 return 0;
 893         }
 894 
 895         data_size = wcp->data_size;
 896         wcp->data_size = 0;
 897 
 898         DO_PROFILE_DEC_INC(writecache_num_write_caches,writecache_flushed_writes[reason]);
 899 
 900         DEBUG(9,("flushing write cache: fd = %d, off=%.0f, size=%u\n",
 901                 fsp->fh->fd, (double)wcp->offset, (unsigned int)data_size));
 902 
 903 #ifdef WITH_PROFILE
 904         if(data_size == wcp->alloc_size) {
 905                 DO_PROFILE_INC(writecache_num_perfect_writes);
 906         }
 907 #endif
 908 
 909         ret = real_write_file(NULL, fsp, wcp->data, wcp->offset, data_size);
 910 
 911         /*
 912          * Ensure file size if kept up to date if write extends file.
 913          */
 914 
 915         if ((ret != -1) && (wcp->offset + ret > wcp->file_size)) {
 916                 wcp->file_size = wcp->offset + ret;
 917         }
 918 
 919         return ret;
 920 }
 921 
 922 /*******************************************************************
 923 sync a file
 924 ********************************************************************/
 925 
 926 NTSTATUS sync_file(connection_struct *conn, files_struct *fsp, bool write_through)
     /* [<][>][^][v][top][bottom][index][help] */
 927 {
 928         if (fsp->fh->fd == -1)
 929                 return NT_STATUS_INVALID_HANDLE;
 930 
 931         if (lp_strict_sync(SNUM(conn)) &&
 932             (lp_syncalways(SNUM(conn)) || write_through)) {
 933                 int ret = flush_write_cache(fsp, SYNC_FLUSH);
 934                 if (ret == -1) {
 935                         return map_nt_error_from_unix(errno);
 936                 }
 937                 ret = SMB_VFS_FSYNC(fsp);
 938                 if (ret == -1) {
 939                         return map_nt_error_from_unix(errno);
 940                 }
 941         }
 942         return NT_STATUS_OK;
 943 }
 944 
 945 /************************************************************
 946  Perform a stat whether a valid fd or not.
 947 ************************************************************/
 948 
 949 int fsp_stat(files_struct *fsp, SMB_STRUCT_STAT *pst)
     /* [<][>][^][v][top][bottom][index][help] */
 950 {
 951         if (fsp->fh->fd == -1) {
 952                 return SMB_VFS_STAT(fsp->conn, fsp->fsp_name, pst);
 953         } else {
 954                 return SMB_VFS_FSTAT(fsp, pst);
 955         }
 956 }

/* [<][>][^][v][top][bottom][index][help] */