2 Unix SMB/CIFS implementation.
3 Wrap disk only vfs functions to sidestep dodgy compilers.
4 Copyright (C) Tim Potter 1998
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.
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.
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.
23 /* Check for NULL pointer parameters in vfswrap_* functions */
25 #define VFS_CHECK_NULL
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
31 int vfswrap_dummy_connect(connection_struct *conn, const char *service, const char *user)
33 return 0; /* Return >= 0 for success */
36 void vfswrap_dummy_disconnect(connection_struct *conn)
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)
48 if ((path == NULL) || (bsize == NULL) || (dfree == NULL) ||
51 smb_panic("NULL pointer passed to vfswrap_disk_free() function\n");
55 result = sys_disk_free(path, small_query, bsize, dfree, dsize);
59 /* Directory operations */
61 DIR *vfswrap_opendir(connection_struct *conn, const char *fname)
65 START_PROFILE(syscall_opendir);
69 smb_panic("NULL pointer passed to vfswrap_opendir()\n");
73 result = opendir(fname);
74 END_PROFILE(syscall_opendir);
78 struct dirent *vfswrap_readdir(connection_struct *conn, DIR *dirp)
80 struct dirent *result;
82 START_PROFILE(syscall_readdir);
86 smb_panic("NULL pointer passed to vfswrap_readdir()\n");
90 result = readdir(dirp);
91 END_PROFILE(syscall_readdir);
95 int vfswrap_mkdir(connection_struct *conn, const char *path, mode_t mode)
98 BOOL has_dacl = False;
100 START_PROFILE(syscall_mkdir);
102 #ifdef VFS_CHECK_NULL
104 smb_panic("NULL pointer passed to vfswrap_mkdir()\n");
108 if (lp_inherit_acls(SNUM(conn)) && (has_dacl = directory_has_default_acl(parent_dirname(path))))
111 result = mkdir(path, mode);
113 if (result == 0 && !has_dacl) {
115 * We need to do this as the default behavior of POSIX ACLs
116 * is to set the mask to be the requested group permission
117 * bits, not the group permission bits to be the requested
118 * group permission bits. This is not what we want, as it will
119 * mess up any inherited ACL bits that were set. JRA.
121 int saved_errno = errno; /* We may get ENOSYS */
122 if (conn->vfs_ops.chmod_acl != NULL) {
123 if ((conn->vfs_ops.chmod_acl(conn, path, mode) == -1) && (errno == ENOSYS))
128 END_PROFILE(syscall_mkdir);
132 int vfswrap_rmdir(connection_struct *conn, const char *path)
136 START_PROFILE(syscall_rmdir);
138 #ifdef VFS_CHECK_NULL
140 smb_panic("NULL pointer passed to vfswrap_rmdir()\n");
144 result = rmdir(path);
145 END_PROFILE(syscall_rmdir);
149 int vfswrap_closedir(connection_struct *conn, DIR *dirp)
153 START_PROFILE(syscall_closedir);
155 #ifdef VFS_CHECK_NULL
157 smb_panic("NULL pointer passed to vfswrap_closedir()\n");
161 result = closedir(dirp);
162 END_PROFILE(syscall_closedir);
166 /* File operations */
168 int vfswrap_open(connection_struct *conn, const char *fname, int flags, mode_t mode)
172 START_PROFILE(syscall_open);
174 #ifdef VFS_CHECK_NULL
176 smb_panic("NULL pointer passed to vfswrap_open()\n");
180 result = sys_open(fname, flags, mode);
181 END_PROFILE(syscall_open);
185 int vfswrap_close(files_struct *fsp, int fd)
189 START_PROFILE(syscall_close);
192 END_PROFILE(syscall_close);
196 ssize_t vfswrap_read(files_struct *fsp, int fd, void *data, size_t n)
200 START_PROFILE_BYTES(syscall_read, n);
202 #ifdef VFS_CHECK_NULL
204 smb_panic("NULL pointer passed to vfswrap_read()\n");
208 result = read(fd, data, n);
209 END_PROFILE(syscall_read);
213 ssize_t vfswrap_write(files_struct *fsp, int fd, const void *data, size_t n)
217 START_PROFILE_BYTES(syscall_write, n);
219 #ifdef VFS_CHECK_NULL
221 smb_panic("NULL pointer passed to vfswrap_write()\n");
225 result = write(fd, data, n);
226 END_PROFILE(syscall_write);
230 SMB_OFF_T vfswrap_lseek(files_struct *fsp, int filedes, SMB_OFF_T offset, int whence)
234 START_PROFILE(syscall_lseek);
236 result = sys_lseek(filedes, offset, whence);
239 * We want to maintain the fiction that we can seek
240 * on a fifo for file system purposes. This allows
241 * people to set up UNIX fifo's that feed data to Windows
245 if((result == -1) && (errno == ESPIPE)) {
250 END_PROFILE(syscall_lseek);
254 int vfswrap_rename(connection_struct *conn, const char *old, const char *new)
258 START_PROFILE(syscall_rename);
260 #ifdef VFS_CHECK_NULL
261 if ((old == NULL) || (new == NULL)) {
262 smb_panic("NULL pointer passed to vfswrap_rename()\n");
266 result = rename(old, new);
267 END_PROFILE(syscall_rename);
271 int vfswrap_fsync(files_struct *fsp, int fd)
276 START_PROFILE(syscall_fsync);
279 END_PROFILE(syscall_fsync);
286 int vfswrap_stat(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *sbuf)
290 START_PROFILE(syscall_stat);
292 #ifdef VFS_CHECK_NULL
293 if ((fname == NULL) || (sbuf == NULL)) {
294 smb_panic("NULL pointer passed to vfswrap_stat()\n");
298 result = sys_stat(fname, sbuf);
299 END_PROFILE(syscall_stat);
303 int vfswrap_fstat(files_struct *fsp, int fd, SMB_STRUCT_STAT *sbuf)
307 START_PROFILE(syscall_fstat);
309 #ifdef VFS_CHECK_NULL
311 smb_panic("NULL pointer passed to vfswrap_fstat()\n");
315 result = sys_fstat(fd, sbuf);
316 END_PROFILE(syscall_fstat);
320 int vfswrap_lstat(connection_struct *conn, const char *path, SMB_STRUCT_STAT *sbuf)
324 START_PROFILE(syscall_lstat);
326 #ifdef VFS_CHECK_NULL
327 if ((path == NULL) || (sbuf == NULL)) {
328 smb_panic("NULL pointer passed to vfswrap_lstat()\n");
332 result = sys_lstat(path, sbuf);
333 END_PROFILE(syscall_lstat);
337 int vfswrap_unlink(connection_struct *conn, const char *path)
341 START_PROFILE(syscall_unlink);
343 #ifdef VFS_CHECK_NULL
345 smb_panic("NULL pointer passed to vfswrap_unlink()\n");
349 result = unlink(path);
350 END_PROFILE(syscall_unlink);
354 int vfswrap_chmod(connection_struct *conn, const char *path, mode_t mode)
358 START_PROFILE(syscall_chmod);
360 #ifdef VFS_CHECK_NULL
362 smb_panic("NULL pointer passed to vfswrap_chmod()\n");
367 * We need to do this due to the fact that the default POSIX ACL
368 * chmod modifies the ACL *mask* for the group owner, not the
369 * group owner bits directly. JRA.
373 if (conn->vfs_ops.chmod_acl != NULL) {
374 int saved_errno = errno; /* We might get ENOSYS */
375 if ((result = conn->vfs_ops.chmod_acl(conn, path, mode)) == 0) {
376 END_PROFILE(syscall_chmod);
379 /* Error - return the old errno. */
383 result = chmod(path, mode);
384 END_PROFILE(syscall_chmod);
388 int vfswrap_fchmod(files_struct *fsp, int fd, mode_t mode)
391 struct vfs_ops *vfs_ops = &fsp->conn->vfs_ops;
393 START_PROFILE(syscall_fchmod);
396 * We need to do this due to the fact that the default POSIX ACL
397 * chmod modifies the ACL *mask* for the group owner, not the
398 * group owner bits directly. JRA.
401 if (vfs_ops->fchmod_acl != NULL) {
402 int saved_errno = errno; /* We might get ENOSYS */
403 if ((result = vfs_ops->fchmod_acl(fsp, fd, mode)) == 0) {
404 END_PROFILE(syscall_chmod);
407 /* Error - return the old errno. */
411 result = fchmod(fd, mode);
412 END_PROFILE(syscall_fchmod);
416 int vfswrap_chown(connection_struct *conn, const char *path, uid_t uid, gid_t gid)
420 START_PROFILE(syscall_chown);
422 #ifdef VFS_CHECK_NULL
424 smb_panic("NULL pointer passed to vfswrap_chown()\n");
428 result = sys_chown(path, uid, gid);
429 END_PROFILE(syscall_chown);
433 int vfswrap_fchown(files_struct *fsp, int fd, uid_t uid, gid_t gid)
437 START_PROFILE(syscall_fchown);
439 result = fchown(fd, uid, gid);
440 END_PROFILE(syscall_fchown);
444 int vfswrap_chdir(connection_struct *conn, const char *path)
448 START_PROFILE(syscall_chdir);
450 #ifdef VFS_CHECK_NULL
452 smb_panic("NULL pointer passed to vfswrap_chdir()\n");
456 result = chdir(path);
457 END_PROFILE(syscall_chdir);
461 char *vfswrap_getwd(connection_struct *conn, char *path)
465 START_PROFILE(syscall_getwd);
467 #ifdef VFS_CHECK_NULL
469 smb_panic("NULL pointer passed to vfswrap_getwd()\n");
473 result = sys_getwd(path);
474 END_PROFILE(syscall_getwd);
478 int vfswrap_utime(connection_struct *conn, const char *path, struct utimbuf *times)
482 START_PROFILE(syscall_utime);
484 #ifdef VFS_CHECK_NULL
485 if ((path == NULL) || (times == NULL)) {
486 smb_panic("NULL pointer passed to vfswrap_utime()\n");
490 result = utime(path, times);
491 END_PROFILE(syscall_utime);
495 /*********************************************************************
496 A version of ftruncate that will write the space on disk if strict
498 **********************************************************************/
500 static int strict_allocate_ftruncate(files_struct *fsp, int fd, SMB_OFF_T len)
502 struct vfs_ops *vfs_ops = &fsp->conn->vfs_ops;
504 SMB_OFF_T currpos = vfs_ops->lseek(fsp, fd, 0, SEEK_CUR);
505 unsigned char zero_space[4096];
506 SMB_OFF_T space_to_write;
511 if (vfs_ops->fstat(fsp, fd, &st) == -1)
514 space_to_write = len - st.st_size;
517 if (S_ISFIFO(st.st_mode))
521 if (st.st_size == len)
524 /* Shrink - just ftruncate. */
525 if (st.st_size > len)
526 return sys_ftruncate(fd, len);
528 /* Write out the real space on disk. */
529 if (vfs_ops->lseek(fsp, fd, st.st_size, SEEK_SET) != st.st_size)
532 space_to_write = len - st.st_size;
534 memset(zero_space, '\0', sizeof(zero_space));
535 while ( space_to_write > 0) {
537 SMB_OFF_T current_len_to_write = MIN(sizeof(zero_space),space_to_write);
539 retlen = vfs_ops->write(fsp,fsp->fd,(char *)zero_space,current_len_to_write);
543 space_to_write -= retlen;
546 /* Seek to where we were */
547 if (vfs_ops->lseek(fsp, fd, currpos, SEEK_SET) != currpos)
553 int vfswrap_ftruncate(files_struct *fsp, int fd, SMB_OFF_T len)
556 struct vfs_ops *vfs_ops = &fsp->conn->vfs_ops;
561 START_PROFILE(syscall_ftruncate);
563 if (lp_strict_allocate(SNUM(fsp->conn))) {
564 result = strict_allocate_ftruncate(fsp, fd, len);
565 END_PROFILE(syscall_ftruncate);
569 /* we used to just check HAVE_FTRUNCATE_EXTEND and only use
570 sys_ftruncate if the system supports it. Then I discovered that
571 you can have some filesystems that support ftruncate
572 expansion and some that don't! On Linux fat can't do
573 ftruncate extend but ext2 can. */
575 result = sys_ftruncate(fd, len);
579 /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
580 extend a file with ftruncate. Provide alternate implementation
582 currpos = vfs_ops->lseek(fsp, fd, 0, SEEK_CUR);
587 /* Do an fstat to see if the file is longer than the requested
588 size in which case the ftruncate above should have
589 succeeded or shorter, in which case seek to len - 1 and
590 write 1 byte of zero */
591 if (vfs_ops->fstat(fsp, fd, &st) == -1) {
596 if (S_ISFIFO(st.st_mode)) {
602 if (st.st_size == len) {
607 if (st.st_size > len) {
608 /* the sys_ftruncate should have worked */
612 if (vfs_ops->lseek(fsp, fd, len-1, SEEK_SET) != len -1)
615 if (vfs_ops->write(fsp, fd, &c, 1)!=1)
618 /* Seek to where we were */
619 if (vfs_ops->lseek(fsp, fd, currpos, SEEK_SET) != currpos)
625 END_PROFILE(syscall_ftruncate);
629 BOOL vfswrap_lock(files_struct *fsp, int fd, int op, SMB_OFF_T offset, SMB_OFF_T count, int type)
633 START_PROFILE(syscall_fcntl_lock);
635 result = fcntl_lock(fd, op, offset, count,type);
636 END_PROFILE(syscall_fcntl_lock);
640 int vfswrap_symlink(connection_struct *conn, const char *oldpath, const char *newpath)
644 START_PROFILE(syscall_symlink);
646 #ifdef VFS_CHECK_NULL
647 if ((oldpath == NULL) || (newpath == NULL))
648 smb_panic("NULL pointer passed to vfswrap_symlink()\n");
651 result = sys_symlink(oldpath, newpath);
652 END_PROFILE(syscall_symlink);
656 int vfswrap_readlink(connection_struct *conn, const char *path, char *buf, size_t bufsiz)
660 START_PROFILE(syscall_readlink);
662 #ifdef VFS_CHECK_NULL
663 if ((path == NULL) || (buf == NULL))
664 smb_panic("NULL pointer passed to vfswrap_readlink()\n");
667 result = sys_readlink(path, buf, bufsiz);
668 END_PROFILE(syscall_readlink);
672 int vfswrap_link(connection_struct *conn, const char *oldpath, const char *newpath)
676 START_PROFILE(syscall_link);
678 #ifdef VFS_CHECK_NULL
679 if ((oldpath == NULL) || (newpath == NULL))
680 smb_panic("NULL pointer passed to vfswrap_link()\n");
682 result = sys_link(oldpath, newpath);
683 END_PROFILE(syscall_link);
687 int vfswrap_mknod(connection_struct *conn, const char *pathname, mode_t mode, SMB_DEV_T dev)
691 START_PROFILE(syscall_mknod);
693 #ifdef VFS_CHECK_NULL
694 if (pathname == NULL)
695 smb_panic("NULL pointer passed to vfswrap_mknod()\n");
697 result = sys_mknod(pathname, mode, dev);
698 END_PROFILE(syscall_mknod);
702 size_t vfswrap_fget_nt_acl(files_struct *fsp, int fd, SEC_DESC **ppdesc)
706 START_PROFILE(fget_nt_acl);
707 result = get_nt_acl(fsp, ppdesc);
708 END_PROFILE(fget_nt_acl);
712 size_t vfswrap_get_nt_acl(files_struct *fsp, const char *name, SEC_DESC **ppdesc)
716 START_PROFILE(get_nt_acl);
717 result = get_nt_acl(fsp, ppdesc);
718 END_PROFILE(get_nt_acl);
722 BOOL vfswrap_fset_nt_acl(files_struct *fsp, int fd, uint32 security_info_sent, SEC_DESC *psd)
726 START_PROFILE(fset_nt_acl);
727 result = set_nt_acl(fsp, security_info_sent, psd);
728 END_PROFILE(fset_nt_acl);
732 BOOL vfswrap_set_nt_acl(files_struct *fsp, const char *name, uint32 security_info_sent, SEC_DESC *psd)
736 START_PROFILE(set_nt_acl);
737 result = set_nt_acl(fsp, security_info_sent, psd);
738 END_PROFILE(set_nt_acl);
742 int vfswrap_chmod_acl(connection_struct *conn, const char *name, mode_t mode)
746 START_PROFILE(chmod_acl);
747 result = chmod_acl(name, mode);
748 END_PROFILE(chmod_acl);
752 int vfswrap_fchmod_acl(files_struct *fsp, int fd, mode_t mode)
756 START_PROFILE(fchmod_acl);
757 result = fchmod_acl(fd, mode);
758 END_PROFILE(fchmod_acl);