2 Unix SMB/Netbios implementation.
4 Wrap disk only vfs functions to sidestep dodgy compilers.
5 Copyright (C) Tim Potter 1998
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 /* Check for NULL pointer parameters in vfswrap_* functions */
26 #define VFS_CHECK_NULL
28 /* We don't want to have NULL function pointers lying around. Someone
29 is sure to try and execute them. These stubs are used to prevent
32 int vfswrap_dummy_connect(connection_struct
*conn
, char *service
, char *user
)
34 return 0; /* Return >= 0 for success */
37 void vfswrap_dummy_disconnect(connection_struct
*conn
)
43 SMB_BIG_UINT
vfswrap_disk_free(connection_struct
*conn
, char *path
, BOOL small_query
, SMB_BIG_UINT
*bsize
,
44 SMB_BIG_UINT
*dfree
, SMB_BIG_UINT
*dsize
)
49 if ((path
== NULL
) || (bsize
== NULL
) || (dfree
== NULL
) ||
52 smb_panic("NULL pointer passed to vfswrap_disk_free() function\n");
56 result
= sys_disk_free(path
, small_query
, bsize
, dfree
, dsize
);
60 /* Directory operations */
62 DIR *vfswrap_opendir(connection_struct
*conn
, char *fname
)
66 START_PROFILE(syscall_opendir
);
70 smb_panic("NULL pointer passed to vfswrap_opendir()\n");
74 result
= opendir(fname
);
75 END_PROFILE(syscall_opendir
);
79 struct dirent
*vfswrap_readdir(connection_struct
*conn
, DIR *dirp
)
81 struct dirent
*result
;
83 START_PROFILE(syscall_readdir
);
87 smb_panic("NULL pointer passed to vfswrap_readdir()\n");
91 result
= readdir(dirp
);
92 END_PROFILE(syscall_readdir
);
96 int vfswrap_mkdir(connection_struct
*conn
, char *path
, mode_t mode
)
100 START_PROFILE(syscall_mkdir
);
102 #ifdef VFS_CHECK_NULL
104 smb_panic("NULL pointer passed to vfswrap_mkdir()\n");
108 result
= mkdir(path
, mode
);
112 * We need to do this as the default behavior of POSIX ACLs
113 * is to set the mask to be the requested group permission
114 * bits, not the group permission bits to be the requested
115 * group permission bits. This is not what we want, as it will
116 * mess up any inherited ACL bits that were set. JRA.
118 int saved_errno
= errno
; /* We may get ENOSYS */
119 if (conn
->vfs_ops
.chmod_acl
!= NULL
) {
120 if ((conn
->vfs_ops
.chmod_acl(conn
, path
, mode
) == -1) && (errno
== ENOSYS
))
125 END_PROFILE(syscall_mkdir
);
129 int vfswrap_rmdir(connection_struct
*conn
, char *path
)
133 START_PROFILE(syscall_rmdir
);
135 #ifdef VFS_CHECK_NULL
137 smb_panic("NULL pointer passed to vfswrap_rmdir()\n");
141 result
= rmdir(path
);
142 END_PROFILE(syscall_rmdir
);
146 int vfswrap_closedir(connection_struct
*conn
, DIR *dirp
)
150 START_PROFILE(syscall_closedir
);
152 #ifdef VFS_CHECK_NULL
154 smb_panic("NULL pointer passed to vfswrap_closedir()\n");
158 result
= closedir(dirp
);
159 END_PROFILE(syscall_closedir
);
163 /* File operations */
165 int vfswrap_open(connection_struct
*conn
, char *fname
, int flags
, mode_t mode
)
169 START_PROFILE(syscall_open
);
171 #ifdef VFS_CHECK_NULL
173 smb_panic("NULL pointer passed to vfswrap_open()\n");
177 result
= sys_open(fname
, flags
, mode
);
178 END_PROFILE(syscall_open
);
182 int vfswrap_close(files_struct
*fsp
, int fd
)
186 START_PROFILE(syscall_close
);
189 END_PROFILE(syscall_close
);
193 ssize_t
vfswrap_read(files_struct
*fsp
, int fd
, void *data
, size_t n
)
197 START_PROFILE_BYTES(syscall_read
, n
);
199 #ifdef VFS_CHECK_NULL
201 smb_panic("NULL pointer passed to vfswrap_read()\n");
205 result
= read(fd
, data
, n
);
206 END_PROFILE(syscall_read
);
210 ssize_t
vfswrap_write(files_struct
*fsp
, int fd
, const void *data
, size_t n
)
214 START_PROFILE_BYTES(syscall_write
, n
);
216 #ifdef VFS_CHECK_NULL
218 smb_panic("NULL pointer passed to vfswrap_write()\n");
222 result
= write(fd
, data
, n
);
223 END_PROFILE(syscall_write
);
227 SMB_OFF_T
vfswrap_lseek(files_struct
*fsp
, int filedes
, SMB_OFF_T offset
, int whence
)
231 START_PROFILE(syscall_lseek
);
233 result
= sys_lseek(filedes
, offset
, whence
);
234 END_PROFILE(syscall_lseek
);
238 /*********************************************************
239 For rename across filesystems Patch from Warren Birnbaum
240 <warrenb@hpcvscdp.cv.hp.com>
241 **********************************************************/
243 static int copy_reg(char *source
, const char *dest
)
245 SMB_STRUCT_STAT source_stats
;
249 if (sys_lstat (source
, &source_stats
) == -1)
252 if (!S_ISREG (source_stats
.st_mode
))
255 if (unlink (dest
) && errno
!= ENOENT
)
258 if((ifd
= sys_open (source
, O_RDONLY
, 0)) < 0)
261 if((ofd
= sys_open (dest
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0600)) < 0 ) {
262 int saved_errno
= errno
;
268 if (transfer_file(ifd
, ofd
, (size_t)-1) == -1) {
269 int saved_errno
= errno
;
277 if (close (ifd
) == -1) {
278 int saved_errno
= errno
;
283 if (close (ofd
) == -1)
287 * chown turns off set[ug]id bits for non-root,
288 * so do the chmod last.
291 /* Try to copy the old file's modtime and access time. */
295 tv
.actime
= source_stats
.st_atime
;
296 tv
.modtime
= source_stats
.st_mtime
;
301 * Try to preserve ownership. For non-root it might fail, but that's ok.
302 * But root probably wants to know, e.g. if NFS disallows it.
305 if ((chown(dest
, source_stats
.st_uid
, source_stats
.st_gid
) == -1) && (errno
!= EPERM
))
308 if (chmod (dest
, source_stats
.st_mode
& 07777))
311 if (unlink (source
) == -1)
317 int vfswrap_rename(connection_struct
*conn
, char *oldname
, char *newname
)
321 START_PROFILE(syscall_rename
);
323 #ifdef VFS_CHECK_NULL
324 if ((oldname
== NULL
) || (newname
== NULL
)) {
325 smb_panic("NULL pointer passed to vfswrap_rename()\n");
329 result
= rename(oldname
, newname
);
330 if (errno
== EXDEV
) {
331 /* Rename across filesystems needed. */
332 result
= copy_reg(oldname
, newname
);
334 END_PROFILE(syscall_rename
);
338 int vfswrap_fsync(files_struct
*fsp
, int fd
)
343 START_PROFILE(syscall_fsync
);
346 END_PROFILE(syscall_fsync
);
353 int vfswrap_stat(connection_struct
*conn
, char *fname
, SMB_STRUCT_STAT
*sbuf
)
357 START_PROFILE(syscall_stat
);
359 #ifdef VFS_CHECK_NULL
360 if ((fname
== NULL
) || (sbuf
== NULL
)) {
361 smb_panic("NULL pointer passed to vfswrap_stat()\n");
365 result
= sys_stat(fname
, sbuf
);
366 END_PROFILE(syscall_stat
);
370 int vfswrap_fstat(files_struct
*fsp
, int fd
, SMB_STRUCT_STAT
*sbuf
)
374 START_PROFILE(syscall_fstat
);
376 #ifdef VFS_CHECK_NULL
378 smb_panic("NULL pointer passed to vfswrap_fstat()\n");
382 result
= sys_fstat(fd
, sbuf
);
383 END_PROFILE(syscall_fstat
);
387 int vfswrap_lstat(connection_struct
*conn
, char *path
, SMB_STRUCT_STAT
*sbuf
)
391 START_PROFILE(syscall_lstat
);
393 #ifdef VFS_CHECK_NULL
394 if ((path
== NULL
) || (sbuf
== NULL
)) {
395 smb_panic("NULL pointer passed to vfswrap_lstat()\n");
399 result
= sys_lstat(path
, sbuf
);
400 END_PROFILE(syscall_lstat
);
404 int vfswrap_unlink(connection_struct
*conn
, char *path
)
408 START_PROFILE(syscall_unlink
);
410 #ifdef VFS_CHECK_NULL
412 smb_panic("NULL pointer passed to vfswrap_unlink()\n");
416 result
= unlink(path
);
417 END_PROFILE(syscall_unlink
);
421 int vfswrap_chmod(connection_struct
*conn
, char *path
, mode_t mode
)
425 START_PROFILE(syscall_chmod
);
427 #ifdef VFS_CHECK_NULL
429 smb_panic("NULL pointer passed to vfswrap_chmod()\n");
434 * We need to do this due to the fact that the default POSIX ACL
435 * chmod modifies the ACL *mask* for the group owner, not the
436 * group owner bits directly. JRA.
440 if (conn
->vfs_ops
.chmod_acl
!= NULL
) {
441 int saved_errno
= errno
; /* We might get ENOSYS */
442 if ((result
= conn
->vfs_ops
.chmod_acl(conn
, path
, mode
)) == 0) {
443 END_PROFILE(syscall_chmod
);
446 /* Error - return the old errno. */
450 result
= chmod(path
, mode
);
451 END_PROFILE(syscall_chmod
);
455 int vfswrap_fchmod(files_struct
*fsp
, int fd
, mode_t mode
)
458 struct vfs_ops
*vfs_ops
= &fsp
->conn
->vfs_ops
;
460 START_PROFILE(syscall_fchmod
);
463 * We need to do this due to the fact that the default POSIX ACL
464 * chmod modifies the ACL *mask* for the group owner, not the
465 * group owner bits directly. JRA.
468 if (vfs_ops
->fchmod_acl
!= NULL
) {
469 int saved_errno
= errno
; /* We might get ENOSYS */
470 if ((result
= vfs_ops
->fchmod_acl(fsp
, fd
, mode
)) == 0) {
471 END_PROFILE(syscall_chmod
);
474 /* Error - return the old errno. */
478 result
= fchmod(fd
, mode
);
479 END_PROFILE(syscall_fchmod
);
483 int vfswrap_chown(connection_struct
*conn
, char *path
, uid_t uid
, gid_t gid
)
487 START_PROFILE(syscall_chown
);
489 #ifdef VFS_CHECK_NULL
491 smb_panic("NULL pointer passed to vfswrap_chown()\n");
495 result
= sys_chown(path
, uid
, gid
);
496 END_PROFILE(syscall_chown
);
500 int vfswrap_fchown(files_struct
*fsp
, int fd
, uid_t uid
, gid_t gid
)
504 START_PROFILE(syscall_fchown
);
506 result
= fchown(fd
, uid
, gid
);
507 END_PROFILE(syscall_fchown
);
511 int vfswrap_chdir(connection_struct
*conn
, char *path
)
515 START_PROFILE(syscall_chdir
);
517 #ifdef VFS_CHECK_NULL
519 smb_panic("NULL pointer passed to vfswrap_chdir()\n");
523 result
= chdir(path
);
524 END_PROFILE(syscall_chdir
);
528 char *vfswrap_getwd(connection_struct
*conn
, char *path
)
532 START_PROFILE(syscall_getwd
);
534 #ifdef VFS_CHECK_NULL
536 smb_panic("NULL pointer passed to vfswrap_getwd()\n");
540 result
= sys_getwd(path
);
541 END_PROFILE(syscall_getwd
);
545 int vfswrap_utime(connection_struct
*conn
, char *path
, struct utimbuf
*times
)
549 START_PROFILE(syscall_utime
);
551 #ifdef VFS_CHECK_NULL
552 if ((path
== NULL
) || (times
== NULL
)) {
553 smb_panic("NULL pointer passed to vfswrap_utime()\n");
557 result
= utime(path
, times
);
558 END_PROFILE(syscall_utime
);
562 /*********************************************************************
563 A version of ftruncate that will write the space on disk if strict
565 **********************************************************************/
567 static int strict_allocate_ftruncate(files_struct
*fsp
, int fd
, SMB_OFF_T len
)
569 struct vfs_ops
*vfs_ops
= &fsp
->conn
->vfs_ops
;
571 SMB_OFF_T currpos
= vfs_ops
->lseek(fsp
, fd
, 0, SEEK_CUR
);
572 unsigned char zero_space
[4096];
573 SMB_OFF_T space_to_write
;
578 if (vfs_ops
->fstat(fsp
, fd
, &st
) == -1)
582 if (S_ISFIFO(st
.st_mode
))
586 if (st
.st_size
== len
)
589 /* Shrink - just ftruncate. */
590 if (st
.st_size
> len
)
591 return sys_ftruncate(fd
, len
);
593 /* Write out the real space on disk. */
594 if (vfs_ops
->lseek(fsp
, fd
, st
.st_size
, SEEK_SET
) != st
.st_size
)
597 space_to_write
= len
- st
.st_size
;
599 memset(zero_space
, '\0', sizeof(zero_space
));
600 while ( space_to_write
> 0) {
602 SMB_OFF_T current_len_to_write
= MIN(sizeof(zero_space
),space_to_write
);
604 retlen
= vfs_ops
->write(fsp
,fsp
->fd
,(char *)zero_space
,current_len_to_write
);
608 space_to_write
-= retlen
;
611 /* Seek to where we were */
612 if (vfs_ops
->lseek(fsp
, fd
, currpos
, SEEK_SET
) != currpos
)
618 int vfswrap_ftruncate(files_struct
*fsp
, int fd
, SMB_OFF_T len
)
621 struct vfs_ops
*vfs_ops
= &fsp
->conn
->vfs_ops
;
626 START_PROFILE(syscall_ftruncate
);
628 if (lp_strict_allocate(SNUM(fsp
->conn
))) {
629 result
= strict_allocate_ftruncate(fsp
, fd
, len
);
630 END_PROFILE(syscall_ftruncate
);
634 /* we used to just check HAVE_FTRUNCATE_EXTEND and only use
635 sys_ftruncate if the system supports it. Then I discovered that
636 you can have some filesystems that support ftruncate
637 expansion and some that don't! On Linux fat can't do
638 ftruncate extend but ext2 can. */
640 result
= sys_ftruncate(fd
, len
);
644 /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
645 extend a file with ftruncate. Provide alternate implementation
647 currpos
= vfs_ops
->lseek(fsp
, fd
, 0, SEEK_CUR
);
652 /* Do an fstat to see if the file is longer than the requested
653 size in which case the ftruncate above should have
654 succeeded or shorter, in which case seek to len - 1 and
655 write 1 byte of zero */
656 if (vfs_ops
->fstat(fsp
, fd
, &st
) == -1) {
661 if (S_ISFIFO(st
.st_mode
)) {
667 if (st
.st_size
== len
) {
672 if (st
.st_size
> len
) {
673 /* the sys_ftruncate should have worked */
677 if (vfs_ops
->lseek(fsp
, fd
, len
-1, SEEK_SET
) != len
-1)
680 if (vfs_ops
->write(fsp
, fd
, &c
, 1)!=1)
683 /* Seek to where we were */
684 if (vfs_ops
->lseek(fsp
, fd
, currpos
, SEEK_SET
) != currpos
)
690 END_PROFILE(syscall_ftruncate
);
694 BOOL
vfswrap_lock(files_struct
*fsp
, int fd
, int op
, SMB_OFF_T offset
, SMB_OFF_T count
, int type
)
698 START_PROFILE(syscall_fcntl_lock
);
700 result
= fcntl_lock(fd
, op
, offset
, count
,type
);
701 END_PROFILE(syscall_fcntl_lock
);
705 int vfswrap_symlink(connection_struct
*conn
, const char *oldpath
, const char *newpath
)
709 START_PROFILE(syscall_symlink
);
711 #ifdef VFS_CHECK_NULL
712 if ((oldpath
== NULL
) || (newpath
== NULL
))
713 smb_panic("NULL pointer passed to vfswrap_symlink()\n");
716 result
= sys_symlink(oldpath
, newpath
);
717 END_PROFILE(syscall_symlink
);
721 int vfswrap_readlink(connection_struct
*conn
, const char *path
, char *buf
, size_t bufsiz
)
725 START_PROFILE(syscall_readlink
);
727 #ifdef VFS_CHECK_NULL
728 if ((path
== NULL
) || (buf
== NULL
))
729 smb_panic("NULL pointer passed to vfswrap_readlink()\n");
732 result
= sys_readlink(path
, buf
, bufsiz
);
733 END_PROFILE(syscall_readlink
);
737 int vfswrap_link(connection_struct
*conn
, const char *oldpath
, const char *newpath
)
741 START_PROFILE(syscall_link
);
743 #ifdef VFS_CHECK_NULL
744 if ((oldpath
== NULL
) || (newpath
== NULL
))
745 smb_panic("NULL pointer passed to vfswrap_link()\n");
747 result
= sys_link(oldpath
, newpath
);
748 END_PROFILE(syscall_link
);
752 int vfswrap_mknod(connection_struct
*conn
, const char *pathname
, mode_t mode
, SMB_DEV_T dev
)
756 START_PROFILE(syscall_mknod
);
758 #ifdef VFS_CHECK_NULL
759 if (pathname
== NULL
)
760 smb_panic("NULL pointer passed to vfswrap_mknod()\n");
762 result
= sys_mknod(pathname
, mode
, dev
);
763 END_PROFILE(syscall_mknod
);
767 char *vfswrap_realpath(connection_struct
*conn
, const char *path
, char *resolved_path
)
771 START_PROFILE(syscall_realpath
);
773 #ifdef VFS_CHECK_NULL
774 if ((path
== NULL
) || (resolved_path
== NULL
))
775 smb_panic("NULL pointer passed to vfswrap_realpath()\n");
777 result
= sys_realpath(path
, resolved_path
);
778 END_PROFILE(syscall_realpath
);
782 size_t vfswrap_fget_nt_acl(files_struct
*fsp
, int fd
, SEC_DESC
**ppdesc
)
786 START_PROFILE(fget_nt_acl
);
787 result
= get_nt_acl(fsp
, ppdesc
);
788 END_PROFILE(fget_nt_acl
);
792 size_t vfswrap_get_nt_acl(files_struct
*fsp
, char *name
, SEC_DESC
**ppdesc
)
796 START_PROFILE(get_nt_acl
);
797 result
= get_nt_acl(fsp
, ppdesc
);
798 END_PROFILE(get_nt_acl
);
802 BOOL
vfswrap_fset_nt_acl(files_struct
*fsp
, int fd
, uint32 security_info_sent
, SEC_DESC
*psd
)
806 START_PROFILE(fset_nt_acl
);
807 result
= set_nt_acl(fsp
, security_info_sent
, psd
);
808 END_PROFILE(fset_nt_acl
);
812 BOOL
vfswrap_set_nt_acl(files_struct
*fsp
, char *name
, uint32 security_info_sent
, SEC_DESC
*psd
)
816 START_PROFILE(set_nt_acl
);
817 result
= set_nt_acl(fsp
, security_info_sent
, psd
);
818 END_PROFILE(set_nt_acl
);
822 int vfswrap_chmod_acl(connection_struct
*conn
, char *name
, mode_t mode
)
826 START_PROFILE(chmod_acl
);
827 result
= chmod_acl(name
, mode
);
828 END_PROFILE(chmod_acl
);
832 int vfswrap_fchmod_acl(files_struct
*fsp
, int fd
, mode_t mode
)
836 START_PROFILE(fchmod_acl
);
837 result
= fchmod_acl(fd
, mode
);
838 END_PROFILE(fchmod_acl
);