preparing for release of 2.2.3a
[Samba.git] / source / smbd / vfs-wrap.c
blob1fa9e72fcc358c6671e6f795ea4d60cb9aaab482
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
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.
22 #include "includes.h"
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
30 this possibility. */
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)
41 /* Disk operations */
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)
46 SMB_BIG_UINT result;
48 #ifdef VFS_CHECK_NULL
49 if ((path == NULL) || (bsize == NULL) || (dfree == NULL) ||
50 (dsize == NULL)) {
52 smb_panic("NULL pointer passed to vfswrap_disk_free() function\n");
54 #endif
56 result = sys_disk_free(path, small_query, bsize, dfree, dsize);
57 return result;
60 /* Directory operations */
62 DIR *vfswrap_opendir(connection_struct *conn, char *fname)
64 DIR *result;
66 START_PROFILE(syscall_opendir);
68 #ifdef VFS_CHECK_NULL
69 if (fname == NULL) {
70 smb_panic("NULL pointer passed to vfswrap_opendir()\n");
72 #endif
74 result = opendir(fname);
75 END_PROFILE(syscall_opendir);
76 return result;
79 struct dirent *vfswrap_readdir(connection_struct *conn, DIR *dirp)
81 struct dirent *result;
83 START_PROFILE(syscall_readdir);
85 #ifdef VFS_CHECK_NULL
86 if (dirp == NULL) {
87 smb_panic("NULL pointer passed to vfswrap_readdir()\n");
89 #endif
91 result = readdir(dirp);
92 END_PROFILE(syscall_readdir);
93 return result;
96 int vfswrap_mkdir(connection_struct *conn, char *path, mode_t mode)
98 int result;
100 START_PROFILE(syscall_mkdir);
102 #ifdef VFS_CHECK_NULL
103 if (path == NULL) {
104 smb_panic("NULL pointer passed to vfswrap_mkdir()\n");
106 #endif
108 result = mkdir(path, mode);
110 if (result == 0) {
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))
121 errno = saved_errno;
125 END_PROFILE(syscall_mkdir);
126 return result;
129 int vfswrap_rmdir(connection_struct *conn, char *path)
131 int result;
133 START_PROFILE(syscall_rmdir);
135 #ifdef VFS_CHECK_NULL
136 if (path == NULL) {
137 smb_panic("NULL pointer passed to vfswrap_rmdir()\n");
139 #endif
141 result = rmdir(path);
142 END_PROFILE(syscall_rmdir);
143 return result;
146 int vfswrap_closedir(connection_struct *conn, DIR *dirp)
148 int result;
150 START_PROFILE(syscall_closedir);
152 #ifdef VFS_CHECK_NULL
153 if (dirp == NULL) {
154 smb_panic("NULL pointer passed to vfswrap_closedir()\n");
156 #endif
158 result = closedir(dirp);
159 END_PROFILE(syscall_closedir);
160 return result;
163 /* File operations */
165 int vfswrap_open(connection_struct *conn, char *fname, int flags, mode_t mode)
167 int result;
169 START_PROFILE(syscall_open);
171 #ifdef VFS_CHECK_NULL
172 if (fname == NULL) {
173 smb_panic("NULL pointer passed to vfswrap_open()\n");
175 #endif
177 result = sys_open(fname, flags, mode);
178 END_PROFILE(syscall_open);
179 return result;
182 int vfswrap_close(files_struct *fsp, int fd)
184 int result;
186 START_PROFILE(syscall_close);
188 result = close(fd);
189 END_PROFILE(syscall_close);
190 return result;
193 ssize_t vfswrap_read(files_struct *fsp, int fd, void *data, size_t n)
195 ssize_t result;
197 START_PROFILE_BYTES(syscall_read, n);
199 #ifdef VFS_CHECK_NULL
200 if (data == NULL) {
201 smb_panic("NULL pointer passed to vfswrap_read()\n");
203 #endif
205 result = read(fd, data, n);
206 END_PROFILE(syscall_read);
207 return result;
210 ssize_t vfswrap_write(files_struct *fsp, int fd, const void *data, size_t n)
212 ssize_t result;
214 START_PROFILE_BYTES(syscall_write, n);
216 #ifdef VFS_CHECK_NULL
217 if (data == NULL) {
218 smb_panic("NULL pointer passed to vfswrap_write()\n");
220 #endif
222 result = write(fd, data, n);
223 END_PROFILE(syscall_write);
224 return result;
227 SMB_OFF_T vfswrap_lseek(files_struct *fsp, int filedes, SMB_OFF_T offset, int whence)
229 SMB_OFF_T result;
231 START_PROFILE(syscall_lseek);
233 result = sys_lseek(filedes, offset, whence);
234 END_PROFILE(syscall_lseek);
235 return result;
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;
246 int ifd;
247 int ofd;
249 if (sys_lstat (source, &source_stats) == -1)
250 return -1;
252 if (!S_ISREG (source_stats.st_mode))
253 return -1;
255 if (unlink (dest) && errno != ENOENT)
256 return -1;
258 if((ifd = sys_open (source, O_RDONLY, 0)) < 0)
259 return -1;
261 if((ofd = sys_open (dest, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0 ) {
262 int saved_errno = errno;
263 close (ifd);
264 errno = saved_errno;
265 return -1;
268 if (transfer_file(ifd, ofd, (size_t)-1) == -1) {
269 int saved_errno = errno;
270 close (ifd);
271 close (ofd);
272 unlink (dest);
273 errno = saved_errno;
274 return -1;
277 if (close (ifd) == -1) {
278 int saved_errno = errno;
279 close (ofd);
280 errno = saved_errno;
281 return -1;
283 if (close (ofd) == -1)
284 return -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. */
293 struct utimbuf tv;
295 tv.actime = source_stats.st_atime;
296 tv.modtime = source_stats.st_mtime;
297 utime (dest, &tv);
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))
306 return -1;
308 if (chmod (dest, source_stats.st_mode & 07777))
309 return -1;
311 if (unlink (source) == -1)
312 return -1;
314 return 0;
317 int vfswrap_rename(connection_struct *conn, char *oldname, char *newname)
319 int result;
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");
327 #endif
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);
335 return result;
338 int vfswrap_fsync(files_struct *fsp, int fd)
340 #ifdef HAVE_FSYNC
341 int result;
343 START_PROFILE(syscall_fsync);
345 result = fsync(fd);
346 END_PROFILE(syscall_fsync);
347 return result;
348 #else
349 return 0;
350 #endif
353 int vfswrap_stat(connection_struct *conn, char *fname, SMB_STRUCT_STAT *sbuf)
355 int result;
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");
363 #endif
365 result = sys_stat(fname, sbuf);
366 END_PROFILE(syscall_stat);
367 return result;
370 int vfswrap_fstat(files_struct *fsp, int fd, SMB_STRUCT_STAT *sbuf)
372 int result;
374 START_PROFILE(syscall_fstat);
376 #ifdef VFS_CHECK_NULL
377 if (sbuf == NULL) {
378 smb_panic("NULL pointer passed to vfswrap_fstat()\n");
380 #endif
382 result = sys_fstat(fd, sbuf);
383 END_PROFILE(syscall_fstat);
384 return result;
387 int vfswrap_lstat(connection_struct *conn, char *path, SMB_STRUCT_STAT *sbuf)
389 int result;
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");
397 #endif
399 result = sys_lstat(path, sbuf);
400 END_PROFILE(syscall_lstat);
401 return result;
404 int vfswrap_unlink(connection_struct *conn, char *path)
406 int result;
408 START_PROFILE(syscall_unlink);
410 #ifdef VFS_CHECK_NULL
411 if (path == NULL) {
412 smb_panic("NULL pointer passed to vfswrap_unlink()\n");
414 #endif
416 result = unlink(path);
417 END_PROFILE(syscall_unlink);
418 return result;
421 int vfswrap_chmod(connection_struct *conn, char *path, mode_t mode)
423 int result;
425 START_PROFILE(syscall_chmod);
427 #ifdef VFS_CHECK_NULL
428 if (path == NULL) {
429 smb_panic("NULL pointer passed to vfswrap_chmod()\n");
431 #endif
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);
444 return result;
446 /* Error - return the old errno. */
447 errno = saved_errno;
450 result = chmod(path, mode);
451 END_PROFILE(syscall_chmod);
452 return result;
455 int vfswrap_fchmod(files_struct *fsp, int fd, mode_t mode)
457 int result;
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);
472 return result;
474 /* Error - return the old errno. */
475 errno = saved_errno;
478 result = fchmod(fd, mode);
479 END_PROFILE(syscall_fchmod);
480 return result;
483 int vfswrap_chown(connection_struct *conn, char *path, uid_t uid, gid_t gid)
485 int result;
487 START_PROFILE(syscall_chown);
489 #ifdef VFS_CHECK_NULL
490 if (path == NULL) {
491 smb_panic("NULL pointer passed to vfswrap_chown()\n");
493 #endif
495 result = sys_chown(path, uid, gid);
496 END_PROFILE(syscall_chown);
497 return result;
500 int vfswrap_fchown(files_struct *fsp, int fd, uid_t uid, gid_t gid)
502 int result;
504 START_PROFILE(syscall_fchown);
506 result = fchown(fd, uid, gid);
507 END_PROFILE(syscall_fchown);
508 return result;
511 int vfswrap_chdir(connection_struct *conn, char *path)
513 int result;
515 START_PROFILE(syscall_chdir);
517 #ifdef VFS_CHECK_NULL
518 if (path == NULL) {
519 smb_panic("NULL pointer passed to vfswrap_chdir()\n");
521 #endif
523 result = chdir(path);
524 END_PROFILE(syscall_chdir);
525 return result;
528 char *vfswrap_getwd(connection_struct *conn, char *path)
530 char *result;
532 START_PROFILE(syscall_getwd);
534 #ifdef VFS_CHECK_NULL
535 if (path == NULL) {
536 smb_panic("NULL pointer passed to vfswrap_getwd()\n");
538 #endif
540 result = sys_getwd(path);
541 END_PROFILE(syscall_getwd);
542 return result;
545 int vfswrap_utime(connection_struct *conn, char *path, struct utimbuf *times)
547 int result;
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");
555 #endif
557 result = utime(path, times);
558 END_PROFILE(syscall_utime);
559 return result;
562 /*********************************************************************
563 A version of ftruncate that will write the space on disk if strict
564 allocate is set.
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;
570 SMB_STRUCT_STAT st;
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;
575 if (currpos == -1)
576 return -1;
578 if (vfs_ops->fstat(fsp, fd, &st) == -1)
579 return -1;
581 #ifdef S_ISFIFO
582 if (S_ISFIFO(st.st_mode))
583 return 0;
584 #endif
586 if (st.st_size == len)
587 return 0;
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)
595 return -1;
597 space_to_write = len - st.st_size;
599 memset(zero_space, '\0', sizeof(zero_space));
600 while ( space_to_write > 0) {
601 SMB_OFF_T retlen;
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);
605 if (retlen <= 0)
606 return -1;
608 space_to_write -= retlen;
611 /* Seek to where we were */
612 if (vfs_ops->lseek(fsp, fd, currpos, SEEK_SET) != currpos)
613 return -1;
615 return 0;
618 int vfswrap_ftruncate(files_struct *fsp, int fd, SMB_OFF_T len)
620 int result = -1;
621 struct vfs_ops *vfs_ops = &fsp->conn->vfs_ops;
622 SMB_STRUCT_STAT st;
623 char c = 0;
624 SMB_OFF_T currpos;
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);
631 return result;
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);
641 if (result == 0)
642 goto done;
644 /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
645 extend a file with ftruncate. Provide alternate implementation
646 for this */
647 currpos = vfs_ops->lseek(fsp, fd, 0, SEEK_CUR);
648 if (currpos == -1) {
649 goto done;
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) {
657 goto done;
660 #ifdef S_ISFIFO
661 if (S_ISFIFO(st.st_mode)) {
662 result = 0;
663 goto done;
665 #endif
667 if (st.st_size == len) {
668 result = 0;
669 goto done;
672 if (st.st_size > len) {
673 /* the sys_ftruncate should have worked */
674 goto done;
677 if (vfs_ops->lseek(fsp, fd, len-1, SEEK_SET) != len -1)
678 goto done;
680 if (vfs_ops->write(fsp, fd, &c, 1)!=1)
681 goto done;
683 /* Seek to where we were */
684 if (vfs_ops->lseek(fsp, fd, currpos, SEEK_SET) != currpos)
685 goto done;
686 result = 0;
688 done:
690 END_PROFILE(syscall_ftruncate);
691 return result;
694 BOOL vfswrap_lock(files_struct *fsp, int fd, int op, SMB_OFF_T offset, SMB_OFF_T count, int type)
696 BOOL result;
698 START_PROFILE(syscall_fcntl_lock);
700 result = fcntl_lock(fd, op, offset, count,type);
701 END_PROFILE(syscall_fcntl_lock);
702 return result;
705 int vfswrap_symlink(connection_struct *conn, const char *oldpath, const char *newpath)
707 int result;
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");
714 #endif
716 result = sys_symlink(oldpath, newpath);
717 END_PROFILE(syscall_symlink);
718 return result;
721 int vfswrap_readlink(connection_struct *conn, const char *path, char *buf, size_t bufsiz)
723 int result;
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");
730 #endif
732 result = sys_readlink(path, buf, bufsiz);
733 END_PROFILE(syscall_readlink);
734 return result;
737 int vfswrap_link(connection_struct *conn, const char *oldpath, const char *newpath)
739 int result;
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");
746 #endif
747 result = sys_link(oldpath, newpath);
748 END_PROFILE(syscall_link);
749 return result;
752 int vfswrap_mknod(connection_struct *conn, const char *pathname, mode_t mode, SMB_DEV_T dev)
754 int result;
756 START_PROFILE(syscall_mknod);
758 #ifdef VFS_CHECK_NULL
759 if (pathname == NULL)
760 smb_panic("NULL pointer passed to vfswrap_mknod()\n");
761 #endif
762 result = sys_mknod(pathname, mode, dev);
763 END_PROFILE(syscall_mknod);
764 return result;
767 char *vfswrap_realpath(connection_struct *conn, const char *path, char *resolved_path)
769 char *result;
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");
776 #endif
777 result = sys_realpath(path, resolved_path);
778 END_PROFILE(syscall_realpath);
779 return result;
782 size_t vfswrap_fget_nt_acl(files_struct *fsp, int fd, SEC_DESC **ppdesc)
784 size_t result;
786 START_PROFILE(fget_nt_acl);
787 result = get_nt_acl(fsp, ppdesc);
788 END_PROFILE(fget_nt_acl);
789 return result;
792 size_t vfswrap_get_nt_acl(files_struct *fsp, char *name, SEC_DESC **ppdesc)
794 size_t result;
796 START_PROFILE(get_nt_acl);
797 result = get_nt_acl(fsp, ppdesc);
798 END_PROFILE(get_nt_acl);
799 return result;
802 BOOL vfswrap_fset_nt_acl(files_struct *fsp, int fd, uint32 security_info_sent, SEC_DESC *psd)
804 BOOL result;
806 START_PROFILE(fset_nt_acl);
807 result = set_nt_acl(fsp, security_info_sent, psd);
808 END_PROFILE(fset_nt_acl);
809 return result;
812 BOOL vfswrap_set_nt_acl(files_struct *fsp, char *name, uint32 security_info_sent, SEC_DESC *psd)
814 BOOL result;
816 START_PROFILE(set_nt_acl);
817 result = set_nt_acl(fsp, security_info_sent, psd);
818 END_PROFILE(set_nt_acl);
819 return result;
822 int vfswrap_chmod_acl(connection_struct *conn, char *name, mode_t mode)
824 int result;
826 START_PROFILE(chmod_acl);
827 result = chmod_acl(name, mode);
828 END_PROFILE(chmod_acl);
829 return result;
832 int vfswrap_fchmod_acl(files_struct *fsp, int fd, mode_t mode)
834 int result;
836 START_PROFILE(fchmod_acl);
837 result = fchmod_acl(fd, mode);
838 END_PROFILE(fchmod_acl);
839 return result;