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,
59 vfswrap_get_shadow_copy_data,
61 /* Directory operations */
103 /* Windows ACL operations. */
109 /* POSIX ACL operations. */
113 vfswrap_sys_acl_get_entry,
114 vfswrap_sys_acl_get_tag_type,
115 vfswrap_sys_acl_get_permset,
116 vfswrap_sys_acl_get_qualifier,
117 vfswrap_sys_acl_get_file,
118 vfswrap_sys_acl_get_fd,
119 vfswrap_sys_acl_clear_perms,
120 vfswrap_sys_acl_add_perm,
121 vfswrap_sys_acl_to_text,
122 vfswrap_sys_acl_init,
123 vfswrap_sys_acl_create_entry,
124 vfswrap_sys_acl_set_tag_type,
125 vfswrap_sys_acl_set_qualifier,
126 vfswrap_sys_acl_set_permset,
127 vfswrap_sys_acl_valid,
128 vfswrap_sys_acl_set_file,
129 vfswrap_sys_acl_set_fd,
130 vfswrap_sys_acl_delete_def_file,
131 vfswrap_sys_acl_get_perm,
132 vfswrap_sys_acl_free_text,
133 vfswrap_sys_acl_free_acl,
134 vfswrap_sys_acl_free_qualifier,
144 vfswrap_lremovexattr,
145 vfswrap_fremovexattr,
152 /****************************************************************************
153 maintain the list of available backends
154 ****************************************************************************/
156 static struct vfs_init_function_entry *vfs_find_backend_entry(const char *name)
158 struct vfs_init_function_entry *entry = backends;
161 if (strcmp(entry->name, name)==0) return entry;
168 NTSTATUS smb_register_vfs(int version, const char *name, vfs_op_tuple *vfs_op_tuples)
170 struct vfs_init_function_entry *entry = backends;
172 if ((version != SMB_VFS_INTERFACE_VERSION)) {
173 DEBUG(0, ("Failed to register vfs module.\n"
174 "The module was compiled against SMB_VFS_INTERFACE_VERSION %d,\n"
175 "current SMB_VFS_INTERFACE_VERSION is %d.\n"
176 "Please recompile against the current Samba Version!\n",
177 version, SMB_VFS_INTERFACE_VERSION));
178 return NT_STATUS_OBJECT_TYPE_MISMATCH;
181 if (!name || !name[0] || !vfs_op_tuples) {
182 DEBUG(0,("smb_register_vfs() called with NULL pointer or empty name!\n"));
183 return NT_STATUS_INVALID_PARAMETER;
186 if (vfs_find_backend_entry(name)) {
187 DEBUG(0,("VFS module %s already loaded!\n", name));
188 return NT_STATUS_OBJECT_NAME_COLLISION;
191 entry = smb_xmalloc(sizeof(struct vfs_init_function_entry));
192 entry->name = smb_xstrdup(name);
193 entry->vfs_op_tuples = vfs_op_tuples;
195 DLIST_ADD(backends, entry);
196 DEBUG(5, ("Successfully added vfs backend '%s'\n", name));
200 /****************************************************************************
201 initialise default vfs hooks
202 ****************************************************************************/
204 static void vfs_init_default(connection_struct *conn)
206 DEBUG(3, ("Initialising default vfs hooks\n"));
208 memcpy(&conn->vfs.ops, &default_vfs.ops, sizeof(default_vfs.ops));
209 memcpy(&conn->vfs_opaque.ops, &default_vfs.ops, sizeof(default_vfs.ops));
212 /****************************************************************************
213 initialise custom vfs hooks
214 ****************************************************************************/
216 BOOL vfs_init_custom(connection_struct *conn, const char *vfs_object)
219 char *module_name = NULL;
220 char *module_param = NULL, *p;
222 vfs_handle_struct *handle;
223 struct vfs_init_function_entry *entry;
225 if (!conn||!vfs_object||!vfs_object[0]) {
226 DEBUG(0,("vfs_init_custon() called with NULL pointer or emtpy vfs_object!\n"));
230 if(!backends) static_init_vfs;
232 DEBUG(3, ("Initialising custom vfs hooks from [%s]\n", vfs_object));
234 module_name = smb_xstrdup(vfs_object);
236 p = strchr(module_name, ':');
241 trim_char(module_param, ' ', ' ');
244 trim_char(module_name, ' ', ' ');
246 /* First, try to load the module with the new module system */
247 if((entry = vfs_find_backend_entry(module_name)) ||
248 (NT_STATUS_IS_OK(smb_probe_module("vfs", module_name)) &&
249 (entry = vfs_find_backend_entry(module_name)))) {
251 DEBUGADD(5,("Successfully loaded vfs module [%s] with the new modules system\n", vfs_object));
253 if ((ops = entry->vfs_op_tuples) == NULL) {
254 DEBUG(0, ("entry->vfs_op_tuples==NULL for [%s] failed\n", vfs_object));
255 SAFE_FREE(module_name);
259 DEBUG(0,("Can't find a vfs module [%s]\n",vfs_object));
260 SAFE_FREE(module_name);
264 handle = (vfs_handle_struct *)talloc_zero(conn->mem_ctx,sizeof(vfs_handle_struct));
266 DEBUG(0,("talloc_zero() failed!\n"));
267 SAFE_FREE(module_name);
270 memcpy(&handle->vfs_next, &conn->vfs, sizeof(struct vfs_ops));
273 handle->param = talloc_strdup(conn->mem_ctx, module_param);
275 DLIST_ADD(conn->vfs_handles, handle);
277 for(i=0; ops[i].op != NULL; i++) {
278 DEBUG(5, ("Checking operation #%d (type %d, layer %d)\n", i, ops[i].type, ops[i].layer));
279 if(ops[i].layer == SMB_VFS_LAYER_OPAQUE) {
280 /* Check whether this operation was already made opaque by different module */
281 if(((void**)&conn->vfs_opaque.ops)[ops[i].type] == ((void**)&default_vfs.ops)[ops[i].type]) {
282 /* No, it isn't overloaded yet. Overload. */
283 DEBUGADD(5, ("Making operation type %d opaque [module %s]\n", ops[i].type, vfs_object));
284 ((void**)&conn->vfs_opaque.ops)[ops[i].type] = ops[i].op;
285 ((vfs_handle_struct **)&conn->vfs_opaque.handles)[ops[i].type] = handle;
288 /* Change current VFS disposition*/
289 DEBUGADD(5, ("Accepting operation type %d from module %s\n", ops[i].type, vfs_object));
290 ((void**)&conn->vfs.ops)[ops[i].type] = ops[i].op;
291 ((vfs_handle_struct **)&conn->vfs.handles)[ops[i].type] = handle;
294 SAFE_FREE(module_name);
298 /*****************************************************************
300 ******************************************************************/
302 BOOL smbd_vfs_init(connection_struct *conn)
304 const char **vfs_objects;
308 /* Normal share - initialise with disk access functions */
309 vfs_init_default(conn);
310 vfs_objects = lp_vfs_objects(SNUM(conn));
312 /* Override VFS functions if 'vfs object' was not specified*/
313 if (!vfs_objects || !vfs_objects[0])
316 for (i=0; vfs_objects[i] ;) {
320 for (j=i-1; j >= 0; j--) {
321 if (!vfs_init_custom(conn, vfs_objects[j])) {
322 DEBUG(0, ("smbd_vfs_init: vfs_init_custom failed for %s\n", vfs_objects[j]));
329 /*******************************************************************
330 Check if directory exists.
331 ********************************************************************/
333 BOOL vfs_directory_exist(connection_struct *conn, const char *dname, SMB_STRUCT_STAT *st)
341 if (SMB_VFS_STAT(conn,dname,st) != 0)
344 ret = S_ISDIR(st->st_mode);
351 /*******************************************************************
353 ********************************************************************/
355 int vfs_MkDir(connection_struct *conn, const char *name, mode_t mode)
358 SMB_STRUCT_STAT sbuf;
360 if(!(ret=SMB_VFS_MKDIR(conn, name, mode))) {
362 inherit_access_acl(conn, name, mode);
365 * Check if high bits should have been set,
366 * then (if bits are missing): add them.
367 * Consider bits automagically set by UNIX, i.e. SGID bit from parent dir.
369 if(mode & ~(S_IRWXU|S_IRWXG|S_IRWXO) &&
370 !SMB_VFS_STAT(conn,name,&sbuf) && (mode & ~sbuf.st_mode))
371 SMB_VFS_CHMOD(conn,name,sbuf.st_mode | (mode & ~sbuf.st_mode));
376 /*******************************************************************
377 Check if an object exists in the vfs.
378 ********************************************************************/
380 BOOL vfs_object_exist(connection_struct *conn,const char *fname,SMB_STRUCT_STAT *sbuf)
389 if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
394 /*******************************************************************
395 Check if a file exists in the vfs.
396 ********************************************************************/
398 BOOL vfs_file_exist(connection_struct *conn, const char *fname,SMB_STRUCT_STAT *sbuf)
407 if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
409 return(S_ISREG(sbuf->st_mode));
412 /****************************************************************************
413 Read data from fsp on the vfs. (note: EINTR re-read differs from vfs_write_data)
414 ****************************************************************************/
416 ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count)
420 while (total < byte_count)
422 ssize_t ret = SMB_VFS_READ(fsp, fsp->fd, buf + total,
425 if (ret == 0) return total;
434 return (ssize_t)total;
437 ssize_t vfs_pread_data(files_struct *fsp, char *buf,
438 size_t byte_count, SMB_OFF_T offset)
442 while (total < byte_count)
444 ssize_t ret = SMB_VFS_PREAD(fsp, fsp->fd, buf + total,
445 byte_count - total, offset + total);
447 if (ret == 0) return total;
456 return (ssize_t)total;
459 /****************************************************************************
460 Write data to a fd on the vfs.
461 ****************************************************************************/
463 ssize_t vfs_write_data(files_struct *fsp,const char *buffer,size_t N)
469 ret = SMB_VFS_WRITE(fsp,fsp->fd,buffer + total,N - total);
478 return (ssize_t)total;
481 ssize_t vfs_pwrite_data(files_struct *fsp,const char *buffer,
482 size_t N, SMB_OFF_T offset)
488 ret = SMB_VFS_PWRITE(fsp, fsp->fd, buffer + total,
489 N - total, offset + total);
498 return (ssize_t)total;
500 /****************************************************************************
501 An allocate file space call using the vfs interface.
502 Allocates space for a file from a filedescriptor.
503 Returns 0 on success, -1 on failure.
504 ****************************************************************************/
506 int vfs_allocate_file_space(files_struct *fsp, SMB_BIG_UINT len)
510 connection_struct *conn = fsp->conn;
511 SMB_BIG_UINT space_avail;
512 SMB_BIG_UINT bsize,dfree,dsize;
514 release_level_2_oplocks_on_change(fsp);
517 * Actually try and commit the space on disk....
520 DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", fsp->fsp_name, (double)len ));
522 if (((SMB_OFF_T)len) < 0) {
523 DEBUG(0,("vfs_allocate_file_space: %s negative len requested.\n", fsp->fsp_name ));
527 ret = SMB_VFS_FSTAT(fsp,fsp->fd,&st);
531 if (len == (SMB_BIG_UINT)st.st_size)
534 if (len < (SMB_BIG_UINT)st.st_size) {
535 /* Shrink - use ftruncate. */
537 DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
538 fsp->fsp_name, (double)st.st_size ));
540 flush_write_cache(fsp, SIZECHANGE_FLUSH);
541 if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fd, (SMB_OFF_T)len)) != -1) {
542 set_filelen_write_cache(fsp, len);
547 /* Grow - we need to test if we have enough space. */
549 if (!lp_strict_allocate(SNUM(fsp->conn)))
553 len /= 1024; /* Len is now number of 1k blocks needed. */
554 space_avail = SMB_VFS_DISK_FREE(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize);
556 DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %.0f, space avail = %.0f\n",
557 fsp->fsp_name, (double)st.st_size, (double)len, (double)space_avail ));
559 if (len > space_avail) {
567 /****************************************************************************
568 A vfs set_filelen call.
569 set the length of a file from a filedescriptor.
570 Returns 0 on success, -1 on failure.
571 ****************************************************************************/
573 int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
577 release_level_2_oplocks_on_change(fsp);
578 DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len));
579 flush_write_cache(fsp, SIZECHANGE_FLUSH);
580 if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fd, len)) != -1)
581 set_filelen_write_cache(fsp, len);
586 /****************************************************************************
587 Transfer some data (n bytes) between two file_struct's.
588 ****************************************************************************/
590 static files_struct *in_fsp;
591 static files_struct *out_fsp;
593 static ssize_t read_fn(int fd, void *buf, size_t len)
595 return SMB_VFS_READ(in_fsp, fd, buf, len);
598 static ssize_t write_fn(int fd, const void *buf, size_t len)
600 return SMB_VFS_WRITE(out_fsp, fd, buf, len);
603 SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n)
608 return transfer_file_internal(in_fsp->fd, out_fsp->fd, n, read_fn, write_fn);
611 /*******************************************************************
612 A vfs_readdir wrapper which just returns the file name.
613 ********************************************************************/
615 char *vfs_readdirname(connection_struct *conn, void *p)
617 SMB_STRUCT_DIRENT *ptr= NULL;
623 ptr = SMB_VFS_READDIR(conn,p);
634 #ifdef HAVE_BROKEN_READDIR
635 /* using /usr/ucb/cc is BAD */
642 /*******************************************************************
643 A wrapper for vfs_chdir().
644 ********************************************************************/
646 int vfs_ChDir(connection_struct *conn, const char *path)
649 static pstring LastDir="";
651 if (strcsequal(path,"."))
654 if (*path == '/' && strcsequal(LastDir,path))
657 DEBUG(4,("vfs_ChDir to %s\n",path));
659 res = SMB_VFS_CHDIR(conn,path);
661 pstrcpy(LastDir,path);
665 /* number of list structures for a caching GetWd function. */
666 #define MAX_GETWDCACHE (50)
669 SMB_DEV_T dev; /* These *must* be compatible with the types returned in a stat() call. */
670 SMB_INO_T inode; /* These *must* be compatible with the types returned in a stat() call. */
671 char *dos_path; /* The pathname in DOS format. */
673 } ino_list[MAX_GETWDCACHE];
675 extern BOOL use_getwd_cache;
677 /****************************************************************************
678 Prompte a ptr (to make it recently used)
679 ****************************************************************************/
681 static void array_promote(char *array,int elsize,int element)
687 p = (char *)malloc(elsize);
690 DEBUG(5,("array_promote: malloc fail\n"));
694 memcpy(p,array + element * elsize, elsize);
695 memmove(array + elsize,array,elsize*element);
696 memcpy(array,p,elsize);
700 /*******************************************************************
701 Return the absolute current directory path - given a UNIX pathname.
702 Note that this path is returned in DOS format, not UNIX
703 format. Note this can be called with conn == NULL.
704 ********************************************************************/
706 char *vfs_GetWd(connection_struct *conn, char *path)
709 static BOOL getwd_cache_init = False;
710 SMB_STRUCT_STAT st, st2;
715 if (!use_getwd_cache)
716 return(SMB_VFS_GETWD(conn,path));
719 if (!getwd_cache_init) {
720 getwd_cache_init = True;
721 for (i=0;i<MAX_GETWDCACHE;i++) {
722 string_set(&ino_list[i].dos_path,"");
723 ino_list[i].valid = False;
727 /* Get the inode of the current directory, if this doesn't work we're
730 if (SMB_VFS_STAT(conn, ".",&st) == -1) {
731 DEBUG(0,("Very strange, couldn't stat \".\" path=%s\n", path));
732 return(SMB_VFS_GETWD(conn,path));
736 for (i=0; i<MAX_GETWDCACHE; i++) {
737 if (ino_list[i].valid) {
739 /* If we have found an entry with a matching inode and dev number
740 then find the inode number for the directory in the cached string.
741 If this agrees with that returned by the stat for the current
742 directory then all is o.k. (but make sure it is a directory all
745 if (st.st_ino == ino_list[i].inode && st.st_dev == ino_list[i].dev) {
746 if (SMB_VFS_STAT(conn,ino_list[i].dos_path,&st2) == 0) {
747 if (st.st_ino == st2.st_ino && st.st_dev == st2.st_dev &&
748 (st2.st_mode & S_IFMT) == S_IFDIR) {
749 pstrcpy (path, ino_list[i].dos_path);
751 /* promote it for future use */
752 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
755 /* If the inode is different then something's changed,
756 scrub the entry and start from scratch. */
757 ino_list[i].valid = False;
764 /* We don't have the information to hand so rely on traditional methods.
765 The very slow getcwd, which spawns a process on some systems, or the
766 not quite so bad getwd. */
768 if (!SMB_VFS_GETWD(conn,s)) {
769 DEBUG(0,("vfs_GetWd: SMB_VFS_GETWD call failed, errno %s\n",strerror(errno)));
775 DEBUG(5,("vfs_GetWd %s, inode %.0f, dev %.0f\n",s,(double)st.st_ino,(double)st.st_dev));
777 /* add it to the cache */
778 i = MAX_GETWDCACHE - 1;
779 string_set(&ino_list[i].dos_path,s);
780 ino_list[i].dev = st.st_dev;
781 ino_list[i].inode = st.st_ino;
782 ino_list[i].valid = True;
784 /* put it at the top of the list */
785 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
790 BOOL canonicalize_path(connection_struct *conn, pstring path)
792 #ifdef REALPATH_TAKES_NULL
793 char *resolved_name = SMB_VFS_REALPATH(conn,path,NULL);
794 if (!resolved_name) {
797 pstrcpy(path, resolved_name);
798 SAFE_FREE(resolved_name);
802 char resolved_name_buf[PATH_MAX+1];
804 pstring resolved_name_buf;
806 char *resolved_name = SMB_VFS_REALPATH(conn,path,resolved_name_buf);
807 if (!resolved_name) {
810 pstrcpy(path, resolved_name);
812 #endif /* REALPATH_TAKES_NULL */
815 /*******************************************************************
816 Reduce a file name, removing .. elements and checking that
817 it is below dir in the heirachy. This uses realpath.
818 ********************************************************************/
820 BOOL reduce_name(connection_struct *conn, const pstring fname)
822 #ifdef REALPATH_TAKES_NULL
823 BOOL free_resolved_name = True;
826 char resolved_name_buf[PATH_MAX+1];
828 pstring resolved_name_buf;
830 BOOL free_resolved_name = False;
832 char *resolved_name = NULL;
833 size_t con_path_len = strlen(conn->connectpath);
835 int saved_errno = errno;
837 DEBUG(3,("reduce_name [%s] [%s]\n", fname, conn->connectpath));
839 #ifdef REALPATH_TAKES_NULL
840 resolved_name = SMB_VFS_REALPATH(conn,fname,NULL);
842 resolved_name = SMB_VFS_REALPATH(conn,fname,resolved_name_buf);
845 if (!resolved_name) {
848 DEBUG(3,("reduce_name: Component not a directory in getting realpath for %s\n", fname));
854 fstring last_component;
855 /* Last component didn't exist. Remove it and try and canonicalise the directory. */
857 pstrcpy(tmp_fname, fname);
858 p = strrchr_m(tmp_fname, '/');
861 fstrcpy(last_component, p);
863 fstrcpy(last_component, tmp_fname);
864 pstrcpy(tmp_fname, ".");
867 #ifdef REALPATH_TAKES_NULL
868 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,NULL);
870 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,resolved_name_buf);
872 if (!resolved_name) {
873 DEBUG(3,("reduce_name: couldn't get realpath for %s\n", fname));
877 pstrcpy(tmp_fname, resolved_name);
878 pstrcat(tmp_fname, "/");
879 pstrcat(tmp_fname, last_component);
880 #ifdef REALPATH_TAKES_NULL
881 SAFE_FREE(resolved_name);
882 resolved_name = strdup(tmp_fname);
883 if (!resolved_name) {
884 DEBUG(0,("reduce_name: malloc fail for %s\n", tmp_fname));
890 safe_strcpy(resolved_name_buf, tmp_fname, PATH_MAX);
892 pstrcpy(pstring resolved_name_buf, tmp_fname);
894 resolved_name = resolved_name_buf;
899 DEBUG(1,("reduce_name: couldn't get realpath for %s\n", fname));
905 DEBUG(10,("reduce_name realpath [%s] -> [%s]\n", fname, resolved_name));
907 if (*resolved_name != '/') {
908 DEBUG(0,("reduce_name: realpath doesn't return absolute paths !\n"));
909 if (free_resolved_name)
910 SAFE_FREE(resolved_name);
915 /* Check for widelinks allowed. */
916 if (!lp_widelinks(SNUM(conn)) && (strncmp(conn->connectpath, resolved_name, con_path_len) != 0)) {
917 DEBUG(2, ("reduce_name: Bad access attempt: %s is a symlink outside the share path", fname));
918 if (free_resolved_name)
919 SAFE_FREE(resolved_name);
924 /* Check if we are allowing users to follow symlinks */
925 /* Patch from David Clerc <David.Clerc@cui.unige.ch>
926 University of Geneva */
929 if (!lp_symlinks(SNUM(conn))) {
930 SMB_STRUCT_STAT statbuf;
931 if ( (SMB_VFS_LSTAT(conn,fname,&statbuf) != -1) &&
932 (S_ISLNK(statbuf.st_mode)) ) {
933 if (free_resolved_name)
934 SAFE_FREE(resolved_name);
935 DEBUG(3,("reduce_name: denied: file path name %s is a symlink\n",resolved_name));
942 DEBUG(3,("reduce_name: %s reduced to %s\n", fname, p));
943 if (free_resolved_name)
944 SAFE_FREE(resolved_name);