2 Unix SMB/Netbios implementation.
4 VFS initialisation and support functions
5 Copyright (C) Tim Potter 1999
6 Copyright (C) Alexander Bokovoy 2002
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 This work was sponsored by Optifacio Software Services, Inc.
27 /* Some structures to help us initialise the vfs operations table */
35 Opaque (final) vfs operations. This is a combination of first-met opaque vfs operations
36 across all currently processed modules. */
38 static vfs_op_tuple vfs_opaque_ops[SMB_VFS_OP_LAST];
40 /* Default vfs hooks. WARNING: The order of these initialisers is
41 very important. They must be in the same order as defined in
42 vfs.h. Change at your own peril. */
44 static struct vfs_ops default_vfs_ops = {
48 vfswrap_dummy_connect,
49 vfswrap_dummy_disconnect,
52 /* Directory operations */
93 /* POSIX ACL operations. */
94 #if defined(HAVE_NO_ACLS)
101 vfswrap_sys_acl_get_entry,
102 vfswrap_sys_acl_get_tag_type,
103 vfswrap_sys_acl_get_permset,
104 vfswrap_sys_acl_get_qualifier,
105 vfswrap_sys_acl_get_file,
106 vfswrap_sys_acl_get_fd,
107 vfswrap_sys_acl_clear_perms,
108 vfswrap_sys_acl_add_perm,
109 vfswrap_sys_acl_to_text,
110 vfswrap_sys_acl_init,
111 vfswrap_sys_acl_create_entry,
112 vfswrap_sys_acl_set_tag_type,
113 vfswrap_sys_acl_set_qualifier,
114 vfswrap_sys_acl_set_permset,
115 vfswrap_sys_acl_valid,
116 vfswrap_sys_acl_set_file,
117 vfswrap_sys_acl_set_fd,
118 vfswrap_sys_acl_delete_def_file,
119 vfswrap_sys_acl_get_perm,
120 vfswrap_sys_acl_free_text,
121 vfswrap_sys_acl_free_acl,
122 vfswrap_sys_acl_free_qualifier
125 /****************************************************************************
126 initialise default vfs hooks
127 ****************************************************************************/
129 static void vfs_init_default(connection_struct *conn)
131 DEBUG(3, ("Initialising default vfs hooks\n"));
133 memcpy(&conn->vfs_ops, &default_vfs_ops, sizeof(struct vfs_ops));
134 conn->vfs_private = NULL;
137 /****************************************************************************
138 initialise custom vfs hooks
139 ****************************************************************************/
141 static BOOL vfs_init_custom(connection_struct *conn, const char *vfs_object)
143 int vfs_version = -1;
144 vfs_op_tuple *ops, *(*init_fptr)(int *, const struct vfs_ops *, struct smb_vfs_handle_struct *);
147 DEBUG(3, ("Initialising custom vfs hooks from %s\n", vfs_object));
149 /* Open object file */
151 if ((conn->vfs_private->handle = sys_dlopen(vfs_object, RTLD_NOW)) == NULL) {
152 DEBUG(0, ("Error opening %s: %s\n", vfs_object, sys_dlerror()));
156 /* Get handle on vfs_init() symbol */
158 init_fptr = (vfs_op_tuple *(*)(int *, const struct vfs_ops *, struct smb_vfs_handle_struct *))sys_dlsym(conn->vfs_private->handle, "vfs_init");
160 if (init_fptr == NULL) {
161 DEBUG(0, ("No vfs_init() symbol found in %s\n", vfs_object));
165 /* Initialise vfs_ops structure */
167 if ((ops = init_fptr(&vfs_version, &conn->vfs_ops, conn->vfs_private)) == NULL) {
168 DEBUG(0, ("vfs_init() function from %s failed\n", vfs_object));
172 if ((vfs_version < SMB_VFS_INTERFACE_CASCADED)) {
173 DEBUG(0, ("vfs_init() returned wrong interface version info (was %d, should be no less than %d)\n",
174 vfs_version, SMB_VFS_INTERFACE_VERSION ));
178 if ((vfs_version < SMB_VFS_INTERFACE_VERSION)) {
179 DEBUG(0, ("Warning: vfs_init() states that module confirms interface version #%d, current interface version is #%d.\n\
180 Proceeding in compatibility mode, new operations (since version #%d) will fallback to default ones.\n",
181 vfs_version, SMB_VFS_INTERFACE_VERSION, vfs_version ));
185 for(i=0; ops[i].op != NULL; i++) {
186 DEBUG(3, ("Checking operation #%d (type %d, layer %d)\n", i, ops[i].type, ops[i].layer));
187 if(ops[i].layer == SMB_VFS_LAYER_OPAQUE) {
188 /* Check whether this operation was already made opaque by different module */
189 if(vfs_opaque_ops[ops[i].type].op == ((void**)&default_vfs_ops)[ops[i].type]) {
190 /* No, it isn't overloaded yet. Overload. */
191 DEBUG(3, ("Making operation type %d opaque [module %s]\n", ops[i].type, vfs_object));
192 vfs_opaque_ops[ops[i].type] = ops[i];
195 /* Change current VFS disposition*/
196 DEBUG(3, ("Accepting operation type %d from module %s\n", ops[i].type, vfs_object));
197 ((void**)&conn->vfs_ops)[ops[i].type] = ops[i].op;
203 /*****************************************************************
205 ******************************************************************/
207 BOOL smbd_vfs_init(connection_struct *conn)
209 char **vfs_objects, *vfsobj, *vfs_module, *vfs_path;
211 struct smb_vfs_handle_struct *handle;
213 /* Normal share - initialise with disk access functions */
214 vfs_init_default(conn);
216 /* Override VFS functions if 'vfs object' was specified*/
217 if (*lp_vfsobj(SNUM(conn))) {
219 for(i=0; i<SMB_VFS_OP_LAST; i++) {
220 vfs_opaque_ops[i].op = ((void**)&default_vfs_ops)[i];
221 vfs_opaque_ops[i].type = i;
222 vfs_opaque_ops[i].layer = SMB_VFS_LAYER_OPAQUE;
224 if (string_set(&vfsobj, lp_vfsobj(SNUM(conn)))) {
225 /* Parse passed modules specification to array of modules */
226 set_first_token(vfsobj);
227 /* We are using default separators: ' \t\r\n' */
228 vfs_objects = toktocliplist(&nobj, NULL);
230 vfs_path = lp_vfs_path(SNUM(conn));
231 conn->vfs_private = NULL;
232 for(i=nobj-1; i>=0; i--) {
233 handle = (struct smb_vfs_handle_struct *) smb_xmalloc(sizeof(smb_vfs_handle_struct));
234 /* Loadable object file */
235 handle->handle = NULL;
236 DLIST_ADD(conn->vfs_private, handle)
239 asprintf(&vfs_module, "%s/%s", vfs_path, vfs_objects[i]);
241 asprintf(&vfs_module, "%s", vfs_objects[i]);
243 if (!vfs_init_custom(conn, vfs_module)) {
244 DEBUG(0, ("smbd_vfs_init: vfs_init_custom failed for %s\n", vfs_module));
245 string_free(&vfsobj);
246 SAFE_FREE(vfs_module);
249 SAFE_FREE(vfs_module);
252 string_free(&vfsobj);
259 /*******************************************************************
260 Create vfs_ops reflecting current vfs_opaque_ops
261 *******************************************************************/
262 struct vfs_ops *smb_vfs_get_opaque_ops(void)
267 ops = smb_xmalloc(sizeof(struct vfs_ops));
269 for(i=0; i<SMB_VFS_OP_LAST; i++) {
270 ((void**)ops)[i] = vfs_opaque_ops[i].op;
275 /*******************************************************************
276 Check if directory exists.
277 ********************************************************************/
279 BOOL vfs_directory_exist(connection_struct *conn, const char *dname, SMB_STRUCT_STAT *st)
287 if (vfs_stat(conn,dname,st) != 0)
290 ret = S_ISDIR(st->st_mode);
297 /*******************************************************************
299 ********************************************************************/
300 static char *vfs_getwd(connection_struct *conn, char *path)
302 return conn->vfs_ops.getwd(conn,path);
305 /*******************************************************************
307 ********************************************************************/
309 int vfs_mkdir(connection_struct *conn, const char *name, mode_t mode)
312 SMB_STRUCT_STAT sbuf;
314 if(!(ret=conn->vfs_ops.mkdir(conn,name,mode))) {
316 * Check if high bits should have been set,
317 * then (if bits are missing): add them.
318 * Consider bits automagically set by UNIX, i.e. SGID bit from parent dir.
320 if(mode & ~(S_IRWXU|S_IRWXG|S_IRWXO) &&
321 !vfs_stat(conn,name,&sbuf) && (mode & ~sbuf.st_mode))
322 vfs_chmod(conn,name,sbuf.st_mode | (mode & ~sbuf.st_mode));
327 /*******************************************************************
328 Check if an object exists in the vfs.
329 ********************************************************************/
331 BOOL vfs_object_exist(connection_struct *conn,const char *fname,SMB_STRUCT_STAT *sbuf)
340 if (vfs_stat(conn,fname,sbuf) == -1)
345 /*******************************************************************
346 Check if a file exists in the vfs.
347 ********************************************************************/
349 BOOL vfs_file_exist(connection_struct *conn, const char *fname,SMB_STRUCT_STAT *sbuf)
358 if (vfs_stat(conn,fname,sbuf) == -1)
360 return(S_ISREG(sbuf->st_mode));
363 /****************************************************************************
364 Read data from fsp on the vfs. (note: EINTR re-read differs from vfs_write_data)
365 ****************************************************************************/
367 ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count)
371 while (total < byte_count)
373 ssize_t ret = fsp->conn->vfs_ops.read(fsp, fsp->fd, buf + total,
376 if (ret == 0) return total;
385 return (ssize_t)total;
388 /****************************************************************************
389 Write data to a fd on the vfs.
390 ****************************************************************************/
392 ssize_t vfs_write_data(files_struct *fsp,const char *buffer,size_t N)
398 ret = fsp->conn->vfs_ops.write(fsp,fsp->fd,buffer + total,N - total);
407 return (ssize_t)total;
410 /****************************************************************************
411 An allocate file space call using the vfs interface.
412 Allocates space for a file from a filedescriptor.
413 Returns 0 on success, -1 on failure.
414 ****************************************************************************/
416 int vfs_allocate_file_space(files_struct *fsp, SMB_OFF_T len)
420 connection_struct *conn = fsp->conn;
421 struct vfs_ops *vfs_ops = &conn->vfs_ops;
422 SMB_OFF_T space_avail;
423 SMB_BIG_UINT bsize,dfree,dsize;
425 release_level_2_oplocks_on_change(fsp);
428 * Actually try and commit the space on disk....
431 DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", fsp->fsp_name, (double)len ));
433 ret = vfs_fstat(fsp,fsp->fd,&st);
437 if (len == st.st_size)
440 if (len < st.st_size) {
441 /* Shrink - use ftruncate. */
443 DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
444 fsp->fsp_name, (double)st.st_size ));
446 flush_write_cache(fsp, SIZECHANGE_FLUSH);
447 if ((ret = vfs_ops->ftruncate(fsp, fsp->fd, len)) != -1) {
448 set_filelen_write_cache(fsp, len);
453 /* Grow - we need to test if we have enough space. */
455 if (!lp_strict_allocate(SNUM(fsp->conn)))
459 len /= 1024; /* Len is now number of 1k blocks needed. */
460 space_avail = (SMB_OFF_T)conn->vfs_ops.disk_free(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize);
462 DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %lu, space avail = %lu\n",
463 fsp->fsp_name, (double)st.st_size, (unsigned long)len, (unsigned long)space_avail ));
465 if (len > space_avail) {
473 /****************************************************************************
474 A vfs set_filelen call.
475 set the length of a file from a filedescriptor.
476 Returns 0 on success, -1 on failure.
477 ****************************************************************************/
479 int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
483 release_level_2_oplocks_on_change(fsp);
484 DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len));
485 flush_write_cache(fsp, SIZECHANGE_FLUSH);
486 if ((ret = fsp->conn->vfs_ops.ftruncate(fsp, fsp->fd, len)) != -1)
487 set_filelen_write_cache(fsp, len);
492 /****************************************************************************
493 Transfer some data (n bytes) between two file_struct's.
494 ****************************************************************************/
496 static files_struct *in_fsp;
497 static files_struct *out_fsp;
499 static ssize_t read_fn(int fd, void *buf, size_t len)
501 return in_fsp->conn->vfs_ops.read(in_fsp, fd, buf, len);
504 static ssize_t write_fn(int fd, const void *buf, size_t len)
506 return out_fsp->conn->vfs_ops.write(out_fsp, fd, buf, len);
509 SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n)
514 return transfer_file_internal(in_fsp->fd, out_fsp->fd, n, read_fn, write_fn);
517 /*******************************************************************
518 A vfs_readdir wrapper which just returns the file name.
519 ********************************************************************/
521 char *vfs_readdirname(connection_struct *conn, void *p)
529 ptr = (struct dirent *)conn->vfs_ops.readdir(conn,p);
540 #ifdef HAVE_BROKEN_READDIR
541 /* using /usr/ucb/cc is BAD */
548 /* VFS options not quite working yet */
552 /***************************************************************************
553 handle the interpretation of the vfs option parameter
554 *************************************************************************/
555 static BOOL handle_vfs_option(char *pszParmValue, char **ptr)
557 struct vfs_options *new_option, **options = (struct vfs_options **)ptr;
560 /* Create new vfs option */
562 new_option = (struct vfs_options *)malloc(sizeof(*new_option));
563 if (new_option == NULL) {
567 ZERO_STRUCTP(new_option);
569 /* Get name and value */
571 new_option->name = strtok(pszParmValue, "=");
573 if (new_option->name == NULL) {
577 while(isspace(*new_option->name)) {
581 for (i = strlen(new_option->name); i > 0; i--) {
582 if (!isspace(new_option->name[i - 1])) break;
585 new_option->name[i] = '\0';
586 new_option->name = strdup(new_option->name);
588 new_option->value = strtok(NULL, "=");
590 if (new_option->value != NULL) {
592 while(isspace(*new_option->value)) {
596 for (i = strlen(new_option->value); i > 0; i--) {
597 if (!isspace(new_option->value[i - 1])) break;
600 new_option->value[i] = '\0';
601 new_option->value = strdup(new_option->value);
606 DLIST_ADD(*options, new_option);
614 /*******************************************************************
615 A wrapper for vfs_chdir().
616 ********************************************************************/
618 int vfs_ChDir(connection_struct *conn, char *path)
621 static pstring LastDir="";
623 if (strcsequal(path,"."))
626 if (*path == '/' && strcsequal(LastDir,path))
629 DEBUG(3,("vfs_ChDir to %s\n",path));
631 res = vfs_chdir(conn,path);
633 pstrcpy(LastDir,path);
637 /* number of list structures for a caching GetWd function. */
638 #define MAX_GETWDCACHE (50)
641 SMB_DEV_T dev; /* These *must* be compatible with the types returned in a stat() call. */
642 SMB_INO_T inode; /* These *must* be compatible with the types returned in a stat() call. */
643 char *dos_path; /* The pathname in DOS format. */
645 } ino_list[MAX_GETWDCACHE];
647 extern BOOL use_getwd_cache;
649 /****************************************************************************
650 Prompte a ptr (to make it recently used)
651 ****************************************************************************/
653 static void array_promote(char *array,int elsize,int element)
659 p = (char *)malloc(elsize);
662 DEBUG(5,("array_promote: malloc fail\n"));
666 memcpy(p,array + element * elsize, elsize);
667 memmove(array + elsize,array,elsize*element);
668 memcpy(array,p,elsize);
672 /*******************************************************************
673 Return the absolute current directory path - given a UNIX pathname.
674 Note that this path is returned in DOS format, not UNIX
675 format. Note this can be called with conn == NULL.
676 ********************************************************************/
678 char *vfs_GetWd(connection_struct *conn, char *path)
681 static BOOL getwd_cache_init = False;
682 SMB_STRUCT_STAT st, st2;
687 if (!use_getwd_cache)
688 return(vfs_getwd(conn,path));
691 if (!getwd_cache_init) {
692 getwd_cache_init = True;
693 for (i=0;i<MAX_GETWDCACHE;i++) {
694 string_set(&ino_list[i].dos_path,"");
695 ino_list[i].valid = False;
699 /* Get the inode of the current directory, if this doesn't work we're
702 if (vfs_stat(conn, ".",&st) == -1) {
703 DEBUG(0,("Very strange, couldn't stat \".\" path=%s\n", path));
704 return(vfs_getwd(conn,path));
708 for (i=0; i<MAX_GETWDCACHE; i++) {
709 if (ino_list[i].valid) {
711 /* If we have found an entry with a matching inode and dev number
712 then find the inode number for the directory in the cached string.
713 If this agrees with that returned by the stat for the current
714 directory then all is o.k. (but make sure it is a directory all
717 if (st.st_ino == ino_list[i].inode && st.st_dev == ino_list[i].dev) {
718 if (vfs_stat(conn,ino_list[i].dos_path,&st2) == 0) {
719 if (st.st_ino == st2.st_ino && st.st_dev == st2.st_dev &&
720 (st2.st_mode & S_IFMT) == S_IFDIR) {
721 pstrcpy (path, ino_list[i].dos_path);
723 /* promote it for future use */
724 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
727 /* If the inode is different then something's changed,
728 scrub the entry and start from scratch. */
729 ino_list[i].valid = False;
736 /* We don't have the information to hand so rely on traditional methods.
737 The very slow getcwd, which spawns a process on some systems, or the
738 not quite so bad getwd. */
740 if (!vfs_getwd(conn,s)) {
741 DEBUG(0,("vfs_GetWd: vfs_getwd call failed, errno %s\n",strerror(errno)));
747 DEBUG(5,("vfs_GetWd %s, inode %.0f, dev %.0f\n",s,(double)st.st_ino,(double)st.st_dev));
749 /* add it to the cache */
750 i = MAX_GETWDCACHE - 1;
751 string_set(&ino_list[i].dos_path,s);
752 ino_list[i].dev = st.st_dev;
753 ino_list[i].inode = st.st_ino;
754 ino_list[i].valid = True;
756 /* put it at the top of the list */
757 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
762 /*******************************************************************
763 Reduce a file name, removing .. elements and checking that
764 it is below dir in the heirachy. This uses vfs_GetWd() and so must be run
765 on the system that has the referenced file system.
766 Widelinks are allowed if widelinks is true.
767 ********************************************************************/
769 BOOL reduce_name(connection_struct *conn, char *s,char *dir,BOOL widelinks)
779 BOOL relative = (*s != '/');
781 *dir2 = *wd = *base_name = *newname = 0;
785 /* can't have a leading .. */
786 if (strncmp(s,"..",2) == 0 && (s[2]==0 || s[2]=='/')) {
787 DEBUG(3,("Illegal file name? (%s)\n",s));
797 DEBUG(3,("reduce_name [%s] [%s]\n",s,dir));
799 /* remove any double slashes */
800 all_string_sub(s,"//","/",0);
802 pstrcpy(base_name,s);
803 p = strrchr_m(base_name,'/');
808 if (!vfs_GetWd(conn,wd)) {
809 DEBUG(0,("couldn't vfs_GetWd for %s %s\n",s,dir));
813 if (vfs_ChDir(conn,dir) != 0) {
814 DEBUG(0,("couldn't vfs_ChDir to %s\n",dir));
818 if (!vfs_GetWd(conn,dir2)) {
819 DEBUG(0,("couldn't vfs_GetWd for %s\n",dir));
824 if (p && (p != base_name)) {
826 if (strcmp(p+1,".")==0)
828 if (strcmp(p+1,"..")==0)
832 if (vfs_ChDir(conn,base_name) != 0) {
834 DEBUG(3,("couldn't vfs_ChDir for %s %s basename=%s\n",s,dir,base_name));
838 if (!vfs_GetWd(conn,newname)) {
840 DEBUG(2,("couldn't get vfs_GetWd for %s %s\n",s,dir2));
844 if (p && (p != base_name)) {
845 pstrcat(newname,"/");
846 pstrcat(newname,p+1);
850 size_t l = strlen(dir2);
851 if (dir2[l-1] == '/')
854 if (strncmp(newname,dir2,l) != 0) {
856 DEBUG(2,("Bad access attempt? s=%s dir=%s newname=%s l=%d\n",s,dir2,newname,(int)l));
861 if (newname[l] == '/')
862 pstrcpy(s,newname + l + 1);
864 pstrcpy(s,newname+l);
874 DEBUG(3,("reduced to %s\n",s));