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