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_P(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"));
234 DEBUG(3, ("Initialising custom vfs hooks from [%s]\n", vfs_object));
236 module_name = smb_xstrdup(vfs_object);
238 p = strchr_m(module_name, ':');
243 trim_char(module_param, ' ', ' ');
246 trim_char(module_name, ' ', ' ');
248 /* First, try to load the module with the new module system */
249 if((entry = vfs_find_backend_entry(module_name)) ||
250 (NT_STATUS_IS_OK(smb_probe_module("vfs", module_name)) &&
251 (entry = vfs_find_backend_entry(module_name)))) {
253 DEBUGADD(5,("Successfully loaded vfs module [%s] with the new modules system\n", vfs_object));
255 if ((ops = entry->vfs_op_tuples) == NULL) {
256 DEBUG(0, ("entry->vfs_op_tuples==NULL for [%s] failed\n", vfs_object));
257 SAFE_FREE(module_name);
261 DEBUG(0,("Can't find a vfs module [%s]\n",vfs_object));
262 SAFE_FREE(module_name);
266 handle = TALLOC_ZERO_P(conn->mem_ctx,vfs_handle_struct);
268 DEBUG(0,("talloc_zero() failed!\n"));
269 SAFE_FREE(module_name);
272 memcpy(&handle->vfs_next, &conn->vfs, sizeof(struct vfs_ops));
275 handle->param = talloc_strdup(conn->mem_ctx, module_param);
277 DLIST_ADD(conn->vfs_handles, handle);
279 for(i=0; ops[i].op != NULL; i++) {
280 DEBUG(5, ("Checking operation #%d (type %d, layer %d)\n", i, ops[i].type, ops[i].layer));
281 if(ops[i].layer == SMB_VFS_LAYER_OPAQUE) {
282 /* Check whether this operation was already made opaque by different module */
283 if(((void**)&conn->vfs_opaque.ops)[ops[i].type] == ((void**)&default_vfs.ops)[ops[i].type]) {
284 /* No, it isn't overloaded yet. Overload. */
285 DEBUGADD(5, ("Making operation type %d opaque [module %s]\n", ops[i].type, vfs_object));
286 ((void**)&conn->vfs_opaque.ops)[ops[i].type] = ops[i].op;
287 ((vfs_handle_struct **)&conn->vfs_opaque.handles)[ops[i].type] = handle;
290 /* Change current VFS disposition*/
291 DEBUGADD(5, ("Accepting operation type %d from module %s\n", ops[i].type, vfs_object));
292 ((void**)&conn->vfs.ops)[ops[i].type] = ops[i].op;
293 ((vfs_handle_struct **)&conn->vfs.handles)[ops[i].type] = handle;
296 SAFE_FREE(module_name);
300 /*****************************************************************
302 ******************************************************************/
304 BOOL smbd_vfs_init(connection_struct *conn)
306 const char **vfs_objects;
310 /* Normal share - initialise with disk access functions */
311 vfs_init_default(conn);
312 vfs_objects = lp_vfs_objects(SNUM(conn));
314 /* Override VFS functions if 'vfs object' was not specified*/
315 if (!vfs_objects || !vfs_objects[0])
318 for (i=0; vfs_objects[i] ;) {
322 for (j=i-1; j >= 0; j--) {
323 if (!vfs_init_custom(conn, vfs_objects[j])) {
324 DEBUG(0, ("smbd_vfs_init: vfs_init_custom failed for %s\n", vfs_objects[j]));
331 /*******************************************************************
332 Check if directory exists.
333 ********************************************************************/
335 BOOL vfs_directory_exist(connection_struct *conn, const char *dname, SMB_STRUCT_STAT *st)
343 if (SMB_VFS_STAT(conn,dname,st) != 0)
346 ret = S_ISDIR(st->st_mode);
353 /*******************************************************************
355 ********************************************************************/
357 int vfs_MkDir(connection_struct *conn, const char *name, mode_t mode)
360 SMB_STRUCT_STAT sbuf;
362 if(!(ret=SMB_VFS_MKDIR(conn, name, mode))) {
364 inherit_access_acl(conn, name, mode);
367 * Check if high bits should have been set,
368 * then (if bits are missing): add them.
369 * Consider bits automagically set by UNIX, i.e. SGID bit from parent dir.
371 if(mode & ~(S_IRWXU|S_IRWXG|S_IRWXO) &&
372 !SMB_VFS_STAT(conn,name,&sbuf) && (mode & ~sbuf.st_mode))
373 SMB_VFS_CHMOD(conn,name,sbuf.st_mode | (mode & ~sbuf.st_mode));
378 /*******************************************************************
379 Check if an object exists in the vfs.
380 ********************************************************************/
382 BOOL vfs_object_exist(connection_struct *conn,const char *fname,SMB_STRUCT_STAT *sbuf)
391 if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
396 /*******************************************************************
397 Check if a file exists in the vfs.
398 ********************************************************************/
400 BOOL vfs_file_exist(connection_struct *conn, const char *fname,SMB_STRUCT_STAT *sbuf)
409 if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
411 return(S_ISREG(sbuf->st_mode));
414 /****************************************************************************
415 Read data from fsp on the vfs. (note: EINTR re-read differs from vfs_write_data)
416 ****************************************************************************/
418 ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count)
422 while (total < byte_count)
424 ssize_t ret = SMB_VFS_READ(fsp, fsp->fd, buf + total,
427 if (ret == 0) return total;
436 return (ssize_t)total;
439 ssize_t vfs_pread_data(files_struct *fsp, char *buf,
440 size_t byte_count, SMB_OFF_T offset)
444 while (total < byte_count)
446 ssize_t ret = SMB_VFS_PREAD(fsp, fsp->fd, buf + total,
447 byte_count - total, offset + total);
449 if (ret == 0) return total;
458 return (ssize_t)total;
461 /****************************************************************************
462 Write data to a fd on the vfs.
463 ****************************************************************************/
465 ssize_t vfs_write_data(files_struct *fsp,const char *buffer,size_t N)
471 ret = SMB_VFS_WRITE(fsp,fsp->fd,buffer + total,N - total);
480 return (ssize_t)total;
483 ssize_t vfs_pwrite_data(files_struct *fsp,const char *buffer,
484 size_t N, SMB_OFF_T offset)
490 ret = SMB_VFS_PWRITE(fsp, fsp->fd, buffer + total,
491 N - total, offset + total);
500 return (ssize_t)total;
502 /****************************************************************************
503 An allocate file space call using the vfs interface.
504 Allocates space for a file from a filedescriptor.
505 Returns 0 on success, -1 on failure.
506 ****************************************************************************/
508 int vfs_allocate_file_space(files_struct *fsp, SMB_BIG_UINT len)
512 connection_struct *conn = fsp->conn;
513 SMB_BIG_UINT space_avail;
514 SMB_BIG_UINT bsize,dfree,dsize;
516 release_level_2_oplocks_on_change(fsp);
519 * Actually try and commit the space on disk....
522 DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", fsp->fsp_name, (double)len ));
524 if (((SMB_OFF_T)len) < 0) {
525 DEBUG(0,("vfs_allocate_file_space: %s negative len requested.\n", fsp->fsp_name ));
529 ret = SMB_VFS_FSTAT(fsp,fsp->fd,&st);
533 if (len == (SMB_BIG_UINT)st.st_size)
536 if (len < (SMB_BIG_UINT)st.st_size) {
537 /* Shrink - use ftruncate. */
539 DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
540 fsp->fsp_name, (double)st.st_size ));
542 flush_write_cache(fsp, SIZECHANGE_FLUSH);
543 if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fd, (SMB_OFF_T)len)) != -1) {
544 set_filelen_write_cache(fsp, len);
549 /* Grow - we need to test if we have enough space. */
551 if (!lp_strict_allocate(SNUM(fsp->conn)))
555 len /= 1024; /* Len is now number of 1k blocks needed. */
556 space_avail = SMB_VFS_DISK_FREE(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize);
557 if (space_avail == (SMB_BIG_UINT)-1) {
561 DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %.0f, space avail = %.0f\n",
562 fsp->fsp_name, (double)st.st_size, (double)len, (double)space_avail ));
564 if (len > space_avail) {
572 /****************************************************************************
573 A vfs set_filelen call.
574 set the length of a file from a filedescriptor.
575 Returns 0 on success, -1 on failure.
576 ****************************************************************************/
578 int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
582 release_level_2_oplocks_on_change(fsp);
583 DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len));
584 flush_write_cache(fsp, SIZECHANGE_FLUSH);
585 if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fd, len)) != -1)
586 set_filelen_write_cache(fsp, len);
591 /****************************************************************************
592 A vfs fill sparse call.
593 Writes zeros from the end of file to len, if len is greater than EOF.
594 Used only by strict_sync.
595 Returns 0 on success, -1 on failure.
596 ****************************************************************************/
598 static char *sparse_buf;
599 #define SPARSE_BUF_WRITE_SIZE (32*1024)
601 int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len)
610 release_level_2_oplocks_on_change(fsp);
611 ret = SMB_VFS_FSTAT(fsp,fsp->fd,&st);
616 if (len <= st.st_size) {
620 DEBUG(10,("vfs_fill_sparse: write zeros in file %s from len %.0f to len %.0f (%.0f bytes)\n",
621 fsp->fsp_name, (double)st.st_size, (double)len, (double)(len - st.st_size)));
623 flush_write_cache(fsp, SIZECHANGE_FLUSH);
626 sparse_buf = SMB_CALLOC_ARRAY(char, SPARSE_BUF_WRITE_SIZE);
634 num_to_write = len - st.st_size;
637 while (total < num_to_write) {
638 size_t curr_write_size = MIN(SPARSE_BUF_WRITE_SIZE, (num_to_write - total));
640 pwrite_ret = SMB_VFS_PWRITE(fsp, fsp->fd, sparse_buf, curr_write_size, offset + total);
641 if (pwrite_ret == -1) {
642 DEBUG(10,("vfs_fill_sparse: SMB_VFS_PWRITE for file %s failed with error %s\n",
643 fsp->fsp_name, strerror(errno) ));
646 if (pwrite_ret == 0) {
653 set_filelen_write_cache(fsp, len);
657 /****************************************************************************
658 Transfer some data (n bytes) between two file_struct's.
659 ****************************************************************************/
661 static files_struct *in_fsp;
662 static files_struct *out_fsp;
664 static ssize_t read_fn(int fd, void *buf, size_t len)
666 return SMB_VFS_READ(in_fsp, fd, buf, len);
669 static ssize_t write_fn(int fd, const void *buf, size_t len)
671 return SMB_VFS_WRITE(out_fsp, fd, buf, len);
674 SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n)
679 return transfer_file_internal(in_fsp->fd, out_fsp->fd, n, read_fn, write_fn);
682 /*******************************************************************
683 A vfs_readdir wrapper which just returns the file name.
684 ********************************************************************/
686 char *vfs_readdirname(connection_struct *conn, void *p)
688 SMB_STRUCT_DIRENT *ptr= NULL;
694 ptr = SMB_VFS_READDIR(conn,p);
705 #ifdef HAVE_BROKEN_READDIR
706 /* using /usr/ucb/cc is BAD */
713 /*******************************************************************
714 A wrapper for vfs_chdir().
715 ********************************************************************/
717 int vfs_ChDir(connection_struct *conn, const char *path)
720 static pstring LastDir="";
722 if (strcsequal(path,"."))
725 if (*path == '/' && strcsequal(LastDir,path))
728 DEBUG(4,("vfs_ChDir to %s\n",path));
730 res = SMB_VFS_CHDIR(conn,path);
732 pstrcpy(LastDir,path);
736 /* number of list structures for a caching GetWd function. */
737 #define MAX_GETWDCACHE (50)
740 SMB_DEV_T dev; /* These *must* be compatible with the types returned in a stat() call. */
741 SMB_INO_T inode; /* These *must* be compatible with the types returned in a stat() call. */
742 char *dos_path; /* The pathname in DOS format. */
744 } ino_list[MAX_GETWDCACHE];
746 extern BOOL use_getwd_cache;
748 /****************************************************************************
749 Prompte a ptr (to make it recently used)
750 ****************************************************************************/
752 static void array_promote(char *array,int elsize,int element)
758 p = (char *)SMB_MALLOC(elsize);
761 DEBUG(5,("array_promote: malloc fail\n"));
765 memcpy(p,array + element * elsize, elsize);
766 memmove(array + elsize,array,elsize*element);
767 memcpy(array,p,elsize);
771 /*******************************************************************
772 Return the absolute current directory path - given a UNIX pathname.
773 Note that this path is returned in DOS format, not UNIX
774 format. Note this can be called with conn == NULL.
775 ********************************************************************/
777 char *vfs_GetWd(connection_struct *conn, char *path)
780 static BOOL getwd_cache_init = False;
781 SMB_STRUCT_STAT st, st2;
786 if (!use_getwd_cache)
787 return(SMB_VFS_GETWD(conn,path));
790 if (!getwd_cache_init) {
791 getwd_cache_init = True;
792 for (i=0;i<MAX_GETWDCACHE;i++) {
793 string_set(&ino_list[i].dos_path,"");
794 ino_list[i].valid = False;
798 /* Get the inode of the current directory, if this doesn't work we're
801 if (SMB_VFS_STAT(conn, ".",&st) == -1) {
802 /* Known to fail for root: the directory may be
803 * NFS-mounted and exported with root_squash (so has no root access). */
804 DEBUG(1,("vfs_GetWd: couldn't stat \".\" path=%s error %s (NFS problem ?)\n", path, strerror(errno) ));
805 return(SMB_VFS_GETWD(conn,path));
809 for (i=0; i<MAX_GETWDCACHE; i++) {
810 if (ino_list[i].valid) {
812 /* If we have found an entry with a matching inode and dev number
813 then find the inode number for the directory in the cached string.
814 If this agrees with that returned by the stat for the current
815 directory then all is o.k. (but make sure it is a directory all
818 if (st.st_ino == ino_list[i].inode && st.st_dev == ino_list[i].dev) {
819 if (SMB_VFS_STAT(conn,ino_list[i].dos_path,&st2) == 0) {
820 if (st.st_ino == st2.st_ino && st.st_dev == st2.st_dev &&
821 (st2.st_mode & S_IFMT) == S_IFDIR) {
822 pstrcpy (path, ino_list[i].dos_path);
824 /* promote it for future use */
825 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
828 /* If the inode is different then something's changed,
829 scrub the entry and start from scratch. */
830 ino_list[i].valid = False;
837 /* We don't have the information to hand so rely on traditional methods.
838 The very slow getcwd, which spawns a process on some systems, or the
839 not quite so bad getwd. */
841 if (!SMB_VFS_GETWD(conn,s)) {
842 DEBUG(0,("vfs_GetWd: SMB_VFS_GETWD call failed, errno %s\n",strerror(errno)));
848 DEBUG(5,("vfs_GetWd %s, inode %.0f, dev %.0f\n",s,(double)st.st_ino,(double)st.st_dev));
850 /* add it to the cache */
851 i = MAX_GETWDCACHE - 1;
852 string_set(&ino_list[i].dos_path,s);
853 ino_list[i].dev = st.st_dev;
854 ino_list[i].inode = st.st_ino;
855 ino_list[i].valid = True;
857 /* put it at the top of the list */
858 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
863 BOOL canonicalize_path(connection_struct *conn, pstring path)
865 #ifdef REALPATH_TAKES_NULL
866 char *resolved_name = SMB_VFS_REALPATH(conn,path,NULL);
867 if (!resolved_name) {
870 pstrcpy(path, resolved_name);
871 SAFE_FREE(resolved_name);
875 char resolved_name_buf[PATH_MAX+1];
877 pstring resolved_name_buf;
879 char *resolved_name = SMB_VFS_REALPATH(conn,path,resolved_name_buf);
880 if (!resolved_name) {
883 pstrcpy(path, resolved_name);
885 #endif /* REALPATH_TAKES_NULL */
888 /*******************************************************************
889 Reduce a file name, removing .. elements and checking that
890 it is below dir in the heirachy. This uses realpath.
891 ********************************************************************/
893 BOOL reduce_name(connection_struct *conn, const pstring fname)
895 #ifdef REALPATH_TAKES_NULL
896 BOOL free_resolved_name = True;
899 char resolved_name_buf[PATH_MAX+1];
901 pstring resolved_name_buf;
903 BOOL free_resolved_name = False;
905 char *resolved_name = NULL;
906 size_t con_path_len = strlen(conn->connectpath);
908 int saved_errno = errno;
910 DEBUG(3,("reduce_name [%s] [%s]\n", fname, conn->connectpath));
912 #ifdef REALPATH_TAKES_NULL
913 resolved_name = SMB_VFS_REALPATH(conn,fname,NULL);
915 resolved_name = SMB_VFS_REALPATH(conn,fname,resolved_name_buf);
918 if (!resolved_name) {
921 DEBUG(3,("reduce_name: Component not a directory in getting realpath for %s\n", fname));
927 fstring last_component;
928 /* Last component didn't exist. Remove it and try and canonicalise the directory. */
930 pstrcpy(tmp_fname, fname);
931 p = strrchr_m(tmp_fname, '/');
934 fstrcpy(last_component, p);
936 fstrcpy(last_component, tmp_fname);
937 pstrcpy(tmp_fname, ".");
940 #ifdef REALPATH_TAKES_NULL
941 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,NULL);
943 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,resolved_name_buf);
945 if (!resolved_name) {
946 DEBUG(3,("reduce_name: couldn't get realpath for %s\n", fname));
950 pstrcpy(tmp_fname, resolved_name);
951 pstrcat(tmp_fname, "/");
952 pstrcat(tmp_fname, last_component);
953 #ifdef REALPATH_TAKES_NULL
954 SAFE_FREE(resolved_name);
955 resolved_name = SMB_STRDUP(tmp_fname);
956 if (!resolved_name) {
957 DEBUG(0,("reduce_name: malloc fail for %s\n", tmp_fname));
963 safe_strcpy(resolved_name_buf, tmp_fname, PATH_MAX);
965 pstrcpy(resolved_name_buf, tmp_fname);
967 resolved_name = resolved_name_buf;
972 DEBUG(1,("reduce_name: couldn't get realpath for %s\n", fname));
973 /* Don't restore the saved errno. We need to return the error that
974 realpath caused here as it was not one of the cases we handle. JRA. */
979 DEBUG(10,("reduce_name realpath [%s] -> [%s]\n", fname, resolved_name));
981 if (*resolved_name != '/') {
982 DEBUG(0,("reduce_name: realpath doesn't return absolute paths !\n"));
983 if (free_resolved_name)
984 SAFE_FREE(resolved_name);
989 /* Check for widelinks allowed. */
990 if (!lp_widelinks(SNUM(conn)) && (strncmp(conn->connectpath, resolved_name, con_path_len) != 0)) {
991 DEBUG(2, ("reduce_name: Bad access attempt: %s is a symlink outside the share path", fname));
992 if (free_resolved_name)
993 SAFE_FREE(resolved_name);
998 /* Check if we are allowing users to follow symlinks */
999 /* Patch from David Clerc <David.Clerc@cui.unige.ch>
1000 University of Geneva */
1003 if (!lp_symlinks(SNUM(conn))) {
1004 SMB_STRUCT_STAT statbuf;
1005 if ( (SMB_VFS_LSTAT(conn,fname,&statbuf) != -1) &&
1006 (S_ISLNK(statbuf.st_mode)) ) {
1007 if (free_resolved_name)
1008 SAFE_FREE(resolved_name);
1009 DEBUG(3,("reduce_name: denied: file path name %s is a symlink\n",resolved_name));
1016 DEBUG(3,("reduce_name: %s reduced to %s\n", fname, resolved_name));
1017 if (free_resolved_name)
1018 SAFE_FREE(resolved_name);
1019 errno = saved_errno;