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