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