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.
28 #define DBGC_CLASS DBGC_VFS
30 struct vfs_init_function_entry {
32 vfs_op_tuple *vfs_op_tuples;
33 struct vfs_init_function_entry *prev, *next;
36 static struct vfs_init_function_entry *backends = NULL;
38 /* Some structures to help us initialise the vfs operations table */
45 /* Default vfs hooks. WARNING: The order of these initialisers is
46 very important. They must be in the same order as defined in
47 vfs.h. Change at your own peril. */
49 static struct vfs_ops default_vfs = {
54 vfswrap_dummy_connect,
55 vfswrap_dummy_disconnect,
60 /* Directory operations */
102 /* POSIX ACL operations. */
106 vfswrap_sys_acl_get_entry,
107 vfswrap_sys_acl_get_tag_type,
108 vfswrap_sys_acl_get_permset,
109 vfswrap_sys_acl_get_qualifier,
110 vfswrap_sys_acl_get_file,
111 vfswrap_sys_acl_get_fd,
112 vfswrap_sys_acl_clear_perms,
113 vfswrap_sys_acl_add_perm,
114 vfswrap_sys_acl_to_text,
115 vfswrap_sys_acl_init,
116 vfswrap_sys_acl_create_entry,
117 vfswrap_sys_acl_set_tag_type,
118 vfswrap_sys_acl_set_qualifier,
119 vfswrap_sys_acl_set_permset,
120 vfswrap_sys_acl_valid,
121 vfswrap_sys_acl_set_file,
122 vfswrap_sys_acl_set_fd,
123 vfswrap_sys_acl_delete_def_file,
124 vfswrap_sys_acl_get_perm,
125 vfswrap_sys_acl_free_text,
126 vfswrap_sys_acl_free_acl,
127 vfswrap_sys_acl_free_qualifier
131 /****************************************************************************
132 maintain the list of available backends
133 ****************************************************************************/
135 static struct vfs_init_function_entry *vfs_find_backend_entry(const char *name)
137 struct vfs_init_function_entry *entry = backends;
140 if (strcmp(entry->name, name)==0) return entry;
147 NTSTATUS smb_register_vfs(int version, const char *name, vfs_op_tuple *vfs_op_tuples)
149 struct vfs_init_function_entry *entry = backends;
151 if ((version != SMB_VFS_INTERFACE_VERSION)) {
152 DEBUG(0, ("Failed to register vfs module.\n"
153 "The module was compiled against SMB_VFS_INTERFACE_VERSION %d,\n"
154 "current SMB_VFS_INTERFACE_VERSION is %d.\n"
155 "Please recompile against the current Samba Version!\n",
156 version, SMB_VFS_INTERFACE_VERSION));
157 return NT_STATUS_OBJECT_TYPE_MISMATCH;
160 if (!name || !name[0] || !vfs_op_tuples) {
161 DEBUG(0,("smb_register_vfs() called with NULL pointer or empty name!\n"));
162 return NT_STATUS_INVALID_PARAMETER;
165 if (vfs_find_backend_entry(name)) {
166 DEBUG(0,("VFS module %s already loaded!\n", name));
167 return NT_STATUS_OBJECT_NAME_COLLISION;
170 entry = smb_xmalloc(sizeof(struct vfs_init_function_entry));
171 entry->name = smb_xstrdup(name);
172 entry->vfs_op_tuples = vfs_op_tuples;
174 DLIST_ADD(backends, entry);
175 DEBUG(5, ("Successfully added vfs backend '%s'\n", name));
179 /****************************************************************************
180 initialise default vfs hooks
181 ****************************************************************************/
183 static void vfs_init_default(connection_struct *conn)
185 DEBUG(3, ("Initialising default vfs hooks\n"));
187 memcpy(&conn->vfs.ops, &default_vfs.ops, sizeof(default_vfs.ops));
188 memcpy(&conn->vfs_opaque.ops, &default_vfs.ops, sizeof(default_vfs.ops));
191 /****************************************************************************
192 initialise custom vfs hooks
193 ****************************************************************************/
195 BOOL vfs_init_custom(connection_struct *conn, const char *vfs_object)
198 char *module_name = NULL;
199 char *module_param = NULL, *p;
201 vfs_handle_struct *handle;
202 struct vfs_init_function_entry *entry;
204 if (!conn||!vfs_object||!vfs_object[0]) {
205 DEBUG(0,("vfs_init_custon() called with NULL pointer or emtpy vfs_object!\n"));
209 if(!backends) static_init_vfs;
211 DEBUG(3, ("Initialising custom vfs hooks from [%s]\n", vfs_object));
213 module_name = smb_xstrdup(vfs_object);
215 p = strchr(module_name, ':');
220 trim_string(module_param, " ", " ");
223 trim_string(module_name, " ", " ");
225 /* First, try to load the module with the new module system */
226 if((entry = vfs_find_backend_entry(module_name)) ||
227 (NT_STATUS_IS_OK(smb_probe_module("vfs", module_name)) &&
228 (entry = vfs_find_backend_entry(module_name)))) {
230 DEBUGADD(5,("Successfully loaded vfs module [%s] with the new modules system\n", vfs_object));
232 if ((ops = entry->vfs_op_tuples) == NULL) {
233 DEBUG(0, ("entry->vfs_op_tuples==NULL for [%s] failed\n", vfs_object));
234 SAFE_FREE(module_name);
238 DEBUG(0,("Can't find a vfs module [%s]\n",vfs_object));
239 SAFE_FREE(module_name);
243 handle = (vfs_handle_struct *)talloc_zero(conn->mem_ctx,sizeof(vfs_handle_struct));
245 DEBUG(0,("talloc_zero() failed!\n"));
246 SAFE_FREE(module_name);
249 memcpy(&handle->vfs_next, &conn->vfs, sizeof(struct vfs_ops));
252 handle->param = talloc_strdup(conn->mem_ctx, module_param);
254 DLIST_ADD(conn->vfs_handles, handle);
256 for(i=0; ops[i].op != NULL; i++) {
257 DEBUG(5, ("Checking operation #%d (type %d, layer %d)\n", i, ops[i].type, ops[i].layer));
258 if(ops[i].layer == SMB_VFS_LAYER_OPAQUE) {
259 /* Check whether this operation was already made opaque by different module */
260 if(((void**)&conn->vfs_opaque.ops)[ops[i].type] == ((void**)&default_vfs.ops)[ops[i].type]) {
261 /* No, it isn't overloaded yet. Overload. */
262 DEBUGADD(5, ("Making operation type %d opaque [module %s]\n", ops[i].type, vfs_object));
263 ((void**)&conn->vfs_opaque.ops)[ops[i].type] = ops[i].op;
264 ((vfs_handle_struct **)&conn->vfs_opaque.handles)[ops[i].type] = handle;
267 /* Change current VFS disposition*/
268 DEBUGADD(5, ("Accepting operation type %d from module %s\n", ops[i].type, vfs_object));
269 ((void**)&conn->vfs.ops)[ops[i].type] = ops[i].op;
270 ((vfs_handle_struct **)&conn->vfs.handles)[ops[i].type] = handle;
273 SAFE_FREE(module_name);
277 /*****************************************************************
279 ******************************************************************/
281 BOOL smbd_vfs_init(connection_struct *conn)
283 const char **vfs_objects;
287 /* Normal share - initialise with disk access functions */
288 vfs_init_default(conn);
289 vfs_objects = lp_vfs_objects(SNUM(conn));
291 /* Override VFS functions if 'vfs object' was not specified*/
292 if (!vfs_objects || !vfs_objects[0])
295 for (i=0; vfs_objects[i] ;) {
299 for (j=i-1; j >= 0; j--) {
300 if (!vfs_init_custom(conn, vfs_objects[j])) {
301 DEBUG(0, ("smbd_vfs_init: vfs_init_custom failed for %s\n", vfs_objects[j]));
308 /*******************************************************************
309 Check if directory exists.
310 ********************************************************************/
312 BOOL vfs_directory_exist(connection_struct *conn, const char *dname, SMB_STRUCT_STAT *st)
320 if (SMB_VFS_STAT(conn,dname,st) != 0)
323 ret = S_ISDIR(st->st_mode);
330 /*******************************************************************
332 ********************************************************************/
334 int vfs_MkDir(connection_struct *conn, const char *name, mode_t mode)
337 SMB_STRUCT_STAT sbuf;
339 if(!(ret=SMB_VFS_MKDIR(conn, name, mode))) {
341 inherit_access_acl(conn, name, mode);
344 * Check if high bits should have been set,
345 * then (if bits are missing): add them.
346 * Consider bits automagically set by UNIX, i.e. SGID bit from parent dir.
348 if(mode & ~(S_IRWXU|S_IRWXG|S_IRWXO) &&
349 !SMB_VFS_STAT(conn,name,&sbuf) && (mode & ~sbuf.st_mode))
350 SMB_VFS_CHMOD(conn,name,sbuf.st_mode | (mode & ~sbuf.st_mode));
355 /*******************************************************************
356 Check if an object exists in the vfs.
357 ********************************************************************/
359 BOOL vfs_object_exist(connection_struct *conn,const char *fname,SMB_STRUCT_STAT *sbuf)
368 if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
373 /*******************************************************************
374 Check if a file exists in the vfs.
375 ********************************************************************/
377 BOOL vfs_file_exist(connection_struct *conn, const char *fname,SMB_STRUCT_STAT *sbuf)
386 if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
388 return(S_ISREG(sbuf->st_mode));
391 /****************************************************************************
392 Read data from fsp on the vfs. (note: EINTR re-read differs from vfs_write_data)
393 ****************************************************************************/
395 ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count)
399 while (total < byte_count)
401 ssize_t ret = SMB_VFS_READ(fsp, fsp->fd, buf + total,
404 if (ret == 0) return total;
413 return (ssize_t)total;
416 /****************************************************************************
417 Write data to a fd on the vfs.
418 ****************************************************************************/
420 ssize_t vfs_write_data(files_struct *fsp,const char *buffer,size_t N)
426 ret = SMB_VFS_WRITE(fsp,fsp->fd,buffer + total,N - total);
435 return (ssize_t)total;
438 /****************************************************************************
439 An allocate file space call using the vfs interface.
440 Allocates space for a file from a filedescriptor.
441 Returns 0 on success, -1 on failure.
442 ****************************************************************************/
444 int vfs_allocate_file_space(files_struct *fsp, SMB_BIG_UINT len)
448 connection_struct *conn = fsp->conn;
449 SMB_BIG_UINT space_avail;
450 SMB_BIG_UINT bsize,dfree,dsize;
452 release_level_2_oplocks_on_change(fsp);
455 * Actually try and commit the space on disk....
458 DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", fsp->fsp_name, (double)len ));
460 if (((SMB_OFF_T)len) < 0) {
461 DEBUG(0,("vfs_allocate_file_space: %s negative len requested.\n", fsp->fsp_name ));
465 ret = SMB_VFS_FSTAT(fsp,fsp->fd,&st);
469 if (len == (SMB_BIG_UINT)st.st_size)
472 if (len < (SMB_BIG_UINT)st.st_size) {
473 /* Shrink - use ftruncate. */
475 DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
476 fsp->fsp_name, (double)st.st_size ));
478 flush_write_cache(fsp, SIZECHANGE_FLUSH);
479 if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fd, (SMB_OFF_T)len)) != -1) {
480 set_filelen_write_cache(fsp, len);
485 /* Grow - we need to test if we have enough space. */
487 if (!lp_strict_allocate(SNUM(fsp->conn)))
491 len /= 1024; /* Len is now number of 1k blocks needed. */
492 space_avail = SMB_VFS_DISK_FREE(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize);
494 DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %.0f, space avail = %.0f\n",
495 fsp->fsp_name, (double)st.st_size, (double)len, (double)space_avail ));
497 if (len > space_avail) {
505 /****************************************************************************
506 A vfs set_filelen call.
507 set the length of a file from a filedescriptor.
508 Returns 0 on success, -1 on failure.
509 ****************************************************************************/
511 int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
515 release_level_2_oplocks_on_change(fsp);
516 DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len));
517 flush_write_cache(fsp, SIZECHANGE_FLUSH);
518 if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fd, len)) != -1)
519 set_filelen_write_cache(fsp, len);
524 /****************************************************************************
525 Transfer some data (n bytes) between two file_struct's.
526 ****************************************************************************/
528 static files_struct *in_fsp;
529 static files_struct *out_fsp;
531 static ssize_t read_fn(int fd, void *buf, size_t len)
533 return SMB_VFS_READ(in_fsp, fd, buf, len);
536 static ssize_t write_fn(int fd, const void *buf, size_t len)
538 return SMB_VFS_WRITE(out_fsp, fd, buf, len);
541 SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n)
546 return transfer_file_internal(in_fsp->fd, out_fsp->fd, n, read_fn, write_fn);
549 /*******************************************************************
550 A vfs_readdir wrapper which just returns the file name.
551 ********************************************************************/
553 char *vfs_readdirname(connection_struct *conn, void *p)
555 struct dirent *ptr= NULL;
561 ptr = (struct dirent *)SMB_VFS_READDIR(conn,p);
572 #ifdef HAVE_BROKEN_READDIR
573 /* using /usr/ucb/cc is BAD */
580 /*******************************************************************
581 A wrapper for vfs_chdir().
582 ********************************************************************/
584 int vfs_ChDir(connection_struct *conn, const char *path)
587 static pstring LastDir="";
589 if (strcsequal(path,"."))
592 if (*path == '/' && strcsequal(LastDir,path))
595 DEBUG(4,("vfs_ChDir to %s\n",path));
597 res = SMB_VFS_CHDIR(conn,path);
599 pstrcpy(LastDir,path);
603 /* number of list structures for a caching GetWd function. */
604 #define MAX_GETWDCACHE (50)
607 SMB_DEV_T dev; /* These *must* be compatible with the types returned in a stat() call. */
608 SMB_INO_T inode; /* These *must* be compatible with the types returned in a stat() call. */
609 char *dos_path; /* The pathname in DOS format. */
611 } ino_list[MAX_GETWDCACHE];
613 extern BOOL use_getwd_cache;
615 /****************************************************************************
616 Prompte a ptr (to make it recently used)
617 ****************************************************************************/
619 static void array_promote(char *array,int elsize,int element)
625 p = (char *)malloc(elsize);
628 DEBUG(5,("array_promote: malloc fail\n"));
632 memcpy(p,array + element * elsize, elsize);
633 memmove(array + elsize,array,elsize*element);
634 memcpy(array,p,elsize);
638 /*******************************************************************
639 Return the absolute current directory path - given a UNIX pathname.
640 Note that this path is returned in DOS format, not UNIX
641 format. Note this can be called with conn == NULL.
642 ********************************************************************/
644 char *vfs_GetWd(connection_struct *conn, char *path)
647 static BOOL getwd_cache_init = False;
648 SMB_STRUCT_STAT st, st2;
653 if (!use_getwd_cache)
654 return(SMB_VFS_GETWD(conn,path));
657 if (!getwd_cache_init) {
658 getwd_cache_init = True;
659 for (i=0;i<MAX_GETWDCACHE;i++) {
660 string_set(&ino_list[i].dos_path,"");
661 ino_list[i].valid = False;
665 /* Get the inode of the current directory, if this doesn't work we're
668 if (SMB_VFS_STAT(conn, ".",&st) == -1) {
669 DEBUG(0,("Very strange, couldn't stat \".\" path=%s\n", path));
670 return(SMB_VFS_GETWD(conn,path));
674 for (i=0; i<MAX_GETWDCACHE; i++) {
675 if (ino_list[i].valid) {
677 /* If we have found an entry with a matching inode and dev number
678 then find the inode number for the directory in the cached string.
679 If this agrees with that returned by the stat for the current
680 directory then all is o.k. (but make sure it is a directory all
683 if (st.st_ino == ino_list[i].inode && st.st_dev == ino_list[i].dev) {
684 if (SMB_VFS_STAT(conn,ino_list[i].dos_path,&st2) == 0) {
685 if (st.st_ino == st2.st_ino && st.st_dev == st2.st_dev &&
686 (st2.st_mode & S_IFMT) == S_IFDIR) {
687 pstrcpy (path, ino_list[i].dos_path);
689 /* promote it for future use */
690 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
693 /* If the inode is different then something's changed,
694 scrub the entry and start from scratch. */
695 ino_list[i].valid = False;
702 /* We don't have the information to hand so rely on traditional methods.
703 The very slow getcwd, which spawns a process on some systems, or the
704 not quite so bad getwd. */
706 if (!SMB_VFS_GETWD(conn,s)) {
707 DEBUG(0,("vfs_GetWd: SMB_VFS_GETWD call failed, errno %s\n",strerror(errno)));
713 DEBUG(5,("vfs_GetWd %s, inode %.0f, dev %.0f\n",s,(double)st.st_ino,(double)st.st_dev));
715 /* add it to the cache */
716 i = MAX_GETWDCACHE - 1;
717 string_set(&ino_list[i].dos_path,s);
718 ino_list[i].dev = st.st_dev;
719 ino_list[i].inode = st.st_ino;
720 ino_list[i].valid = True;
722 /* put it at the top of the list */
723 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
729 /* check if the file 'nmae' is a symlink, in that case check that it point to
730 a file that reside under the 'dir' tree */
732 static BOOL readlink_check(connection_struct *conn, const char *dir, char *name)
741 if (!vfs_GetWd(conn, savedir)) {
742 DEBUG(0,("couldn't vfs_GetWd for %s %s\n", name, dir));
746 if (vfs_ChDir(conn, dir) != 0) {
747 DEBUG(0,("couldn't vfs_ChDir to %s\n", dir));
751 if (!vfs_GetWd(conn, realdir)) {
752 DEBUG(0,("couldn't vfs_GetWd for %s\n", dir));
753 vfs_ChDir(conn, savedir);
757 reallen = strlen(realdir);
758 if (realdir[reallen -1] == '/') {
760 realdir[reallen] = 0;
763 if (SMB_VFS_READLINK(conn, name, flink, sizeof(pstring) -1) != -1) {
764 DEBUG(3,("reduce_name: file path name %s is a symlink\nChecking it's path\n", name));
766 pstrcpy(cleanlink, flink);
768 pstrcpy(cleanlink, realdir);
769 pstrcat(cleanlink, "/");
770 pstrcat(cleanlink, flink);
772 unix_clean_name(cleanlink);
774 if (strncmp(cleanlink, realdir, reallen) != 0) {
775 DEBUG(2,("Bad access attempt? s=%s dir=%s newname=%s l=%d\n", name, realdir, cleanlink, (int)reallen));
780 vfs_ChDir(conn, savedir);
785 /*******************************************************************
786 Reduce a file name, removing .. elements and checking that
787 it is below dir in the heirachy. This uses vfs_GetWd() and so must be run
788 on the system that has the referenced file system.
789 Widelinks are allowed if widelinks is true.
790 ********************************************************************/
792 BOOL reduce_name(connection_struct *conn, pstring s, const char *dir,BOOL widelinks)
802 BOOL relative = (*s != '/');
804 *dir2 = *wd = *base_name = *newname = 0;
808 /* can't have a leading .. */
809 if (strncmp(s,"..",2) == 0 && (s[2]==0 || s[2]=='/')) {
810 DEBUG(3,("Illegal file name? (%s)\n",s));
820 DEBUG(3,("reduce_name [%s] [%s]\n",s,dir));
822 /* remove any double slashes */
823 all_string_sub(s,"//","/",0);
825 pstrcpy(base_name,s);
826 p = strrchr_m(base_name,'/');
829 return readlink_check(conn, dir, s);
831 if (!vfs_GetWd(conn,wd)) {
832 DEBUG(0,("couldn't vfs_GetWd for %s %s\n",s,dir));
836 if (vfs_ChDir(conn,dir) != 0) {
837 DEBUG(0,("couldn't vfs_ChDir to %s\n",dir));
841 if (!vfs_GetWd(conn,dir2)) {
842 DEBUG(0,("couldn't vfs_GetWd for %s\n",dir));
847 if (p && (p != base_name)) {
849 if (strcmp(p+1,".")==0)
851 if (strcmp(p+1,"..")==0)
855 if (vfs_ChDir(conn,base_name) != 0) {
857 DEBUG(3,("couldn't vfs_ChDir for %s %s basename=%s\n",s,dir,base_name));
861 if (!vfs_GetWd(conn,newname)) {
863 DEBUG(2,("couldn't get vfs_GetWd for %s %s\n",s,base_name));
867 if (p && (p != base_name)) {
868 pstrcat(newname,"/");
869 pstrcat(newname,p+1);
873 size_t l = strlen(dir2);
874 if (dir2[l-1] == '/')
877 if (strncmp(newname,dir2,l) != 0) {
879 DEBUG(2,("Bad access attempt? s=%s dir=%s newname=%s l=%d\n",s,dir2,newname,(int)l));
883 if (!readlink_check(conn, dir, newname)) {
884 DEBUG(2, ("Bad access attemt? %s is a symlink outside the share path", s));
889 if (newname[l] == '/')
890 pstrcpy(s,newname + l + 1);
892 pstrcpy(s,newname+l);
902 DEBUG(3,("reduced to %s\n",s));