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 /* We don't want to have NULL function pointers lying around. Someone
25 is sure to try and execute them. These stubs are used to prevent
28 int vfswrap_dummy_connect(connection_struct
*conn
, const char *service
, const char *user
)
30 return 0; /* Return >= 0 for success */
33 void vfswrap_dummy_disconnect(connection_struct
*conn
)
39 SMB_BIG_UINT
vfswrap_disk_free(connection_struct
*conn
, const char *path
, BOOL small_query
, SMB_BIG_UINT
*bsize
,
40 SMB_BIG_UINT
*dfree
, SMB_BIG_UINT
*dsize
)
44 result
= sys_disk_free(path
, small_query
, bsize
, dfree
, dsize
);
48 /* Directory operations */
50 DIR *vfswrap_opendir(connection_struct
*conn
, const char *fname
)
54 START_PROFILE(syscall_opendir
);
56 result
= opendir(fname
);
57 END_PROFILE(syscall_opendir
);
61 struct dirent
*vfswrap_readdir(connection_struct
*conn
, DIR *dirp
)
63 struct dirent
*result
;
65 START_PROFILE(syscall_readdir
);
67 result
= readdir(dirp
);
68 END_PROFILE(syscall_readdir
);
72 int vfswrap_mkdir(connection_struct
*conn
, const char *path
, mode_t mode
)
75 BOOL has_dacl
= False
;
77 START_PROFILE(syscall_mkdir
);
79 if (lp_inherit_acls(SNUM(conn
)) && (has_dacl
= directory_has_default_acl(conn
, parent_dirname(path
))))
82 result
= mkdir(path
, mode
);
84 if (result
== 0 && !has_dacl
) {
86 * We need to do this as the default behavior of POSIX ACLs
87 * is to set the mask to be the requested group permission
88 * bits, not the group permission bits to be the requested
89 * group permission bits. This is not what we want, as it will
90 * mess up any inherited ACL bits that were set. JRA.
92 int saved_errno
= errno
; /* We may get ENOSYS */
93 if (conn
->vfs_ops
.chmod_acl
!= NULL
) {
94 if ((conn
->vfs_ops
.chmod_acl(conn
, path
, mode
) == -1) && (errno
== ENOSYS
))
99 END_PROFILE(syscall_mkdir
);
103 int vfswrap_rmdir(connection_struct
*conn
, const char *path
)
107 START_PROFILE(syscall_rmdir
);
109 result
= rmdir(path
);
110 END_PROFILE(syscall_rmdir
);
114 int vfswrap_closedir(connection_struct
*conn
, DIR *dirp
)
118 START_PROFILE(syscall_closedir
);
120 result
= closedir(dirp
);
121 END_PROFILE(syscall_closedir
);
125 /* File operations */
127 int vfswrap_open(connection_struct
*conn
, const char *fname
, int flags
, mode_t mode
)
131 START_PROFILE(syscall_open
);
133 result
= sys_open(fname
, flags
, mode
);
134 END_PROFILE(syscall_open
);
138 int vfswrap_close(files_struct
*fsp
, int fd
)
142 START_PROFILE(syscall_close
);
145 END_PROFILE(syscall_close
);
149 ssize_t
vfswrap_read(files_struct
*fsp
, int fd
, void *data
, size_t n
)
153 START_PROFILE_BYTES(syscall_read
, n
);
155 result
= sys_read(fd
, data
, n
);
156 END_PROFILE(syscall_read
);
160 ssize_t
vfswrap_write(files_struct
*fsp
, int fd
, const void *data
, size_t n
)
164 START_PROFILE_BYTES(syscall_write
, n
);
166 result
= sys_write(fd
, data
, n
);
167 END_PROFILE(syscall_write
);
171 ssize_t
vfswrap_sendfile(int tofd
, struct files_struct
*fsp
, int fromfd
, const DATA_BLOB
*hdr
,
172 SMB_OFF_T offset
, size_t n
)
176 START_PROFILE_BYTES(syscall_sendfile
, n
);
177 result
= sys_sendfile(tofd
, fromfd
, hdr
, offset
, n
);
178 END_PROFILE(syscall_sendfile
);
182 SMB_OFF_T
vfswrap_lseek(files_struct
*fsp
, int filedes
, SMB_OFF_T offset
, int whence
)
184 SMB_OFF_T result
= 0;
186 START_PROFILE(syscall_lseek
);
188 /* Cope with 'stat' file opens. */
190 result
= sys_lseek(filedes
, offset
, whence
);
193 * We want to maintain the fiction that we can seek
194 * on a fifo for file system purposes. This allows
195 * people to set up UNIX fifo's that feed data to Windows
199 if((result
== -1) && (errno
== ESPIPE
)) {
204 END_PROFILE(syscall_lseek
);
208 /*********************************************************
209 For rename across filesystems Patch from Warren Birnbaum
210 <warrenb@hpcvscdp.cv.hp.com>
211 **********************************************************/
213 static int copy_reg(const char *source
, const char *dest
)
215 SMB_STRUCT_STAT source_stats
;
219 if (sys_lstat (source
, &source_stats
) == -1)
222 if (!S_ISREG (source_stats
.st_mode
))
225 if (unlink (dest
) && errno
!= ENOENT
)
228 if((ifd
= sys_open (source
, O_RDONLY
, 0)) < 0)
231 if((ofd
= sys_open (dest
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0600)) < 0 ) {
232 int saved_errno
= errno
;
238 if (transfer_file(ifd
, ofd
, (size_t)-1) == -1) {
239 int saved_errno
= errno
;
247 if (close (ifd
) == -1) {
248 int saved_errno
= errno
;
253 if (close (ofd
) == -1)
257 * chown turns off set[ug]id bits for non-root,
258 * so do the chmod last.
261 /* Try to copy the old file's modtime and access time. */
265 tv
.actime
= source_stats
.st_atime
;
266 tv
.modtime
= source_stats
.st_mtime
;
271 * Try to preserve ownership. For non-root it might fail, but that's ok.
272 * But root probably wants to know, e.g. if NFS disallows it.
275 if ((chown(dest
, source_stats
.st_uid
, source_stats
.st_gid
) == -1) && (errno
!= EPERM
))
278 if (chmod (dest
, source_stats
.st_mode
& 07777))
281 if (unlink (source
) == -1)
287 int vfswrap_rename(connection_struct
*conn
, const char *oldname
, const char *newname
)
291 START_PROFILE(syscall_rename
);
292 result
= rename(oldname
, newname
);
293 if (errno
== EXDEV
) {
294 /* Rename across filesystems needed. */
295 result
= copy_reg(oldname
, newname
);
297 END_PROFILE(syscall_rename
);
301 int vfswrap_fsync(files_struct
*fsp
, int fd
)
306 START_PROFILE(syscall_fsync
);
308 END_PROFILE(syscall_fsync
);
315 int vfswrap_stat(connection_struct
*conn
, const char *fname
, SMB_STRUCT_STAT
*sbuf
)
319 START_PROFILE(syscall_stat
);
320 result
= sys_stat(fname
, sbuf
);
321 END_PROFILE(syscall_stat
);
325 int vfswrap_fstat(files_struct
*fsp
, int fd
, SMB_STRUCT_STAT
*sbuf
)
329 START_PROFILE(syscall_fstat
);
330 result
= sys_fstat(fd
, sbuf
);
331 END_PROFILE(syscall_fstat
);
335 int vfswrap_lstat(connection_struct
*conn
, const char *path
, SMB_STRUCT_STAT
*sbuf
)
339 START_PROFILE(syscall_lstat
);
340 result
= sys_lstat(path
, sbuf
);
341 END_PROFILE(syscall_lstat
);
345 int vfswrap_unlink(connection_struct
*conn
, const char *path
)
349 START_PROFILE(syscall_unlink
);
350 result
= unlink(path
);
351 END_PROFILE(syscall_unlink
);
355 int vfswrap_chmod(connection_struct
*conn
, const char *path
, mode_t mode
)
359 START_PROFILE(syscall_chmod
);
362 * We need to do this due to the fact that the default POSIX ACL
363 * chmod modifies the ACL *mask* for the group owner, not the
364 * group owner bits directly. JRA.
368 if (conn
->vfs_ops
.chmod_acl
!= NULL
) {
369 int saved_errno
= errno
; /* We might get ENOSYS */
370 if ((result
= conn
->vfs_ops
.chmod_acl(conn
, path
, mode
)) == 0) {
371 END_PROFILE(syscall_chmod
);
374 /* Error - return the old errno. */
378 result
= chmod(path
, mode
);
379 END_PROFILE(syscall_chmod
);
383 int vfswrap_fchmod(files_struct
*fsp
, int fd
, mode_t mode
)
386 struct vfs_ops
*vfs_ops
= &fsp
->conn
->vfs_ops
;
388 START_PROFILE(syscall_fchmod
);
391 * We need to do this due to the fact that the default POSIX ACL
392 * chmod modifies the ACL *mask* for the group owner, not the
393 * group owner bits directly. JRA.
396 if (vfs_ops
->fchmod_acl
!= NULL
) {
397 int saved_errno
= errno
; /* We might get ENOSYS */
398 if ((result
= vfs_ops
->fchmod_acl(fsp
, fd
, mode
)) == 0) {
399 END_PROFILE(syscall_chmod
);
402 /* Error - return the old errno. */
406 result
= fchmod(fd
, mode
);
407 END_PROFILE(syscall_fchmod
);
411 int vfswrap_chown(connection_struct
*conn
, const char *path
, uid_t uid
, gid_t gid
)
415 START_PROFILE(syscall_chown
);
416 result
= sys_chown(path
, uid
, gid
);
417 END_PROFILE(syscall_chown
);
421 int vfswrap_fchown(files_struct
*fsp
, int fd
, uid_t uid
, gid_t gid
)
426 START_PROFILE(syscall_fchown
);
428 result
= fchown(fd
, uid
, gid
);
429 END_PROFILE(syscall_fchown
);
437 int vfswrap_chdir(connection_struct
*conn
, const char *path
)
441 START_PROFILE(syscall_chdir
);
442 result
= chdir(path
);
443 END_PROFILE(syscall_chdir
);
447 char *vfswrap_getwd(connection_struct
*conn
, char *path
)
451 START_PROFILE(syscall_getwd
);
452 result
= sys_getwd(path
);
453 END_PROFILE(syscall_getwd
);
457 int vfswrap_utime(connection_struct
*conn
, const char *path
, struct utimbuf
*times
)
461 START_PROFILE(syscall_utime
);
462 result
= utime(path
, times
);
463 END_PROFILE(syscall_utime
);
467 /*********************************************************************
468 A version of ftruncate that will write the space on disk if strict
470 **********************************************************************/
472 static int strict_allocate_ftruncate(files_struct
*fsp
, int fd
, SMB_OFF_T len
)
474 struct vfs_ops
*vfs_ops
= &fsp
->conn
->vfs_ops
;
476 SMB_OFF_T currpos
= vfs_ops
->lseek(fsp
, fd
, 0, SEEK_CUR
);
477 unsigned char zero_space
[4096];
478 SMB_OFF_T space_to_write
;
483 if (vfs_ops
->fstat(fsp
, fd
, &st
) == -1)
487 if (S_ISFIFO(st
.st_mode
))
491 if (st
.st_size
== len
)
494 /* Shrink - just ftruncate. */
495 if (st
.st_size
> len
)
496 return sys_ftruncate(fd
, len
);
498 /* Write out the real space on disk. */
499 if (vfs_ops
->lseek(fsp
, fd
, st
.st_size
, SEEK_SET
) != st
.st_size
)
502 space_to_write
= len
- st
.st_size
;
504 memset(zero_space
, '\0', sizeof(zero_space
));
505 while ( space_to_write
> 0) {
507 SMB_OFF_T current_len_to_write
= MIN(sizeof(zero_space
),space_to_write
);
509 retlen
= vfs_ops
->write(fsp
,fsp
->fd
,(char *)zero_space
,current_len_to_write
);
513 space_to_write
-= retlen
;
516 /* Seek to where we were */
517 if (vfs_ops
->lseek(fsp
, fd
, currpos
, SEEK_SET
) != currpos
)
523 int vfswrap_ftruncate(files_struct
*fsp
, int fd
, SMB_OFF_T len
)
526 struct vfs_ops
*vfs_ops
= &fsp
->conn
->vfs_ops
;
531 START_PROFILE(syscall_ftruncate
);
533 if (lp_strict_allocate(SNUM(fsp
->conn
))) {
534 result
= strict_allocate_ftruncate(fsp
, fd
, len
);
535 END_PROFILE(syscall_ftruncate
);
539 /* we used to just check HAVE_FTRUNCATE_EXTEND and only use
540 sys_ftruncate if the system supports it. Then I discovered that
541 you can have some filesystems that support ftruncate
542 expansion and some that don't! On Linux fat can't do
543 ftruncate extend but ext2 can. */
545 result
= sys_ftruncate(fd
, len
);
549 /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
550 extend a file with ftruncate. Provide alternate implementation
552 currpos
= vfs_ops
->lseek(fsp
, fd
, 0, SEEK_CUR
);
557 /* Do an fstat to see if the file is longer than the requested
558 size in which case the ftruncate above should have
559 succeeded or shorter, in which case seek to len - 1 and
560 write 1 byte of zero */
561 if (vfs_ops
->fstat(fsp
, fd
, &st
) == -1) {
566 if (S_ISFIFO(st
.st_mode
)) {
572 if (st
.st_size
== len
) {
577 if (st
.st_size
> len
) {
578 /* the sys_ftruncate should have worked */
582 if (vfs_ops
->lseek(fsp
, fd
, len
-1, SEEK_SET
) != len
-1)
585 if (vfs_ops
->write(fsp
, fd
, &c
, 1)!=1)
588 /* Seek to where we were */
589 if (vfs_ops
->lseek(fsp
, fd
, currpos
, SEEK_SET
) != currpos
)
595 END_PROFILE(syscall_ftruncate
);
599 BOOL
vfswrap_lock(files_struct
*fsp
, int fd
, int op
, SMB_OFF_T offset
, SMB_OFF_T count
, int type
)
603 START_PROFILE(syscall_fcntl_lock
);
604 result
= fcntl_lock(fd
, op
, offset
, count
,type
);
605 END_PROFILE(syscall_fcntl_lock
);
609 int vfswrap_symlink(connection_struct
*conn
, const char *oldpath
, const char *newpath
)
613 START_PROFILE(syscall_symlink
);
614 result
= sys_symlink(oldpath
, newpath
);
615 END_PROFILE(syscall_symlink
);
619 int vfswrap_readlink(connection_struct
*conn
, const char *path
, char *buf
, size_t bufsiz
)
623 START_PROFILE(syscall_readlink
);
624 result
= sys_readlink(path
, buf
, bufsiz
);
625 END_PROFILE(syscall_readlink
);
629 int vfswrap_link(connection_struct
*conn
, const char *oldpath
, const char *newpath
)
633 START_PROFILE(syscall_link
);
634 result
= sys_link(oldpath
, newpath
);
635 END_PROFILE(syscall_link
);
639 int vfswrap_mknod(connection_struct
*conn
, const char *pathname
, mode_t mode
, SMB_DEV_T dev
)
643 START_PROFILE(syscall_mknod
);
644 result
= sys_mknod(pathname
, mode
, dev
);
645 END_PROFILE(syscall_mknod
);
649 char *vfswrap_realpath(connection_struct
*conn
, const char *path
, char *resolved_path
)
653 START_PROFILE(syscall_realpath
);
654 result
= sys_realpath(path
, resolved_path
);
655 END_PROFILE(syscall_realpath
);
659 size_t vfswrap_fget_nt_acl(files_struct
*fsp
, int fd
, SEC_DESC
**ppdesc
)
663 START_PROFILE(fget_nt_acl
);
664 result
= get_nt_acl(fsp
, ppdesc
);
665 END_PROFILE(fget_nt_acl
);
669 size_t vfswrap_get_nt_acl(files_struct
*fsp
, const char *name
, SEC_DESC
**ppdesc
)
673 START_PROFILE(get_nt_acl
);
674 result
= get_nt_acl(fsp
, ppdesc
);
675 END_PROFILE(get_nt_acl
);
679 BOOL
vfswrap_fset_nt_acl(files_struct
*fsp
, int fd
, uint32 security_info_sent
, SEC_DESC
*psd
)
683 START_PROFILE(fset_nt_acl
);
684 result
= set_nt_acl(fsp
, security_info_sent
, psd
);
685 END_PROFILE(fset_nt_acl
);
689 BOOL
vfswrap_set_nt_acl(files_struct
*fsp
, const char *name
, uint32 security_info_sent
, SEC_DESC
*psd
)
693 START_PROFILE(set_nt_acl
);
694 result
= set_nt_acl(fsp
, security_info_sent
, psd
);
695 END_PROFILE(set_nt_acl
);
699 int vfswrap_chmod_acl(connection_struct
*conn
, const char *name
, mode_t mode
)
703 START_PROFILE(chmod_acl
);
704 result
= chmod_acl(conn
, name
, mode
);
705 END_PROFILE(chmod_acl
);
709 int vfswrap_fchmod_acl(files_struct
*fsp
, int fd
, mode_t mode
)
713 START_PROFILE(fchmod_acl
);
714 result
= fchmod_acl(fsp
, fd
, mode
);
715 END_PROFILE(fchmod_acl
);
719 int vfswrap_sys_acl_get_entry(struct connection_struct
*conn
, SMB_ACL_T theacl
, int entry_id
, SMB_ACL_ENTRY_T
*entry_p
)
721 return sys_acl_get_entry(theacl
, entry_id
, entry_p
);
724 int vfswrap_sys_acl_get_tag_type(struct connection_struct
*conn
, SMB_ACL_ENTRY_T entry_d
, SMB_ACL_TAG_T
*tag_type_p
)
726 return sys_acl_get_tag_type(entry_d
, tag_type_p
);
729 int vfswrap_sys_acl_get_permset(struct connection_struct
*conn
, SMB_ACL_ENTRY_T entry_d
, SMB_ACL_PERMSET_T
*permset_p
)
731 return sys_acl_get_permset(entry_d
, permset_p
);
734 void * vfswrap_sys_acl_get_qualifier(struct connection_struct
*conn
, SMB_ACL_ENTRY_T entry_d
)
736 return sys_acl_get_qualifier(entry_d
);
739 SMB_ACL_T
vfswrap_sys_acl_get_file(struct connection_struct
*conn
, const char *path_p
, SMB_ACL_TYPE_T type
)
741 return sys_acl_get_file(path_p
, type
);
744 SMB_ACL_T
vfswrap_sys_acl_get_fd(struct files_struct
*fsp
, int fd
)
746 return sys_acl_get_fd(fd
);
749 int vfswrap_sys_acl_clear_perms(struct connection_struct
*conn
, SMB_ACL_PERMSET_T permset
)
751 return sys_acl_clear_perms(permset
);
754 int vfswrap_sys_acl_add_perm(struct connection_struct
*conn
, SMB_ACL_PERMSET_T permset
, SMB_ACL_PERM_T perm
)
756 return sys_acl_add_perm(permset
, perm
);
759 char * vfswrap_sys_acl_to_text(struct connection_struct
*conn
, SMB_ACL_T theacl
, ssize_t
*plen
)
761 return sys_acl_to_text(theacl
, plen
);
764 SMB_ACL_T
vfswrap_sys_acl_init(struct connection_struct
*conn
, int count
)
766 return sys_acl_init(count
);
769 int vfswrap_sys_acl_create_entry(struct connection_struct
*conn
, SMB_ACL_T
*pacl
, SMB_ACL_ENTRY_T
*pentry
)
771 return sys_acl_create_entry(pacl
, pentry
);
774 int vfswrap_sys_acl_set_tag_type(struct connection_struct
*conn
, SMB_ACL_ENTRY_T entry
, SMB_ACL_TAG_T tagtype
)
776 return sys_acl_set_tag_type(entry
, tagtype
);
779 int vfswrap_sys_acl_set_qualifier(struct connection_struct
*conn
, SMB_ACL_ENTRY_T entry
, void *qual
)
781 return sys_acl_set_qualifier(entry
, qual
);
784 int vfswrap_sys_acl_set_permset(struct connection_struct
*conn
, SMB_ACL_ENTRY_T entry
, SMB_ACL_PERMSET_T permset
)
786 return sys_acl_set_permset(entry
, permset
);
789 int vfswrap_sys_acl_valid(struct connection_struct
*conn
, SMB_ACL_T theacl
)
791 return sys_acl_valid(theacl
);
794 int vfswrap_sys_acl_set_file(struct connection_struct
*conn
, const char *name
, SMB_ACL_TYPE_T acltype
, SMB_ACL_T theacl
)
796 return sys_acl_set_file(name
, acltype
, theacl
);
799 int vfswrap_sys_acl_set_fd(struct files_struct
*fsp
, int fd
, SMB_ACL_T theacl
)
801 return sys_acl_set_fd(fd
, theacl
);
804 int vfswrap_sys_acl_delete_def_file(struct connection_struct
*conn
, const char *path
)
806 return sys_acl_delete_def_file(path
);
809 int vfswrap_sys_acl_get_perm(struct connection_struct
*conn
, SMB_ACL_PERMSET_T permset
, SMB_ACL_PERM_T perm
)
811 return sys_acl_get_perm(permset
, perm
);
814 int vfswrap_sys_acl_free_text(struct connection_struct
*conn
, char *text
)
816 return sys_acl_free_text(text
);
819 int vfswrap_sys_acl_free_acl(struct connection_struct
*conn
, SMB_ACL_T posix_acl
)
821 return sys_acl_free_acl(posix_acl
);
824 int vfswrap_sys_acl_free_qualifier(struct connection_struct
*conn
, void *qualifier
, SMB_ACL_TAG_T tagtype
)
826 return sys_acl_free_qualifier(qualifier
, tagtype
);