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,
62 /* Directory operations */
105 /* Windows ACL operations. */
111 /* POSIX ACL operations. */
115 vfswrap_sys_acl_get_entry,
116 vfswrap_sys_acl_get_tag_type,
117 vfswrap_sys_acl_get_permset,
118 vfswrap_sys_acl_get_qualifier,
119 vfswrap_sys_acl_get_file,
120 vfswrap_sys_acl_get_fd,
121 vfswrap_sys_acl_clear_perms,
122 vfswrap_sys_acl_add_perm,
123 vfswrap_sys_acl_to_text,
124 vfswrap_sys_acl_init,
125 vfswrap_sys_acl_create_entry,
126 vfswrap_sys_acl_set_tag_type,
127 vfswrap_sys_acl_set_qualifier,
128 vfswrap_sys_acl_set_permset,
129 vfswrap_sys_acl_valid,
130 vfswrap_sys_acl_set_file,
131 vfswrap_sys_acl_set_fd,
132 vfswrap_sys_acl_delete_def_file,
133 vfswrap_sys_acl_get_perm,
134 vfswrap_sys_acl_free_text,
135 vfswrap_sys_acl_free_acl,
136 vfswrap_sys_acl_free_qualifier,
146 vfswrap_lremovexattr,
147 vfswrap_fremovexattr,
152 /* AIO operations. */
163 /****************************************************************************
164 maintain the list of available backends
165 ****************************************************************************/
167 static struct vfs_init_function_entry *vfs_find_backend_entry(const char *name)
169 struct vfs_init_function_entry *entry = backends;
172 if (strcmp(entry->name, name)==0) return entry;
179 NTSTATUS smb_register_vfs(int version, const char *name, vfs_op_tuple *vfs_op_tuples)
181 struct vfs_init_function_entry *entry = backends;
183 if ((version != SMB_VFS_INTERFACE_VERSION)) {
184 DEBUG(0, ("Failed to register vfs module.\n"
185 "The module was compiled against SMB_VFS_INTERFACE_VERSION %d,\n"
186 "current SMB_VFS_INTERFACE_VERSION is %d.\n"
187 "Please recompile against the current Samba Version!\n",
188 version, SMB_VFS_INTERFACE_VERSION));
189 return NT_STATUS_OBJECT_TYPE_MISMATCH;
192 if (!name || !name[0] || !vfs_op_tuples) {
193 DEBUG(0,("smb_register_vfs() called with NULL pointer or empty name!\n"));
194 return NT_STATUS_INVALID_PARAMETER;
197 if (vfs_find_backend_entry(name)) {
198 DEBUG(0,("VFS module %s already loaded!\n", name));
199 return NT_STATUS_OBJECT_NAME_COLLISION;
202 entry = SMB_XMALLOC_P(struct vfs_init_function_entry);
203 entry->name = smb_xstrdup(name);
204 entry->vfs_op_tuples = vfs_op_tuples;
206 DLIST_ADD(backends, entry);
207 DEBUG(5, ("Successfully added vfs backend '%s'\n", name));
211 /****************************************************************************
212 initialise default vfs hooks
213 ****************************************************************************/
215 static void vfs_init_default(connection_struct *conn)
217 DEBUG(3, ("Initialising default vfs hooks\n"));
219 memcpy(&conn->vfs.ops, &default_vfs.ops, sizeof(default_vfs.ops));
220 memcpy(&conn->vfs_opaque.ops, &default_vfs.ops, sizeof(default_vfs.ops));
223 /****************************************************************************
224 initialise custom vfs hooks
225 ****************************************************************************/
227 BOOL vfs_init_custom(connection_struct *conn, const char *vfs_object)
230 char *module_name = NULL;
231 char *module_param = NULL, *p;
233 vfs_handle_struct *handle;
234 struct vfs_init_function_entry *entry;
236 if (!conn||!vfs_object||!vfs_object[0]) {
237 DEBUG(0,("vfs_init_custon() called with NULL pointer or emtpy vfs_object!\n"));
245 DEBUG(3, ("Initialising custom vfs hooks from [%s]\n", vfs_object));
247 module_name = smb_xstrdup(vfs_object);
249 p = strchr_m(module_name, ':');
254 trim_char(module_param, ' ', ' ');
257 trim_char(module_name, ' ', ' ');
259 /* First, try to load the module with the new module system */
260 if((entry = vfs_find_backend_entry(module_name)) ||
261 (NT_STATUS_IS_OK(smb_probe_module("vfs", module_name)) &&
262 (entry = vfs_find_backend_entry(module_name)))) {
264 DEBUGADD(5,("Successfully loaded vfs module [%s] with the new modules system\n", vfs_object));
266 if ((ops = entry->vfs_op_tuples) == NULL) {
267 DEBUG(0, ("entry->vfs_op_tuples==NULL for [%s] failed\n", vfs_object));
268 SAFE_FREE(module_name);
272 DEBUG(0,("Can't find a vfs module [%s]\n",vfs_object));
273 SAFE_FREE(module_name);
277 handle = TALLOC_ZERO_P(conn->mem_ctx,vfs_handle_struct);
279 DEBUG(0,("talloc_zero() failed!\n"));
280 SAFE_FREE(module_name);
283 memcpy(&handle->vfs_next, &conn->vfs, sizeof(struct vfs_ops));
286 handle->param = talloc_strdup(conn->mem_ctx, module_param);
288 DLIST_ADD(conn->vfs_handles, handle);
290 for(i=0; ops[i].op != NULL; i++) {
291 DEBUG(5, ("Checking operation #%d (type %d, layer %d)\n", i, ops[i].type, ops[i].layer));
292 if(ops[i].layer == SMB_VFS_LAYER_OPAQUE) {
293 /* Check whether this operation was already made opaque by different module */
294 if(((void**)&conn->vfs_opaque.ops)[ops[i].type] == ((void**)&default_vfs.ops)[ops[i].type]) {
295 /* No, it isn't overloaded yet. Overload. */
296 DEBUGADD(5, ("Making operation type %d opaque [module %s]\n", ops[i].type, vfs_object));
297 ((void**)&conn->vfs_opaque.ops)[ops[i].type] = ops[i].op;
298 ((vfs_handle_struct **)&conn->vfs_opaque.handles)[ops[i].type] = handle;
301 /* Change current VFS disposition*/
302 DEBUGADD(5, ("Accepting operation type %d from module %s\n", ops[i].type, vfs_object));
303 ((void**)&conn->vfs.ops)[ops[i].type] = ops[i].op;
304 ((vfs_handle_struct **)&conn->vfs.handles)[ops[i].type] = handle;
307 SAFE_FREE(module_name);
311 /*****************************************************************
313 ******************************************************************/
315 BOOL smbd_vfs_init(connection_struct *conn)
317 const char **vfs_objects;
321 /* Normal share - initialise with disk access functions */
322 vfs_init_default(conn);
323 vfs_objects = lp_vfs_objects(SNUM(conn));
325 /* Override VFS functions if 'vfs object' was not specified*/
326 if (!vfs_objects || !vfs_objects[0])
329 for (i=0; vfs_objects[i] ;) {
333 for (j=i-1; j >= 0; j--) {
334 if (!vfs_init_custom(conn, vfs_objects[j])) {
335 DEBUG(0, ("smbd_vfs_init: vfs_init_custom failed for %s\n", vfs_objects[j]));
342 /*******************************************************************
343 Check if directory exists.
344 ********************************************************************/
346 BOOL vfs_directory_exist(connection_struct *conn, const char *dname, SMB_STRUCT_STAT *st)
354 if (SMB_VFS_STAT(conn,dname,st) != 0)
357 ret = S_ISDIR(st->st_mode);
364 /*******************************************************************
366 ********************************************************************/
368 int vfs_MkDir(connection_struct *conn, const char *name, mode_t mode)
371 SMB_STRUCT_STAT sbuf;
373 if(!(ret=SMB_VFS_MKDIR(conn, name, mode))) {
375 inherit_access_acl(conn, name, mode);
378 * Check if high bits should have been set,
379 * then (if bits are missing): add them.
380 * Consider bits automagically set by UNIX, i.e. SGID bit from parent dir.
382 if(mode & ~(S_IRWXU|S_IRWXG|S_IRWXO) &&
383 !SMB_VFS_STAT(conn,name,&sbuf) && (mode & ~sbuf.st_mode))
384 SMB_VFS_CHMOD(conn,name,sbuf.st_mode | (mode & ~sbuf.st_mode));
389 /*******************************************************************
390 Check if an object exists in the vfs.
391 ********************************************************************/
393 BOOL vfs_object_exist(connection_struct *conn,const char *fname,SMB_STRUCT_STAT *sbuf)
402 if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
407 /*******************************************************************
408 Check if a file exists in the vfs.
409 ********************************************************************/
411 BOOL vfs_file_exist(connection_struct *conn, const char *fname,SMB_STRUCT_STAT *sbuf)
420 if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
422 return(S_ISREG(sbuf->st_mode));
425 /****************************************************************************
426 Read data from fsp on the vfs. (note: EINTR re-read differs from vfs_write_data)
427 ****************************************************************************/
429 ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count)
433 while (total < byte_count)
435 ssize_t ret = SMB_VFS_READ(fsp, fsp->fh->fd, buf + total,
438 if (ret == 0) return total;
447 return (ssize_t)total;
450 ssize_t vfs_pread_data(files_struct *fsp, char *buf,
451 size_t byte_count, SMB_OFF_T offset)
455 while (total < byte_count)
457 ssize_t ret = SMB_VFS_PREAD(fsp, fsp->fh->fd, buf + total,
458 byte_count - total, offset + total);
460 if (ret == 0) return total;
469 return (ssize_t)total;
472 /****************************************************************************
473 Write data to a fd on the vfs.
474 ****************************************************************************/
476 ssize_t vfs_write_data(files_struct *fsp,const char *buffer,size_t N)
482 ret = SMB_VFS_WRITE(fsp,fsp->fh->fd,buffer + total,N - total);
491 return (ssize_t)total;
494 ssize_t vfs_pwrite_data(files_struct *fsp,const char *buffer,
495 size_t N, SMB_OFF_T offset)
501 ret = SMB_VFS_PWRITE(fsp, fsp->fh->fd, buffer + total,
502 N - total, offset + total);
511 return (ssize_t)total;
513 /****************************************************************************
514 An allocate file space call using the vfs interface.
515 Allocates space for a file from a filedescriptor.
516 Returns 0 on success, -1 on failure.
517 ****************************************************************************/
519 int vfs_allocate_file_space(files_struct *fsp, SMB_BIG_UINT len)
523 connection_struct *conn = fsp->conn;
524 SMB_BIG_UINT space_avail;
525 SMB_BIG_UINT bsize,dfree,dsize;
527 release_level_2_oplocks_on_change(fsp);
530 * Actually try and commit the space on disk....
533 DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", fsp->fsp_name, (double)len ));
535 if (((SMB_OFF_T)len) < 0) {
536 DEBUG(0,("vfs_allocate_file_space: %s negative len requested.\n", fsp->fsp_name ));
540 ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st);
544 if (len == (SMB_BIG_UINT)st.st_size)
547 if (len < (SMB_BIG_UINT)st.st_size) {
548 /* Shrink - use ftruncate. */
550 DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
551 fsp->fsp_name, (double)st.st_size ));
553 flush_write_cache(fsp, SIZECHANGE_FLUSH);
554 if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, (SMB_OFF_T)len)) != -1) {
555 set_filelen_write_cache(fsp, len);
560 /* Grow - we need to test if we have enough space. */
562 if (!lp_strict_allocate(SNUM(fsp->conn)))
566 len /= 1024; /* Len is now number of 1k blocks needed. */
567 space_avail = get_dfree_info(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize);
568 if (space_avail == (SMB_BIG_UINT)-1) {
572 DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %.0f, space avail = %.0f\n",
573 fsp->fsp_name, (double)st.st_size, (double)len, (double)space_avail ));
575 if (len > space_avail) {
583 /****************************************************************************
584 A vfs set_filelen call.
585 set the length of a file from a filedescriptor.
586 Returns 0 on success, -1 on failure.
587 ****************************************************************************/
589 int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
593 release_level_2_oplocks_on_change(fsp);
594 DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len));
595 flush_write_cache(fsp, SIZECHANGE_FLUSH);
596 if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, len)) != -1)
597 set_filelen_write_cache(fsp, len);
602 /****************************************************************************
603 A vfs fill sparse call.
604 Writes zeros from the end of file to len, if len is greater than EOF.
605 Used only by strict_sync.
606 Returns 0 on success, -1 on failure.
607 ****************************************************************************/
609 static char *sparse_buf;
610 #define SPARSE_BUF_WRITE_SIZE (32*1024)
612 int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len)
621 release_level_2_oplocks_on_change(fsp);
622 ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st);
627 if (len <= st.st_size) {
631 DEBUG(10,("vfs_fill_sparse: write zeros in file %s from len %.0f to len %.0f (%.0f bytes)\n",
632 fsp->fsp_name, (double)st.st_size, (double)len, (double)(len - st.st_size)));
634 flush_write_cache(fsp, SIZECHANGE_FLUSH);
637 sparse_buf = SMB_CALLOC_ARRAY(char, SPARSE_BUF_WRITE_SIZE);
645 num_to_write = len - st.st_size;
648 while (total < num_to_write) {
649 size_t curr_write_size = MIN(SPARSE_BUF_WRITE_SIZE, (num_to_write - total));
651 pwrite_ret = SMB_VFS_PWRITE(fsp, fsp->fh->fd, sparse_buf, curr_write_size, offset + total);
652 if (pwrite_ret == -1) {
653 DEBUG(10,("vfs_fill_sparse: SMB_VFS_PWRITE for file %s failed with error %s\n",
654 fsp->fsp_name, strerror(errno) ));
657 if (pwrite_ret == 0) {
664 set_filelen_write_cache(fsp, len);
668 /****************************************************************************
669 Transfer some data (n bytes) between two file_struct's.
670 ****************************************************************************/
672 static files_struct *in_fsp;
673 static files_struct *out_fsp;
675 static ssize_t read_fn(int fd, void *buf, size_t len)
677 return SMB_VFS_READ(in_fsp, fd, buf, len);
680 static ssize_t write_fn(int fd, const void *buf, size_t len)
682 return SMB_VFS_WRITE(out_fsp, fd, buf, len);
685 SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n)
690 return transfer_file_internal(in_fsp->fh->fd, out_fsp->fh->fd, n, read_fn, write_fn);
693 /*******************************************************************
694 A vfs_readdir wrapper which just returns the file name.
695 ********************************************************************/
697 char *vfs_readdirname(connection_struct *conn, void *p)
699 SMB_STRUCT_DIRENT *ptr= NULL;
705 ptr = SMB_VFS_READDIR(conn,p);
716 #ifdef HAVE_BROKEN_READDIR_NAME
717 /* using /usr/ucb/cc is BAD */
724 /*******************************************************************
725 A wrapper for vfs_chdir().
726 ********************************************************************/
728 int vfs_ChDir(connection_struct *conn, const char *path)
731 static pstring LastDir="";
733 if (strcsequal(path,"."))
736 if (*path == '/' && strcsequal(LastDir,path))
739 DEBUG(4,("vfs_ChDir to %s\n",path));
741 res = SMB_VFS_CHDIR(conn,path);
743 pstrcpy(LastDir,path);
747 /* number of list structures for a caching GetWd function. */
748 #define MAX_GETWDCACHE (50)
751 SMB_DEV_T dev; /* These *must* be compatible with the types returned in a stat() call. */
752 SMB_INO_T inode; /* These *must* be compatible with the types returned in a stat() call. */
753 char *dos_path; /* The pathname in DOS format. */
755 } ino_list[MAX_GETWDCACHE];
757 extern BOOL use_getwd_cache;
759 /****************************************************************************
760 Prompte a ptr (to make it recently used)
761 ****************************************************************************/
763 static void array_promote(char *array,int elsize,int element)
769 p = (char *)SMB_MALLOC(elsize);
772 DEBUG(5,("array_promote: malloc fail\n"));
776 memcpy(p,array + element * elsize, elsize);
777 memmove(array + elsize,array,elsize*element);
778 memcpy(array,p,elsize);
782 /*******************************************************************
783 Return the absolute current directory path - given a UNIX pathname.
784 Note that this path is returned in DOS format, not UNIX
785 format. Note this can be called with conn == NULL.
786 ********************************************************************/
788 char *vfs_GetWd(connection_struct *conn, char *path)
791 static BOOL getwd_cache_init = False;
792 SMB_STRUCT_STAT st, st2;
797 if (!use_getwd_cache)
798 return(SMB_VFS_GETWD(conn,path));
801 if (!getwd_cache_init) {
802 getwd_cache_init = True;
803 for (i=0;i<MAX_GETWDCACHE;i++) {
804 string_set(&ino_list[i].dos_path,"");
805 ino_list[i].valid = False;
809 /* Get the inode of the current directory, if this doesn't work we're
812 if (SMB_VFS_STAT(conn, ".",&st) == -1) {
813 /* Known to fail for root: the directory may be
814 * NFS-mounted and exported with root_squash (so has no root access). */
815 DEBUG(1,("vfs_GetWd: couldn't stat \".\" path=%s error %s (NFS problem ?)\n", path, strerror(errno) ));
816 return(SMB_VFS_GETWD(conn,path));
820 for (i=0; i<MAX_GETWDCACHE; i++) {
821 if (ino_list[i].valid) {
823 /* If we have found an entry with a matching inode and dev number
824 then find the inode number for the directory in the cached string.
825 If this agrees with that returned by the stat for the current
826 directory then all is o.k. (but make sure it is a directory all
829 if (st.st_ino == ino_list[i].inode && st.st_dev == ino_list[i].dev) {
830 if (SMB_VFS_STAT(conn,ino_list[i].dos_path,&st2) == 0) {
831 if (st.st_ino == st2.st_ino && st.st_dev == st2.st_dev &&
832 (st2.st_mode & S_IFMT) == S_IFDIR) {
833 pstrcpy (path, ino_list[i].dos_path);
835 /* promote it for future use */
836 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
839 /* If the inode is different then something's changed,
840 scrub the entry and start from scratch. */
841 ino_list[i].valid = False;
848 /* We don't have the information to hand so rely on traditional methods.
849 The very slow getcwd, which spawns a process on some systems, or the
850 not quite so bad getwd. */
852 if (!SMB_VFS_GETWD(conn,s)) {
853 DEBUG(0,("vfs_GetWd: SMB_VFS_GETWD call failed, errno %s\n",strerror(errno)));
859 DEBUG(5,("vfs_GetWd %s, inode %.0f, dev %.0f\n",s,(double)st.st_ino,(double)st.st_dev));
861 /* add it to the cache */
862 i = MAX_GETWDCACHE - 1;
863 string_set(&ino_list[i].dos_path,s);
864 ino_list[i].dev = st.st_dev;
865 ino_list[i].inode = st.st_ino;
866 ino_list[i].valid = True;
868 /* put it at the top of the list */
869 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
874 BOOL canonicalize_path(connection_struct *conn, pstring path)
876 #ifdef REALPATH_TAKES_NULL
877 char *resolved_name = SMB_VFS_REALPATH(conn,path,NULL);
878 if (!resolved_name) {
881 pstrcpy(path, resolved_name);
882 SAFE_FREE(resolved_name);
886 char resolved_name_buf[PATH_MAX+1];
888 pstring resolved_name_buf;
890 char *resolved_name = SMB_VFS_REALPATH(conn,path,resolved_name_buf);
891 if (!resolved_name) {
894 pstrcpy(path, resolved_name);
896 #endif /* REALPATH_TAKES_NULL */
899 /*******************************************************************
900 Reduce a file name, removing .. elements and checking that
901 it is below dir in the heirachy. This uses realpath.
902 ********************************************************************/
904 BOOL reduce_name(connection_struct *conn, const pstring fname)
906 #ifdef REALPATH_TAKES_NULL
907 BOOL free_resolved_name = True;
910 char resolved_name_buf[PATH_MAX+1];
912 pstring resolved_name_buf;
914 BOOL free_resolved_name = False;
916 char *resolved_name = NULL;
917 size_t con_path_len = strlen(conn->connectpath);
919 int saved_errno = errno;
921 DEBUG(3,("reduce_name [%s] [%s]\n", fname, conn->connectpath));
923 #ifdef REALPATH_TAKES_NULL
924 resolved_name = SMB_VFS_REALPATH(conn,fname,NULL);
926 resolved_name = SMB_VFS_REALPATH(conn,fname,resolved_name_buf);
929 if (!resolved_name) {
932 DEBUG(3,("reduce_name: Component not a directory in getting realpath for %s\n", fname));
938 fstring last_component;
939 /* Last component didn't exist. Remove it and try and canonicalise the directory. */
941 pstrcpy(tmp_fname, fname);
942 p = strrchr_m(tmp_fname, '/');
945 fstrcpy(last_component, p);
947 fstrcpy(last_component, tmp_fname);
948 pstrcpy(tmp_fname, ".");
951 #ifdef REALPATH_TAKES_NULL
952 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,NULL);
954 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,resolved_name_buf);
956 if (!resolved_name) {
957 DEBUG(3,("reduce_name: couldn't get realpath for %s\n", fname));
961 pstrcpy(tmp_fname, resolved_name);
962 pstrcat(tmp_fname, "/");
963 pstrcat(tmp_fname, last_component);
964 #ifdef REALPATH_TAKES_NULL
965 SAFE_FREE(resolved_name);
966 resolved_name = SMB_STRDUP(tmp_fname);
967 if (!resolved_name) {
968 DEBUG(0,("reduce_name: malloc fail for %s\n", tmp_fname));
974 safe_strcpy(resolved_name_buf, tmp_fname, PATH_MAX);
976 pstrcpy(resolved_name_buf, tmp_fname);
978 resolved_name = resolved_name_buf;
983 DEBUG(1,("reduce_name: couldn't get realpath for %s\n", fname));
984 /* Don't restore the saved errno. We need to return the error that
985 realpath caused here as it was not one of the cases we handle. JRA. */
990 DEBUG(10,("reduce_name realpath [%s] -> [%s]\n", fname, resolved_name));
992 if (*resolved_name != '/') {
993 DEBUG(0,("reduce_name: realpath doesn't return absolute paths !\n"));
994 if (free_resolved_name)
995 SAFE_FREE(resolved_name);
1000 /* Check for widelinks allowed. */
1001 if (!lp_widelinks(SNUM(conn)) && (strncmp(conn->connectpath, resolved_name, con_path_len) != 0)) {
1002 DEBUG(2, ("reduce_name: Bad access attempt: %s is a symlink outside the share path", fname));
1003 if (free_resolved_name)
1004 SAFE_FREE(resolved_name);
1009 /* Check if we are allowing users to follow symlinks */
1010 /* Patch from David Clerc <David.Clerc@cui.unige.ch>
1011 University of Geneva */
1014 if (!lp_symlinks(SNUM(conn))) {
1015 SMB_STRUCT_STAT statbuf;
1016 if ( (SMB_VFS_LSTAT(conn,fname,&statbuf) != -1) &&
1017 (S_ISLNK(statbuf.st_mode)) ) {
1018 if (free_resolved_name)
1019 SAFE_FREE(resolved_name);
1020 DEBUG(3,("reduce_name: denied: file path name %s is a symlink\n",resolved_name));
1027 DEBUG(3,("reduce_name: %s reduced to %s\n", fname, resolved_name));
1028 if (free_resolved_name)
1029 SAFE_FREE(resolved_name);
1030 errno = saved_errno;