Fixed usage of uninitialised variable in strict_allocate_ftruncate()
[samba.git] / source3 / smbd / vfs-wrap.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Wrap disk only vfs functions to sidestep dodgy compilers.
4    Copyright (C) Tim Potter 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 /* Check for NULL pointer parameters in vfswrap_* functions */
24
25 #define VFS_CHECK_NULL
26
27 /* We don't want to have NULL function pointers lying around.  Someone
28    is sure to try and execute them.  These stubs are used to prevent
29    this possibility. */
30
31 int vfswrap_dummy_connect(connection_struct *conn, const char *service, const char *user)
32 {
33     return 0;    /* Return >= 0 for success */
34 }
35
36 void vfswrap_dummy_disconnect(connection_struct *conn)
37 {
38 }
39
40 /* Disk operations */
41
42 SMB_BIG_UINT vfswrap_disk_free(connection_struct *conn, const char *path, BOOL small_query, SMB_BIG_UINT *bsize, 
43                                SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
44 {
45     SMB_BIG_UINT result;
46
47 #ifdef VFS_CHECK_NULL
48     if ((path == NULL) || (bsize == NULL) || (dfree == NULL) ||
49         (dsize == NULL)) {
50         
51         smb_panic("NULL pointer passed to vfswrap_disk_free() function\n");
52     }
53 #endif
54
55     result = sys_disk_free(path, small_query, bsize, dfree, dsize);
56     return result;
57 }
58     
59 /* Directory operations */
60
61 DIR *vfswrap_opendir(connection_struct *conn, const char *fname)
62 {
63     DIR *result;
64
65     START_PROFILE(syscall_opendir);
66
67 #ifdef VFS_CHECK_NULL
68     if (fname == NULL) {
69         smb_panic("NULL pointer passed to vfswrap_opendir()\n");
70     }
71 #endif
72
73     result = opendir(fname);
74     END_PROFILE(syscall_opendir);
75     return result;
76 }
77
78 struct dirent *vfswrap_readdir(connection_struct *conn, DIR *dirp)
79 {
80     struct dirent *result;
81
82     START_PROFILE(syscall_readdir);
83
84 #ifdef VFS_CHECK_NULL
85     if (dirp == NULL) {
86         smb_panic("NULL pointer passed to vfswrap_readdir()\n");
87     }
88 #endif
89
90     result = readdir(dirp);
91     END_PROFILE(syscall_readdir);
92     return result;
93 }
94
95 int vfswrap_mkdir(connection_struct *conn, const char *path, mode_t mode)
96 {
97     int result;
98
99     START_PROFILE(syscall_mkdir);
100
101 #ifdef VFS_CHECK_NULL
102     if (path == NULL) {
103         smb_panic("NULL pointer passed to vfswrap_mkdir()\n");
104     }
105 #endif
106
107     result = mkdir(path, mode);
108
109         if (result == 0) {
110                 /*
111                  * We need to do this as the default behavior of POSIX ACLs     
112                  * is to set the mask to be the requested group permission
113                  * bits, not the group permission bits to be the requested
114                  * group permission bits. This is not what we want, as it will
115                  * mess up any inherited ACL bits that were set. JRA.
116                  */
117                 int saved_errno = errno; /* We may get ENOSYS */
118                 if (conn->vfs_ops.chmod_acl != NULL) {
119                         if ((conn->vfs_ops.chmod_acl(conn, path, mode) == -1) && (errno == ENOSYS))
120                                 errno = saved_errno;
121                 }
122         }
123
124     END_PROFILE(syscall_mkdir);
125     return result;
126 }
127
128 int vfswrap_rmdir(connection_struct *conn, const char *path)
129 {
130     int result;
131
132     START_PROFILE(syscall_rmdir);
133
134 #ifdef VFS_CHECK_NULL
135     if (path == NULL) {
136         smb_panic("NULL pointer passed to vfswrap_rmdir()\n");
137     }
138 #endif
139
140     result = rmdir(path);
141     END_PROFILE(syscall_rmdir);
142     return result;
143 }
144
145 int vfswrap_closedir(connection_struct *conn, DIR *dirp)
146 {
147     int result;
148
149     START_PROFILE(syscall_closedir);
150
151 #ifdef VFS_CHECK_NULL
152     if (dirp == NULL) {
153         smb_panic("NULL pointer passed to vfswrap_closedir()\n");
154     }
155 #endif
156
157     result = closedir(dirp);
158     END_PROFILE(syscall_closedir);
159     return result;
160 }
161
162 /* File operations */
163     
164 int vfswrap_open(connection_struct *conn, const char *fname, int flags, mode_t mode)
165 {
166     int result;
167
168     START_PROFILE(syscall_open);
169
170 #ifdef VFS_CHECK_NULL
171     if (fname == NULL) {
172         smb_panic("NULL pointer passed to vfswrap_open()\n");
173     }
174 #endif
175
176     result = sys_open(fname, flags, mode);
177     END_PROFILE(syscall_open);
178     return result;
179 }
180
181 int vfswrap_close(files_struct *fsp, int fd)
182 {
183     int result;
184
185     START_PROFILE(syscall_close);
186
187     result = close(fd);
188     END_PROFILE(syscall_close);
189     return result;
190 }
191
192 ssize_t vfswrap_read(files_struct *fsp, int fd, void *data, size_t n)
193 {
194     ssize_t result;
195
196     START_PROFILE_BYTES(syscall_read, n);
197
198 #ifdef VFS_CHECK_NULL
199     if (data == NULL) {
200         smb_panic("NULL pointer passed to vfswrap_read()\n");
201     }
202 #endif
203
204     result = read(fd, data, n);
205     END_PROFILE(syscall_read);
206     return result;
207 }
208
209 ssize_t vfswrap_write(files_struct *fsp, int fd, const void *data, size_t n)
210 {
211     ssize_t result;
212
213     START_PROFILE_BYTES(syscall_write, n);
214
215 #ifdef VFS_CHECK_NULL
216     if (data == NULL) {
217         smb_panic("NULL pointer passed to vfswrap_write()\n");
218     }
219 #endif
220
221     result = write(fd, data, n);
222     END_PROFILE(syscall_write);
223     return result;
224 }
225
226 SMB_OFF_T vfswrap_lseek(files_struct *fsp, int filedes, SMB_OFF_T offset, int whence)
227 {
228     SMB_OFF_T result;
229
230     START_PROFILE(syscall_lseek);
231
232     result = sys_lseek(filedes, offset, whence);
233     END_PROFILE(syscall_lseek);
234     return result;
235 }
236
237 int vfswrap_rename(connection_struct *conn, const char *old, const char *new)
238 {
239     int result;
240
241     START_PROFILE(syscall_rename);
242
243 #ifdef VFS_CHECK_NULL
244     if ((old == NULL) || (new == NULL)) {
245         smb_panic("NULL pointer passed to vfswrap_rename()\n");
246     }
247 #endif
248
249     result = rename(old, new);
250     END_PROFILE(syscall_rename);
251     return result;
252 }
253
254 int vfswrap_fsync(files_struct *fsp, int fd)
255 {
256 #ifdef HAVE_FSYNC
257     int result;
258
259     START_PROFILE(syscall_fsync);
260
261     result = fsync(fd);
262     END_PROFILE(syscall_fsync);
263     return result;
264 #else
265         return 0;
266 #endif
267 }
268
269 int vfswrap_stat(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *sbuf)
270 {
271     int result;
272
273     START_PROFILE(syscall_stat);
274
275 #ifdef VFS_CHECK_NULL
276     if ((fname == NULL) || (sbuf == NULL)) {
277         smb_panic("NULL pointer passed to vfswrap_stat()\n");
278     }
279 #endif
280
281     result = sys_stat(fname, sbuf);
282     END_PROFILE(syscall_stat);
283     return result;
284 }
285
286 int vfswrap_fstat(files_struct *fsp, int fd, SMB_STRUCT_STAT *sbuf)
287 {
288     int result;
289
290     START_PROFILE(syscall_fstat);
291
292 #ifdef VFS_CHECK_NULL
293     if (sbuf == NULL) {
294         smb_panic("NULL pointer passed to vfswrap_fstat()\n");
295     }
296 #endif
297
298     result = sys_fstat(fd, sbuf);
299     END_PROFILE(syscall_fstat);
300     return result;
301 }
302
303 int vfswrap_lstat(connection_struct *conn, const char *path, SMB_STRUCT_STAT *sbuf)
304 {
305     int result;
306
307     START_PROFILE(syscall_lstat);
308
309 #ifdef VFS_CHECK_NULL
310     if ((path == NULL) || (sbuf == NULL)) {
311         smb_panic("NULL pointer passed to vfswrap_lstat()\n");
312     }
313 #endif
314
315     result = sys_lstat(path, sbuf);
316     END_PROFILE(syscall_lstat);
317     return result;
318 }
319
320 int vfswrap_unlink(connection_struct *conn, const char *path)
321 {
322     int result;
323
324     START_PROFILE(syscall_unlink);
325
326 #ifdef VFS_CHECK_NULL
327     if (path == NULL) {
328         smb_panic("NULL pointer passed to vfswrap_unlink()\n");
329     }
330 #endif
331
332     result = unlink(path);
333     END_PROFILE(syscall_unlink);
334     return result;
335 }
336
337 int vfswrap_chmod(connection_struct *conn, const char *path, mode_t mode)
338 {
339     int result;
340
341     START_PROFILE(syscall_chmod);
342
343 #ifdef VFS_CHECK_NULL
344     if (path == NULL) {
345         smb_panic("NULL pointer passed to vfswrap_chmod()\n");
346     }
347 #endif
348
349         /*
350          * We need to do this due to the fact that the default POSIX ACL
351          * chmod modifies the ACL *mask* for the group owner, not the
352          * group owner bits directly. JRA.
353          */
354
355         
356         if (conn->vfs_ops.chmod_acl != NULL) {
357                 int saved_errno = errno; /* We might get ENOSYS */
358                 if ((result = conn->vfs_ops.chmod_acl(conn, path, mode)) == 0) {
359                         END_PROFILE(syscall_chmod);
360                         return result;
361                 }
362                 /* Error - return the old errno. */
363                 errno = saved_errno;
364         }
365
366     result = chmod(path, mode);
367     END_PROFILE(syscall_chmod);
368     return result;
369 }
370
371 int vfswrap_fchmod(files_struct *fsp, int fd, mode_t mode)
372 {
373     int result;
374         struct vfs_ops *vfs_ops = &fsp->conn->vfs_ops;
375         
376     START_PROFILE(syscall_fchmod);
377
378         /*
379          * We need to do this due to the fact that the default POSIX ACL
380          * chmod modifies the ACL *mask* for the group owner, not the
381          * group owner bits directly. JRA.
382          */
383         
384         if (vfs_ops->fchmod_acl != NULL) {
385                 int saved_errno = errno; /* We might get ENOSYS */
386                 if ((result = vfs_ops->fchmod_acl(fsp, fd, mode)) == 0) {
387                         END_PROFILE(syscall_chmod);
388                         return result;
389                 }
390                 /* Error - return the old errno. */
391                 errno = saved_errno;
392         }
393
394     result = fchmod(fd, mode);
395     END_PROFILE(syscall_fchmod);
396     return result;
397 }
398
399 int vfswrap_chown(connection_struct *conn, const char *path, uid_t uid, gid_t gid)
400 {
401     int result;
402
403     START_PROFILE(syscall_chown);
404
405 #ifdef VFS_CHECK_NULL
406     if (path == NULL) {
407         smb_panic("NULL pointer passed to vfswrap_chown()\n");
408     }
409 #endif
410
411     result = sys_chown(path, uid, gid);
412     END_PROFILE(syscall_chown);
413     return result;
414 }
415
416 int vfswrap_fchown(files_struct *fsp, int fd, uid_t uid, gid_t gid)
417 {
418     int result;
419
420     START_PROFILE(syscall_fchown);
421
422     result = fchown(fd, uid, gid);
423     END_PROFILE(syscall_fchown);
424     return result;
425 }
426
427 int vfswrap_chdir(connection_struct *conn, const char *path)
428 {
429     int result;
430
431     START_PROFILE(syscall_chdir);
432
433 #ifdef VFS_CHECK_NULL
434     if (path == NULL) {
435         smb_panic("NULL pointer passed to vfswrap_chdir()\n");
436     }
437 #endif
438
439     result = chdir(path);
440     END_PROFILE(syscall_chdir);
441     return result;
442 }
443
444 char *vfswrap_getwd(connection_struct *conn, char *path)
445 {
446     char *result;
447
448     START_PROFILE(syscall_getwd);
449
450 #ifdef VFS_CHECK_NULL
451     if (path == NULL) {
452         smb_panic("NULL pointer passed to vfswrap_getwd()\n");
453     }
454 #endif
455
456     result = sys_getwd(path);
457     END_PROFILE(syscall_getwd);
458     return result;
459 }
460
461 int vfswrap_utime(connection_struct *conn, const char *path, struct utimbuf *times)
462 {
463     int result;
464
465     START_PROFILE(syscall_utime);
466
467 #ifdef VFS_CHECK_NULL
468     if ((path == NULL) || (times == NULL)) {
469         smb_panic("NULL pointer passed to vfswrap_utime()\n");
470     }
471 #endif
472
473     result = utime(path, times);
474     END_PROFILE(syscall_utime);
475     return result;
476 }
477
478 /*********************************************************************
479  A version of ftruncate that will write the space on disk if strict
480  allocate is set.
481 **********************************************************************/
482
483 static int strict_allocate_ftruncate(files_struct *fsp, int fd, SMB_OFF_T len)
484 {
485         struct vfs_ops *vfs_ops = &fsp->conn->vfs_ops;
486         SMB_STRUCT_STAT st;
487         SMB_OFF_T currpos = vfs_ops->lseek(fsp, fd, 0, SEEK_CUR);
488         unsigned char zero_space[4096];
489         SMB_OFF_T space_to_write;
490
491         if (currpos == -1)
492                 return -1;
493
494         if (vfs_ops->fstat(fsp, fd, &st) == -1)
495                 return -1;
496
497         space_to_write = len - st.st_size;
498
499 #ifdef S_ISFIFO
500         if (S_ISFIFO(st.st_mode))
501                 return 0;
502 #endif
503
504         if (st.st_size == len)
505                 return 0;
506
507         /* Shrink - just ftruncate. */
508         if (st.st_size > len)
509                 return sys_ftruncate(fd, len);
510
511         /* Write out the real space on disk. */
512         if (vfs_ops->lseek(fsp, fd, st.st_size, SEEK_SET) != st.st_size)
513                 return -1;
514
515         space_to_write = len - st.st_size;
516
517         memset(zero_space, '\0', sizeof(zero_space));
518         while ( space_to_write > 0) {
519                 SMB_OFF_T retlen;
520                 SMB_OFF_T current_len_to_write = MIN(sizeof(zero_space),space_to_write);
521
522                 retlen = vfs_ops->write(fsp,fsp->fd,(char *)zero_space,current_len_to_write);
523                 if (retlen <= 0)
524                         return -1;
525
526                 space_to_write -= retlen;
527         }
528
529         /* Seek to where we were */
530         if (vfs_ops->lseek(fsp, fd, currpos, SEEK_SET) != currpos)
531                 return -1;
532
533         return 0;
534 }
535
536 int vfswrap_ftruncate(files_struct *fsp, int fd, SMB_OFF_T len)
537 {
538         int result = -1;
539         struct vfs_ops *vfs_ops = &fsp->conn->vfs_ops;
540         SMB_STRUCT_STAT st;
541         char c = 0;
542         SMB_OFF_T currpos;
543
544         START_PROFILE(syscall_ftruncate);
545
546         if (lp_strict_allocate(SNUM(fsp->conn))) {
547                 result = strict_allocate_ftruncate(fsp, fd, len);
548                 END_PROFILE(syscall_ftruncate);
549                 return result;
550         }
551
552         /* we used to just check HAVE_FTRUNCATE_EXTEND and only use
553            sys_ftruncate if the system supports it. Then I discovered that
554            you can have some filesystems that support ftruncate
555            expansion and some that don't! On Linux fat can't do
556            ftruncate extend but ext2 can. */
557
558         result = sys_ftruncate(fd, len);
559         if (result == 0)
560                 goto done;
561
562         /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
563            extend a file with ftruncate. Provide alternate implementation
564            for this */
565         currpos = vfs_ops->lseek(fsp, fd, 0, SEEK_CUR);
566         if (currpos == -1) {
567                 goto done;
568         }
569
570         /* Do an fstat to see if the file is longer than the requested
571            size in which case the ftruncate above should have
572            succeeded or shorter, in which case seek to len - 1 and
573            write 1 byte of zero */
574         if (vfs_ops->fstat(fsp, fd, &st) == -1) {
575                 goto done;
576         }
577
578 #ifdef S_ISFIFO
579         if (S_ISFIFO(st.st_mode)) {
580                 result = 0;
581                 goto done;
582         }
583 #endif
584
585         if (st.st_size == len) {
586                 result = 0;
587                 goto done;
588         }
589
590         if (st.st_size > len) {
591                 /* the sys_ftruncate should have worked */
592                 goto done;
593         }
594
595         if (vfs_ops->lseek(fsp, fd, len-1, SEEK_SET) != len -1)
596                 goto done;
597
598         if (vfs_ops->write(fsp, fd, &c, 1)!=1)
599                 goto done;
600
601         /* Seek to where we were */
602         if (vfs_ops->lseek(fsp, fd, currpos, SEEK_SET) != currpos)
603                 goto done;
604         result = 0;
605
606   done:
607
608         END_PROFILE(syscall_ftruncate);
609         return result;
610 }
611
612 BOOL vfswrap_lock(files_struct *fsp, int fd, int op, SMB_OFF_T offset, SMB_OFF_T count, int type)
613 {
614     BOOL result;
615
616     START_PROFILE(syscall_fcntl_lock);
617
618     result =  fcntl_lock(fd, op, offset, count,type);
619     END_PROFILE(syscall_fcntl_lock);
620     return result;
621 }
622
623 int vfswrap_symlink(connection_struct *conn, const char *oldpath, const char *newpath)
624 {
625     int result;
626
627     START_PROFILE(syscall_symlink);
628
629 #ifdef VFS_CHECK_NULL
630     if ((oldpath == NULL) || (newpath == NULL))
631                 smb_panic("NULL pointer passed to vfswrap_symlink()\n");
632 #endif
633
634     result = sys_symlink(oldpath, newpath);
635     END_PROFILE(syscall_symlink);
636     return result;
637 }
638
639 int vfswrap_readlink(connection_struct *conn, const char *path, char *buf, size_t bufsiz)
640 {
641     int result;
642
643     START_PROFILE(syscall_readlink);
644
645 #ifdef VFS_CHECK_NULL
646     if ((path == NULL) || (buf == NULL))
647                 smb_panic("NULL pointer passed to vfswrap_readlink()\n");
648 #endif
649
650     result = sys_readlink(path, buf, bufsiz);
651     END_PROFILE(syscall_readlink);
652     return result;
653 }
654
655 int vfswrap_link(connection_struct *conn, const char *oldpath, const char *newpath)
656 {
657         int result;
658
659         START_PROFILE(syscall_link);
660
661 #ifdef VFS_CHECK_NULL
662         if ((oldpath == NULL) || (newpath == NULL))
663                 smb_panic("NULL pointer passed to vfswrap_link()\n");
664 #endif
665         result = sys_link(oldpath, newpath);
666         END_PROFILE(syscall_link);
667         return result;
668 }
669
670 int vfswrap_mknod(connection_struct *conn, const char *pathname, mode_t mode, SMB_DEV_T dev)
671 {
672         int result;
673
674         START_PROFILE(syscall_mknod);
675
676 #ifdef VFS_CHECK_NULL
677         if (pathname == NULL)
678                 smb_panic("NULL pointer passed to vfswrap_mknod()\n");
679 #endif
680         result = sys_mknod(pathname, mode, dev);
681         END_PROFILE(syscall_mknod);
682         return result;
683 }
684
685 size_t vfswrap_fget_nt_acl(files_struct *fsp, int fd, SEC_DESC **ppdesc)
686 {
687         size_t result;
688
689         START_PROFILE(fget_nt_acl);
690         result = get_nt_acl(fsp, ppdesc);
691         END_PROFILE(fget_nt_acl);
692         return result;
693 }
694
695 size_t vfswrap_get_nt_acl(files_struct *fsp, const char *name, SEC_DESC **ppdesc)
696 {
697         size_t result;
698
699         START_PROFILE(get_nt_acl);
700         result = get_nt_acl(fsp, ppdesc);
701         END_PROFILE(get_nt_acl);
702         return result;
703 }
704
705 BOOL vfswrap_fset_nt_acl(files_struct *fsp, int fd, uint32 security_info_sent, SEC_DESC *psd)
706 {
707         BOOL result;
708
709         START_PROFILE(fset_nt_acl);
710         result = set_nt_acl(fsp, security_info_sent, psd);
711         END_PROFILE(fset_nt_acl);
712         return result;
713 }
714
715 BOOL vfswrap_set_nt_acl(files_struct *fsp, const char *name, uint32 security_info_sent, SEC_DESC *psd)
716 {
717         BOOL result;
718
719         START_PROFILE(set_nt_acl);
720         result = set_nt_acl(fsp, security_info_sent, psd);
721         END_PROFILE(set_nt_acl);
722         return result;
723 }
724
725 int vfswrap_chmod_acl(connection_struct *conn, const char *name, mode_t mode)
726 {
727         int result;
728
729         START_PROFILE(chmod_acl);
730         result = chmod_acl(name, mode);
731         END_PROFILE(chmod_acl);
732         return result;
733 }
734
735 int vfswrap_fchmod_acl(files_struct *fsp, int fd, mode_t mode)
736 {
737         int result;
738
739         START_PROFILE(fchmod_acl);
740         result = fchmod_acl(fd, mode);
741         END_PROFILE(fchmod_acl);
742         return result;
743 }