if we are adding a new sambaAccount, make sure that we add a
[Samba.git] / source / smbd / vfs.c
blobfd25d9956348aae411c3f318a81733855d938064
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
4 VFS initialisation and support functions
5 Copyright (C) Tim Potter 1999
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 /* Some structures to help us initialise the vfs operations table */
26 struct vfs_syminfo {
27 char *name;
28 void *fptr;
31 /* Default vfs hooks. WARNING: The order of these initialisers is
32 very important. They must be in the same order as defined in
33 vfs.h. Change at your own peril. */
35 struct vfs_ops default_vfs_ops = {
37 /* Disk operations */
39 vfswrap_dummy_connect,
40 vfswrap_dummy_disconnect,
41 vfswrap_disk_free,
43 /* Directory operations */
45 vfswrap_opendir,
46 vfswrap_readdir,
47 vfswrap_mkdir,
48 vfswrap_rmdir,
49 vfswrap_closedir,
51 /* File operations */
53 vfswrap_open,
54 vfswrap_close,
55 vfswrap_read,
56 vfswrap_write,
57 vfswrap_lseek,
58 vfswrap_rename,
59 vfswrap_fsync,
60 vfswrap_stat,
61 vfswrap_fstat,
62 vfswrap_lstat,
63 vfswrap_unlink,
64 vfswrap_chmod,
65 vfswrap_fchmod,
66 vfswrap_chown,
67 vfswrap_fchown,
68 vfswrap_chdir,
69 vfswrap_getwd,
70 vfswrap_utime,
71 vfswrap_ftruncate,
72 vfswrap_lock,
73 vfswrap_symlink,
74 vfswrap_readlink,
75 vfswrap_link,
76 vfswrap_mknod,
77 vfswrap_realpath,
79 vfswrap_fget_nt_acl,
80 vfswrap_get_nt_acl,
81 vfswrap_fset_nt_acl,
82 vfswrap_set_nt_acl,
84 /* POSIX ACL operations. */
85 #if defined(HAVE_NO_ACLS)
86 NULL,
87 NULL,
88 #else
89 vfswrap_chmod_acl,
90 vfswrap_fchmod_acl,
91 #endif
92 vfswrap_sys_acl_get_entry,
93 vfswrap_sys_acl_get_tag_type,
94 vfswrap_sys_acl_get_permset,
95 vfswrap_sys_acl_get_qualifier,
96 vfswrap_sys_acl_get_file,
97 vfswrap_sys_acl_get_fd,
98 vfswrap_sys_acl_clear_perms,
99 vfswrap_sys_acl_add_perm,
100 vfswrap_sys_acl_to_text,
101 vfswrap_sys_acl_init,
102 vfswrap_sys_acl_create_entry,
103 vfswrap_sys_acl_set_tag_type,
104 vfswrap_sys_acl_set_qualifier,
105 vfswrap_sys_acl_set_permset,
106 vfswrap_sys_acl_valid,
107 vfswrap_sys_acl_set_file,
108 vfswrap_sys_acl_set_fd,
109 vfswrap_sys_acl_delete_def_file,
110 vfswrap_sys_acl_get_perm,
111 vfswrap_sys_acl_free_text,
112 vfswrap_sys_acl_free_acl,
113 vfswrap_sys_acl_free_qualifier
116 /****************************************************************************
117 initialise default vfs hooks
118 ****************************************************************************/
120 static BOOL vfs_init_default(connection_struct *conn)
122 DEBUG(3, ("Initialising default vfs hooks\n"));
124 memcpy(&conn->vfs_ops, &default_vfs_ops, sizeof(struct vfs_ops));
125 return True;
128 /****************************************************************************
129 initialise custom vfs hooks
130 ****************************************************************************/
132 static BOOL vfs_init_custom(connection_struct *conn)
134 int vfs_version = -1;
135 struct vfs_ops *ops, *(*init_fptr)(int *, struct vfs_ops *);
137 DEBUG(3, ("Initialising custom vfs hooks from %s\n", lp_vfsobj(SNUM(conn))));
139 /* Open object file */
141 if ((conn->dl_handle = sys_dlopen(lp_vfsobj(SNUM(conn)), RTLD_NOW | RTLD_GLOBAL)) == NULL) {
142 DEBUG(0, ("Error opening %s: %s\n", lp_vfsobj(SNUM(conn)), sys_dlerror()));
143 return False;
146 /* Get handle on vfs_init() symbol */
148 init_fptr = (struct vfs_ops *(*)(int *, struct vfs_ops *))sys_dlsym(conn->dl_handle, "vfs_init");
150 if (init_fptr == NULL) {
151 DEBUG(0, ("No vfs_init() symbol found in %s\n", lp_vfsobj(SNUM(conn))));
152 return False;
155 /* Initialise vfs_ops structure */
157 conn->vfs_ops = default_vfs_ops;
159 if ((ops = init_fptr(&vfs_version, &default_vfs_ops)) == NULL) {
160 DEBUG(0, ("vfs_init function from %s failed\n", lp_vfsobj(SNUM(conn))));
161 return False;
164 if (vfs_version != SMB_VFS_INTERFACE_VERSION) {
165 DEBUG(0, ("vfs_init returned wrong interface version info (was %d, should be %d)\n",
166 vfs_version, SMB_VFS_INTERFACE_VERSION ));
167 return False;
170 if (ops != &conn->vfs_ops) {
171 memcpy(&conn->vfs_ops, ops, sizeof(struct vfs_ops));
174 return True;
177 /*****************************************************************
178 Generic VFS init.
179 ******************************************************************/
181 BOOL smbd_vfs_init(connection_struct *conn)
183 if (*lp_vfsobj(SNUM(conn))) {
184 /* Loadable object file */
186 if (!vfs_init_custom(conn)) {
187 DEBUG(0, ("smbd_vfs_init: vfs_init_custom failed\n"));
188 return False;
191 return True;
194 /* Normal share - initialise with disk access functions */
196 return vfs_init_default(conn);
199 /*******************************************************************
200 Check if directory exists.
201 ********************************************************************/
203 BOOL vfs_directory_exist(connection_struct *conn, const char *dname, SMB_STRUCT_STAT *st)
205 SMB_STRUCT_STAT st2;
206 BOOL ret;
208 if (!st)
209 st = &st2;
211 if (vfs_stat(conn,dname,st) != 0)
212 return(False);
214 ret = S_ISDIR(st->st_mode);
215 if(!ret)
216 errno = ENOTDIR;
218 return ret;
221 /*******************************************************************
222 vfs mkdir wrapper that calls dos_to_unix.
223 ********************************************************************/
225 int vfs_mkdir(connection_struct *conn, char *const fname, mode_t mode)
227 int ret;
228 pstring name;
229 SMB_STRUCT_STAT sbuf;
231 pstrcpy(name,dos_to_unix_static(fname)); /* paranoia copy */
232 if(!(ret=conn->vfs_ops.mkdir(conn,name,mode))) {
234 * Check if high bits should have been set,
235 * then (if bits are missing): add them.
236 * Consider bits automagically set by UNIX, i.e. SGID bit from parent dir.
238 if(mode & ~(S_IRWXU|S_IRWXG|S_IRWXO) &&
239 !vfs_stat(conn,name,&sbuf) && (mode & ~sbuf.st_mode))
240 vfs_chmod(conn,name,sbuf.st_mode | (mode & ~sbuf.st_mode));
242 return ret;
245 /*******************************************************************
246 vfs getwd wrapper that calls dos_to_unix.
247 ********************************************************************/
249 char *vfs_getwd(connection_struct *conn, char *unix_path)
251 char *wd;
252 wd = conn->vfs_ops.getwd(conn,unix_path);
253 if (wd)
254 unix_to_dos(wd);
255 return wd;
258 /*******************************************************************
259 Check if an object exists in the vfs.
260 ********************************************************************/
262 BOOL vfs_object_exist(connection_struct *conn, const char *fname,SMB_STRUCT_STAT *sbuf)
264 SMB_STRUCT_STAT st;
266 if (!sbuf)
267 sbuf = &st;
269 ZERO_STRUCTP(sbuf);
271 if (vfs_stat(conn,fname,sbuf) == -1)
272 return(False);
273 return True;
276 /*******************************************************************
277 Check if a file exists in the vfs.
278 ********************************************************************/
280 BOOL vfs_file_exist(connection_struct *conn, const char *fname,SMB_STRUCT_STAT *sbuf)
282 SMB_STRUCT_STAT st;
284 if (!sbuf)
285 sbuf = &st;
287 ZERO_STRUCTP(sbuf);
289 if (vfs_stat(conn,fname,sbuf) == -1)
290 return False;
291 return(S_ISREG(sbuf->st_mode));
294 /****************************************************************************
295 Read data from fsp on the vfs. (note: EINTR re-read differs from vfs_write_data)
296 ****************************************************************************/
298 ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count)
300 size_t total=0;
302 while (total < byte_count)
304 ssize_t ret = fsp->conn->vfs_ops.read(fsp, fsp->fd, buf + total,
305 byte_count - total);
307 if (ret == 0) return total;
308 if (ret == -1) {
309 if (errno == EINTR)
310 continue;
311 else
312 return -1;
314 total += ret;
316 return (ssize_t)total;
319 /****************************************************************************
320 Write data to a fd on the vfs.
321 ****************************************************************************/
323 ssize_t vfs_write_data(files_struct *fsp,const char *buffer,size_t N)
325 size_t total=0;
326 ssize_t ret;
328 while (total < N) {
329 ret = fsp->conn->vfs_ops.write(fsp,fsp->fd,buffer + total,N - total);
331 if (ret == -1)
332 return -1;
333 if (ret == 0)
334 return total;
336 total += ret;
339 return (ssize_t)total;
342 /****************************************************************************
343 An allocate file space call using the vfs interface.
344 Allocates space for a file from a filedescriptor.
345 Returns 0 on success, -1 on failure.
346 ****************************************************************************/
348 int vfs_allocate_file_space(files_struct *fsp, SMB_OFF_T len)
350 int ret;
351 SMB_STRUCT_STAT st;
352 connection_struct *conn = fsp->conn;
353 struct vfs_ops *vfs_ops = &conn->vfs_ops;
354 SMB_OFF_T space_avail;
355 SMB_BIG_UINT bsize,dfree,dsize;
357 release_level_2_oplocks_on_change(fsp);
360 * Actually try and commit the space on disk....
363 DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", fsp->fsp_name, (double)len ));
365 ret = vfs_fstat(fsp,fsp->fd,&st);
366 if (ret == -1)
367 return ret;
369 if (len == st.st_size)
370 return 0;
372 if (len < st.st_size) {
373 /* Shrink - use ftruncate. */
375 DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
376 fsp->fsp_name, (double)st.st_size ));
378 flush_write_cache(fsp, SIZECHANGE_FLUSH);
379 if ((ret = vfs_ops->ftruncate(fsp, fsp->fd, len)) != -1) {
380 set_filelen_write_cache(fsp, len);
382 return ret;
385 /* Grow - we need to test if we have enough space. */
387 if (!lp_strict_allocate(SNUM(fsp->conn)))
388 return 0;
390 len -= st.st_size;
391 len /= 1024; /* Len is now number of 1k blocks needed. */
392 space_avail = (SMB_OFF_T)conn->vfs_ops.disk_free(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize);
394 DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %lu, space avail = %lu\n",
395 fsp->fsp_name, (double)st.st_size, (unsigned long)len, (unsigned long)space_avail ));
397 if (len > space_avail) {
398 errno = ENOSPC;
399 return -1;
402 return 0;
405 /****************************************************************************
406 A vfs set_filelen call.
407 set the length of a file from a filedescriptor.
408 Returns 0 on success, -1 on failure.
409 ****************************************************************************/
411 int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
413 int ret;
415 release_level_2_oplocks_on_change(fsp);
416 DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len));
417 flush_write_cache(fsp, SIZECHANGE_FLUSH);
418 if ((ret = fsp->conn->vfs_ops.ftruncate(fsp, fsp->fd, len)) != -1)
419 set_filelen_write_cache(fsp, len);
421 return ret;
424 /****************************************************************************
425 Transfer some data (n bytes) between two file_struct's.
426 ****************************************************************************/
428 static files_struct *in_fsp;
429 static files_struct *out_fsp;
431 static ssize_t read_fn(int fd, void *buf, size_t len)
433 return in_fsp->conn->vfs_ops.read(in_fsp, fd, buf, len);
436 static ssize_t write_fn(int fd, const void *buf, size_t len)
438 return out_fsp->conn->vfs_ops.write(out_fsp, fd, buf, len);
441 SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n)
443 in_fsp = in;
444 out_fsp = out;
446 return transfer_file_internal(in_fsp->fd, out_fsp->fd, n, read_fn, write_fn);
449 /*******************************************************************
450 A vfs_readdir wrapper which just returns the file name.
451 ********************************************************************/
453 char *vfs_readdirname(connection_struct *conn, void *p)
455 struct dirent *ptr;
456 char *dname;
458 if (!p)
459 return(NULL);
461 ptr = (struct dirent *)conn->vfs_ops.readdir(conn,p);
462 if (!ptr)
463 return(NULL);
465 dname = ptr->d_name;
467 #ifdef NEXT2
468 if (telldir(p) < 0)
469 return(NULL);
470 #endif
472 #ifdef HAVE_BROKEN_READDIR
473 /* using /usr/ucb/cc is BAD */
474 dname = dname - 2;
475 #endif
478 static pstring buf;
479 memcpy(buf, dname, NAMLEN(ptr)+1);
480 unix_to_dos(buf);
481 dname = buf;
484 return(dname);
487 /* VFS options not quite working yet */
489 #if 0
491 /***************************************************************************
492 handle the interpretation of the vfs option parameter
493 *************************************************************************/
494 static BOOL handle_vfs_option(char *pszParmValue, char **ptr)
496 struct vfs_options *new_option, **options = (struct vfs_options **)ptr;
497 int i;
499 /* Create new vfs option */
501 new_option = (struct vfs_options *)malloc(sizeof(*new_option));
502 if (new_option == NULL) {
503 return False;
506 ZERO_STRUCTP(new_option);
508 /* Get name and value */
510 new_option->name = strtok(pszParmValue, "=");
512 if (new_option->name == NULL) {
513 return False;
516 while(isspace(*new_option->name)) {
517 new_option->name++;
520 for (i = strlen(new_option->name); i > 0; i--) {
521 if (!isspace(new_option->name[i - 1])) break;
524 new_option->name[i] = '\0';
525 new_option->name = strdup(new_option->name);
527 new_option->value = strtok(NULL, "=");
529 if (new_option->value != NULL) {
531 while(isspace(*new_option->value)) {
532 new_option->value++;
535 for (i = strlen(new_option->value); i > 0; i--) {
536 if (!isspace(new_option->value[i - 1])) break;
539 new_option->value[i] = '\0';
540 new_option->value = strdup(new_option->value);
543 /* Add to list */
545 DLIST_ADD(*options, new_option);
547 return True;
550 #endif
553 /*******************************************************************
554 A wrapper for vfs_chdir().
555 ********************************************************************/
557 int vfs_ChDir(connection_struct *conn, const char *path)
559 int res;
560 static pstring LastDir="";
562 if (strcsequal(path,"."))
563 return(0);
565 if (*path == '/' && strcsequal(LastDir,path))
566 return(0);
568 DEBUG(3,("vfs_ChDir to %s\n",path));
570 res = vfs_chdir(conn,path);
571 if (!res)
572 pstrcpy(LastDir,path);
573 return(res);
576 /* number of list structures for a caching GetWd function. */
577 #define MAX_GETWDCACHE (50)
579 struct {
580 SMB_DEV_T dev; /* These *must* be compatible with the types returned in a stat() call. */
581 SMB_INO_T inode; /* These *must* be compatible with the types returned in a stat() call. */
582 char *dos_path; /* The pathname in DOS format. */
583 BOOL valid;
584 } ino_list[MAX_GETWDCACHE];
586 extern BOOL use_getwd_cache;
588 /****************************************************************************
589 Prompte a ptr (to make it recently used)
590 ****************************************************************************/
592 static void array_promote(char *array,int elsize,int element)
594 char *p;
595 if (element == 0)
596 return;
598 p = (char *)malloc(elsize);
600 if (!p) {
601 DEBUG(5,("array_promote: malloc fail\n"));
602 return;
605 memcpy(p,array + element * elsize, elsize);
606 memmove(array + elsize,array,elsize*element);
607 memcpy(array,p,elsize);
608 SAFE_FREE(p);
611 /*******************************************************************
612 Return the absolute current directory path - given a UNIX pathname.
613 Note that this path is returned in DOS format, not UNIX
614 format. Note this can be called with conn == NULL.
615 ********************************************************************/
617 char *vfs_GetWd(connection_struct *conn, char *path)
619 pstring s;
620 static BOOL getwd_cache_init = False;
621 SMB_STRUCT_STAT st, st2;
622 int i;
624 *s = 0;
626 if (!use_getwd_cache)
627 return(vfs_getwd(conn,path));
629 /* init the cache */
630 if (!getwd_cache_init) {
631 getwd_cache_init = True;
632 for (i=0;i<MAX_GETWDCACHE;i++) {
633 string_set(&ino_list[i].dos_path,"");
634 ino_list[i].valid = False;
638 /* Get the inode of the current directory, if this doesn't work we're
639 in trouble :-) */
641 if (vfs_stat(conn, ".",&st) == -1) {
642 DEBUG(0,("Very strange, couldn't stat \".\" path=%s\n", path));
643 return(vfs_getwd(conn,path));
647 for (i=0; i<MAX_GETWDCACHE; i++) {
648 if (ino_list[i].valid) {
650 /* If we have found an entry with a matching inode and dev number
651 then find the inode number for the directory in the cached string.
652 If this agrees with that returned by the stat for the current
653 directory then all is o.k. (but make sure it is a directory all
654 the same...) */
656 if (st.st_ino == ino_list[i].inode && st.st_dev == ino_list[i].dev) {
657 if (vfs_stat(conn,ino_list[i].dos_path,&st2) == 0) {
658 if (st.st_ino == st2.st_ino && st.st_dev == st2.st_dev &&
659 (st2.st_mode & S_IFMT) == S_IFDIR) {
660 pstrcpy (path, ino_list[i].dos_path);
662 /* promote it for future use */
663 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
664 return (path);
666 } else {
667 /* If the inode is different then something's changed,
668 scrub the entry and start from scratch. */
669 ino_list[i].valid = False;
676 /* We don't have the information to hand so rely on traditional methods.
677 The very slow getcwd, which spawns a process on some systems, or the
678 not quite so bad getwd. */
680 if (!vfs_getwd(conn,s)) {
681 DEBUG(0,("vfs_GetWd: vfs_getwd call failed, errno %s\n",strerror(errno)));
682 return (NULL);
685 pstrcpy(path,s);
687 DEBUG(5,("vfs_GetWd %s, inode %.0f, dev %.0f\n",s,(double)st.st_ino,(double)st.st_dev));
689 /* add it to the cache */
690 i = MAX_GETWDCACHE - 1;
691 string_set(&ino_list[i].dos_path,s);
692 ino_list[i].dev = st.st_dev;
693 ino_list[i].inode = st.st_ino;
694 ino_list[i].valid = True;
696 /* put it at the top of the list */
697 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
699 return (path);
702 /*******************************************************************
703 Reduce a file name, removing .. elements and checking that
704 it is below dir in the heirachy. This uses vfs_GetWd() and so must be run
705 on the system that has the referenced file system.
706 Widelinks are allowed if widelinks is true.
707 ********************************************************************/
709 BOOL reduce_name(connection_struct *conn, char *s,char *dir,BOOL widelinks)
711 #ifndef REDUCE_PATHS
712 return True;
713 #else
714 pstring dir2;
715 pstring wd;
716 pstring base_name;
717 pstring newname;
718 char *p=NULL;
719 BOOL relative = (*s != '/');
721 *dir2 = *wd = *base_name = *newname = 0;
723 if (widelinks) {
724 unix_clean_name(s);
725 /* can't have a leading .. */
726 if (strncmp(s,"..",2) == 0 && (s[2]==0 || s[2]=='/')) {
727 DEBUG(3,("Illegal file name? (%s)\n",s));
728 return(False);
731 if (strlen(s) == 0)
732 pstrcpy(s,"./");
734 return(True);
737 DEBUG(3,("reduce_name [%s] [%s]\n",s,dir));
739 /* remove any double slashes */
740 all_string_sub(s,"//","/",0);
742 pstrcpy(base_name,s);
743 p = strrchr(base_name,'/');
745 if (!p)
746 return(True);
748 if (!vfs_GetWd(conn,wd)) {
749 DEBUG(0,("couldn't vfs_GetWd for %s %s\n",s,dir));
750 return(False);
753 if (vfs_ChDir(conn,dir) != 0) {
754 DEBUG(0,("couldn't vfs_ChDir to %s\n",dir));
755 return(False);
758 if (!vfs_GetWd(conn,dir2)) {
759 DEBUG(0,("couldn't vfs_GetWd for %s\n",dir));
760 vfs_ChDir(conn,wd);
761 return(False);
764 if (p && (p != base_name)) {
765 *p = 0;
766 if (strcmp(p+1,".")==0)
767 p[1]=0;
768 if (strcmp(p+1,"..")==0)
769 *p = '/';
772 if (vfs_ChDir(conn,base_name) != 0) {
773 vfs_ChDir(conn,wd);
774 DEBUG(3,("couldn't vfs_ChDir for %s %s basename=%s\n",s,dir,base_name));
775 return(False);
778 if (!vfs_GetWd(conn,newname)) {
779 vfs_ChDir(conn,wd);
780 DEBUG(2,("couldn't get vfs_GetWd for %s %s\n",s,dir2));
781 return(False);
784 if (p && (p != base_name)) {
785 pstrcat(newname,"/");
786 pstrcat(newname,p+1);
790 size_t l = strlen(dir2);
791 if (dir2[l-1] == '/')
792 l--;
794 if (strncmp(newname,dir2,l) != 0) {
795 vfs_ChDir(conn,wd);
796 DEBUG(2,("Bad access attempt? s=%s dir=%s newname=%s l=%d\n",s,dir2,newname,(int)l));
797 return(False);
800 if (relative) {
801 if (newname[l] == '/')
802 pstrcpy(s,newname + l + 1);
803 else
804 pstrcpy(s,newname+l);
805 } else
806 pstrcpy(s,newname);
809 vfs_ChDir(conn,wd);
811 if (strlen(s) == 0)
812 pstrcpy(s,"./");
814 DEBUG(3,("reduced to %s\n",s));
815 return(True);
816 #endif