This commit was manufactured by cvs2svn to create branch 'SAMBA_3_0'.
[tprouty/samba.git] / source / smbd / fileio.c
1 /* 
2    Unix SMB/CIFS implementation.
3    read/write to a files_struct
4    Copyright (C) Andrew Tridgell 1992-1998
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22
23 static BOOL setup_write_cache(files_struct *, SMB_OFF_T);
24
25 /****************************************************************************
26 seek a file. Try to avoid the seek if possible
27 ****************************************************************************/
28
29 SMB_OFF_T seek_file(files_struct *fsp,SMB_OFF_T pos)
30 {
31   SMB_OFF_T offset = 0;
32   SMB_OFF_T seek_ret;
33
34   if (fsp->print_file && lp_postscript(fsp->conn->service))
35     offset = 3;
36
37   seek_ret = fsp->conn->vfs_ops.lseek(fsp,fsp->fd,pos+offset,SEEK_SET);
38
39   if(seek_ret == -1) {
40     DEBUG(0,("seek_file: sys_lseek failed. Error was %s\n", strerror(errno) ));
41     fsp->pos = -1;
42     return -1;
43   }
44
45   fsp->pos = seek_ret - offset;
46
47   DEBUG(10,("seek_file: requested pos = %.0f, new pos = %.0f\n",
48         (double)(pos+offset), (double)fsp->pos ));
49
50   return(fsp->pos);
51 }
52
53 /****************************************************************************
54  Read from write cache if we can.
55 ****************************************************************************/
56
57
58 BOOL read_from_write_cache(files_struct *fsp,char *data,SMB_OFF_T pos,size_t n)
59 {
60   write_cache *wcp = fsp->wcp;
61
62   if(!wcp)
63     return False;
64
65   if(n > wcp->data_size || pos < wcp->offset || pos + n > wcp->offset + wcp->data_size)
66     return False;
67
68   memcpy(data, wcp->data + (pos - wcp->offset), n);
69
70   DO_PROFILE_INC(writecache_read_hits);
71
72   return True;
73 }
74
75 /****************************************************************************
76 read from a file
77 ****************************************************************************/
78
79 ssize_t read_file(files_struct *fsp,char *data,SMB_OFF_T pos,size_t n)
80 {
81         ssize_t ret=0,readret;
82
83         /* you can't read from print files */
84         if (fsp->print_file)
85                 return -1;
86
87         /*
88          * Serve from write cache if we can.
89          */
90
91         if(read_from_write_cache(fsp, data, pos, n))
92                 return n;
93
94         flush_write_cache(fsp, READ_FLUSH);
95
96         if (seek_file(fsp,pos) == -1) {
97                 DEBUG(3,("read_file: Failed to seek to %.0f\n",(double)pos));
98                 return(ret);
99         }
100   
101         if (n > 0) {
102 #ifdef DMF_FIX
103                 int numretries = 3;
104 tryagain:
105                 readret = fsp->conn->vfs_ops.read(fsp,fsp->fd,data,n);
106                 if (readret == -1) {
107                         if ((errno == EAGAIN) && numretries) {
108                                 DEBUG(3,("read_file EAGAIN retry in 10 seconds\n"));
109                                 (void)sleep(10);
110                                 --numretries;
111                                 goto tryagain;
112                         }
113                         return -1;
114                 }
115 #else /* NO DMF fix. */
116                 readret = fsp->conn->vfs_ops.read(fsp,fsp->fd,data,n);
117                 if (readret == -1)
118                         return -1;
119 #endif
120                 if (readret > 0)
121                         ret += readret;
122         }
123
124         return(ret);
125 }
126
127 /* how many write cache buffers have been allocated */
128 static unsigned int allocated_write_caches;
129
130 /****************************************************************************
131  *Really* write to a file.
132 ****************************************************************************/
133
134 static ssize_t real_write_file(files_struct *fsp,char *data,SMB_OFF_T pos, size_t n)
135 {
136   if ((pos != -1) && (seek_file(fsp,pos) == -1))
137     return -1;
138
139   return vfs_write_data(fsp,data,n);
140 }
141
142 /****************************************************************************
143 write to a file
144 ****************************************************************************/
145
146 ssize_t write_file(files_struct *fsp, char *data, SMB_OFF_T pos, size_t n)
147 {
148   write_cache *wcp = fsp->wcp;
149   ssize_t total_written = 0;
150   int write_path = -1; 
151
152   if (fsp->print_file) {
153           return print_job_write(fsp->print_jobid, data, n);
154   }
155
156   if (!fsp->can_write) {
157     errno = EPERM;
158     return(0);
159   }
160
161   if (!fsp->modified) {
162     SMB_STRUCT_STAT st;
163     fsp->modified = True;
164
165     if (fsp->conn->vfs_ops.fstat(fsp,fsp->fd,&st) == 0) {
166       int dosmode = dos_mode(fsp->conn,fsp->fsp_name,&st);
167       fsp->size = st.st_size;
168       if (MAP_ARCHIVE(fsp->conn) && !IS_DOS_ARCHIVE(dosmode)) { 
169         file_chmod(fsp->conn,fsp->fsp_name,dosmode | aARCH,&st);
170       }
171
172       /*
173        * If this is the first write and we have an exclusive oplock then setup
174        * the write cache.
175        */
176
177       if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) && !wcp) {
178         setup_write_cache(fsp, st.st_size);
179         wcp = fsp->wcp;
180       } 
181     }  
182   }
183
184 #ifdef WITH_PROFILE
185   DO_PROFILE_INC(writecache_total_writes);
186   if (!fsp->oplock_type) {
187     DO_PROFILE_INC(writecache_non_oplock_writes);
188   }
189 #endif
190
191   /*
192    * If this file is level II oplocked then we need
193    * to grab the shared memory lock and inform all
194    * other files with a level II lock that they need
195    * to flush their read caches. We keep the lock over
196    * the shared memory area whilst doing this.
197    */
198
199   release_level_2_oplocks_on_change(fsp);
200
201 #ifdef WITH_PROFILE
202   if (profile_p && profile_p->writecache_total_writes % 500 == 0) {
203     DEBUG(3,("WRITECACHE: initwrites=%u abutted=%u total=%u \
204 nonop=%u allocated=%u active=%u direct=%u perfect=%u readhits=%u\n",
205         profile_p->writecache_init_writes,
206         profile_p->writecache_abutted_writes,
207         profile_p->writecache_total_writes,
208         profile_p->writecache_non_oplock_writes,
209         profile_p->writecache_allocated_write_caches,
210         profile_p->writecache_num_write_caches,
211         profile_p->writecache_direct_writes,
212         profile_p->writecache_num_perfect_writes,
213         profile_p->writecache_read_hits ));
214
215     DEBUG(3,("WRITECACHE: Flushes SEEK=%d, READ=%d, WRITE=%d, READRAW=%d, OPLOCK=%d, CLOSE=%d, SYNC=%d\n",
216         profile_p->writecache_flushed_writes[SEEK_FLUSH],
217         profile_p->writecache_flushed_writes[READ_FLUSH],
218         profile_p->writecache_flushed_writes[WRITE_FLUSH],
219         profile_p->writecache_flushed_writes[READRAW_FLUSH],
220         profile_p->writecache_flushed_writes[OPLOCK_RELEASE_FLUSH],
221         profile_p->writecache_flushed_writes[CLOSE_FLUSH],
222         profile_p->writecache_flushed_writes[SYNC_FLUSH] ));
223   }
224 #endif
225
226   if(!wcp) {
227     DO_PROFILE_INC(writecache_direct_writes);
228     total_written = real_write_file(fsp, data, pos, n);
229     if ((total_written != -1) && (pos + total_written > fsp->size))
230       fsp->size = pos + total_written;
231     return total_written;
232   }
233
234   DEBUG(9,("write_file(fd=%d pos=%.0f size=%u) wcp->offset=%.0f wcp->data_size=%u\n",
235            fsp->fd, (double)pos, (unsigned int)n, (double)wcp->offset, (unsigned int)wcp->data_size));
236
237   /* 
238    * If we have active cache and it isn't contiguous then we flush.
239    * NOTE: There is a small problem with running out of disk ....
240    */
241
242   if (wcp->data_size) {
243
244     BOOL cache_flush_needed = False;
245
246     if ((pos >= wcp->offset) && (pos <= wcp->offset + wcp->data_size)) {
247       
248       /*
249        * Start of write overlaps or abutts the existing data.
250        */
251
252       size_t data_used = MIN((wcp->alloc_size - (pos - wcp->offset)), n);
253
254       memcpy(wcp->data + (pos - wcp->offset), data, data_used);
255
256       /*
257        * Update the current buffer size with the new data.
258        */
259
260       if(pos + data_used > wcp->offset + wcp->data_size)
261         wcp->data_size = pos + data_used - wcp->offset;
262
263       /*
264        * Update the file size if changed.
265        */
266
267       if (wcp->offset + wcp->data_size > wcp->file_size)
268         fsp->size = wcp->file_size = wcp->offset + wcp->data_size;
269
270       /*
271        * If we used all the data then
272        * return here.
273        */
274
275       if(n == data_used)
276         return n;
277       else
278         cache_flush_needed = True;
279
280       /*
281        * Move the start of data forward by the amount used,
282        * cut down the amount left by the same amount.
283        */
284
285       data += data_used;
286       pos += data_used;
287       n -= data_used;
288
289       DO_PROFILE_INC(writecache_abutted_writes);
290       total_written = data_used;
291
292       write_path = 1;
293
294     } else if ((pos < wcp->offset) && (pos + n > wcp->offset) && 
295                (pos + n <= wcp->offset + wcp->alloc_size)) {
296
297       /*
298        * End of write overlaps the existing data.
299        */
300
301       size_t data_used = pos + n - wcp->offset;
302
303       memcpy(wcp->data, data + n - data_used, data_used);
304
305       /*
306        * Update the current buffer size with the new data.
307        */
308
309       if(pos + n > wcp->offset + wcp->data_size)
310         wcp->data_size = pos + n - wcp->offset;
311
312       /*
313        * Update the file size if changed.
314        */
315
316       if (wcp->offset + wcp->data_size > wcp->file_size)
317         fsp->size = wcp->file_size = wcp->offset + wcp->data_size;
318
319       /*
320        * We don't need to move the start of data, but we
321        * cut down the amount left by the amount used.
322        */
323
324       n -= data_used;
325
326       /*
327        * We cannot have used all the data here.
328        */
329
330       cache_flush_needed = True;
331
332       DO_PROFILE_INC(writecache_abutted_writes);
333       total_written = data_used;
334
335       write_path = 2;
336
337     } else if ( (pos >= wcp->file_size) && 
338                 (wcp->offset + wcp->data_size == wcp->file_size) &&
339                 (pos > wcp->offset + wcp->data_size) && 
340                 (pos < wcp->offset + wcp->alloc_size) ) {
341
342       /*
343        * Non-contiguous write part of which fits within
344        * the cache buffer and is extending the file
345        * and the cache contents reflect the current
346        * data up to the current end of the file.
347        */
348
349       size_t data_used;
350
351       if(pos + n <= wcp->offset + wcp->alloc_size)
352         data_used = n;
353       else
354         data_used = wcp->offset + wcp->alloc_size - pos;
355
356       /*
357        * Fill in the non-continuous area with zeros.
358        */
359
360       memset(wcp->data + wcp->data_size, '\0',
361              pos - (wcp->offset + wcp->data_size) );
362
363       memcpy(wcp->data + (pos - wcp->offset), data, data_used);
364
365       /*
366        * Update the current buffer size with the new data.
367        */
368
369       if(pos + data_used > wcp->offset + wcp->data_size)
370         wcp->data_size = pos + data_used - wcp->offset;
371
372       /*
373        * Update the file size if changed.
374        */
375
376       if (wcp->offset + wcp->data_size > wcp->file_size)
377         fsp->size = wcp->file_size = wcp->offset + wcp->data_size;
378
379       /*
380        * If we used all the data then
381        * return here.
382        */
383
384       if(n == data_used)
385         return n;
386       else
387         cache_flush_needed = True;
388
389       /*
390        * Move the start of data forward by the amount used,
391        * cut down the amount left by the same amount.
392        */
393
394       data += data_used;
395       pos += data_used;
396       n -= data_used;
397
398       DO_PROFILE_INC(writecache_abutted_writes);
399       total_written = data_used;
400
401       write_path = 3;
402
403     } else {
404
405       /*
406        * Write is bigger than buffer, or there is no overlap on the
407        * low or high ends.
408        */
409
410       DEBUG(9,("write_file: non cacheable write : fd = %d, pos = %.0f, len = %u, current cache pos = %.0f \
411 len = %u\n",fsp->fd, (double)pos, (unsigned int)n, (double)wcp->offset, (unsigned int)wcp->data_size ));
412
413       /*
414        * Update the file size if needed.
415        */
416
417       if(pos + n > wcp->file_size)
418         fsp->size = wcp->file_size = pos + n;
419
420       /*
421        * If write would fit in the cache, and is larger than
422        * the data already in the cache, flush the cache and
423        * preferentially copy the data new data into it. Otherwise
424        * just write the data directly.
425        */
426
427       if ( n <= wcp->alloc_size && n > wcp->data_size) {
428         cache_flush_needed = True;
429       } else {
430         ssize_t ret = real_write_file(fsp, data, pos, n);
431
432         DO_PROFILE_INC(writecache_direct_writes);
433         if (ret == -1)
434           return ret;
435
436         if (pos + ret > wcp->file_size)
437           fsp->size = wcp->file_size = pos + ret;
438
439         return ret;
440       }
441
442       write_path = 4;
443
444     }
445
446     if(wcp->data_size > wcp->file_size)
447       fsp->size = wcp->file_size = wcp->data_size;
448
449     if (cache_flush_needed) {
450       DEBUG(3,("WRITE_FLUSH:%d: due to noncontinuous write: fd = %d, size = %.0f, pos = %.0f, \
451 n = %u, wcp->offset=%.0f, wcp->data_size=%u\n",
452              write_path, fsp->fd, (double)wcp->file_size, (double)pos, (unsigned int)n,
453              (double)wcp->offset, (unsigned int)wcp->data_size ));
454
455       flush_write_cache(fsp, WRITE_FLUSH);
456     }
457   }
458
459   /*
460    * If the write request is bigger than the cache
461    * size, write it all out.
462    */
463
464   if (n > wcp->alloc_size ) {
465     ssize_t ret = real_write_file(fsp, data, pos, n);
466     if (ret == -1)
467       return -1;
468
469     if (pos + ret > wcp->file_size)
470       fsp->size = wcp->file_size = pos + n;
471
472     DO_PROFILE_INC(writecache_direct_writes);
473     return total_written + n;
474   }
475
476   /*
477    * If there's any data left, cache it.
478    */
479
480   if (n) {
481 #ifdef WITH_PROFILE
482     if (wcp->data_size) {
483       DO_PROFILE_INC(writecache_abutted_writes);
484     } else {
485       DO_PROFILE_INC(writecache_init_writes);
486     }
487 #endif
488     memcpy(wcp->data+wcp->data_size, data, n);
489     if (wcp->data_size == 0) {
490       wcp->offset = pos;
491       DO_PROFILE_INC(writecache_num_write_caches);
492     }
493     wcp->data_size += n;
494
495     /*
496      * Update the file size if changed.
497      */
498
499     if (wcp->offset + wcp->data_size > wcp->file_size)
500       fsp->size = wcp->file_size = wcp->offset + wcp->data_size;
501     DEBUG(9,("wcp->offset = %.0f wcp->data_size = %u cache return %u\n",
502                 (double)wcp->offset, (unsigned int)wcp->data_size, (unsigned int)n));
503
504     total_written += n;
505     return total_written; /* .... that's a write :) */
506   }
507   
508   return total_written;
509 }
510
511 /****************************************************************************
512  Delete the write cache structure.
513 ****************************************************************************/
514
515 void delete_write_cache(files_struct *fsp)
516 {
517   write_cache *wcp;
518
519   if(!fsp)
520     return;
521
522   if(!(wcp = fsp->wcp))
523     return;
524
525   DO_PROFILE_DEC(writecache_allocated_write_caches);
526   allocated_write_caches--;
527
528   SMB_ASSERT(wcp->data_size == 0);
529
530   SAFE_FREE(wcp->data);
531   SAFE_FREE(fsp->wcp);
532
533   DEBUG(10,("delete_write_cache: File %s deleted write cache\n", fsp->fsp_name ));
534
535 }
536
537 /****************************************************************************
538  Setup the write cache structure.
539 ****************************************************************************/
540
541 static BOOL setup_write_cache(files_struct *fsp, SMB_OFF_T file_size)
542 {
543   ssize_t alloc_size = lp_write_cache_size(SNUM(fsp->conn));
544   write_cache *wcp;
545
546   if (allocated_write_caches >= MAX_WRITE_CACHES) 
547         return False;
548
549   if(alloc_size == 0 || fsp->wcp)
550     return False;
551
552   if((wcp = (write_cache *)malloc(sizeof(write_cache))) == NULL) {
553     DEBUG(0,("setup_write_cache: malloc fail.\n"));
554     return False;
555   }
556
557   wcp->file_size = file_size;
558   wcp->offset = 0;
559   wcp->alloc_size = alloc_size;
560   wcp->data_size = 0;
561   if((wcp->data = malloc(wcp->alloc_size)) == NULL) {
562     DEBUG(0,("setup_write_cache: malloc fail for buffer size %u.\n",
563           (unsigned int)wcp->alloc_size ));
564     SAFE_FREE(wcp);
565     return False;
566   }
567
568   memset(wcp->data, '\0', wcp->alloc_size );
569
570   fsp->wcp = wcp;
571   DO_PROFILE_INC(writecache_allocated_write_caches);
572   allocated_write_caches++;
573
574   DEBUG(10,("setup_write_cache: File %s allocated write cache size %u\n",
575                 fsp->fsp_name, wcp->alloc_size ));
576
577   return True;
578 }
579
580 /****************************************************************************
581  Cope with a size change.
582 ****************************************************************************/
583
584 void set_filelen_write_cache(files_struct *fsp, SMB_OFF_T file_size)
585 {
586   fsp->size = file_size;
587   if(fsp->wcp) {
588     /* The cache *must* have been flushed before we do this. */
589     if (fsp->wcp->data_size != 0) {
590       pstring msg;
591       slprintf(msg, sizeof(msg)-1, "set_filelen_write_cache: size change \
592 on file %s with write cache size = %u\n", fsp->fsp_name, fsp->wcp->data_size );
593       smb_panic(msg);
594     }
595     fsp->wcp->file_size = file_size;
596   }
597 }
598
599 /*******************************************************************
600  Flush a write cache struct to disk.
601 ********************************************************************/
602
603 ssize_t flush_write_cache(files_struct *fsp, enum flush_reason_enum reason)
604 {
605   write_cache *wcp = fsp->wcp;
606   size_t data_size;
607   ssize_t ret;
608
609   if(!wcp || !wcp->data_size)
610     return 0;
611
612   data_size = wcp->data_size;
613   wcp->data_size = 0;
614
615   DO_PROFILE_DEC_INC(writecache_num_write_caches,writecache_flushed_writes[reason]);
616
617   DEBUG(9,("flushing write cache: fd = %d, off=%.0f, size=%u\n",
618            fsp->fd, (double)wcp->offset, (unsigned int)data_size));
619
620 #ifdef WITH_PROFILE
621   if(data_size == wcp->alloc_size)
622     DO_PROFILE_INC(writecache_num_perfect_writes);
623 #endif
624
625   ret = real_write_file(fsp, wcp->data, wcp->offset, data_size);
626
627   /*
628    * Ensure file size if kept up to date if write extends file.
629    */
630
631   if ((ret != -1) && (wcp->offset + ret > wcp->file_size))
632     wcp->file_size = wcp->offset + ret;
633
634   return ret;
635 }
636
637 /*******************************************************************
638 sync a file
639 ********************************************************************/
640
641 void sync_file(connection_struct *conn, files_struct *fsp)
642 {
643     if(lp_strict_sync(SNUM(conn)) && fsp->fd != -1) {
644       flush_write_cache(fsp, SYNC_FLUSH);
645       conn->vfs_ops.fsync(fsp,fsp->fd);
646     }
647 }
648
649 /************************************************************
650  Perform a stat whether a valid fd or not.
651 ************************************************************/
652
653 int fsp_stat(files_struct *fsp, SMB_STRUCT_STAT *pst)
654 {
655         if (fsp->fd == -1)
656                 return vfs_stat(fsp->conn, fsp->fsp_name, pst);
657         else
658                 return vfs_fstat(fsp,fsp->fd, pst);
659 }