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,
150 /* AIO operations. */
161 /****************************************************************************
162 maintain the list of available backends
163 ****************************************************************************/
165 static struct vfs_init_function_entry *vfs_find_backend_entry(const char *name)
167 struct vfs_init_function_entry *entry = backends;
170 if (strcmp(entry->name, name)==0) return entry;
177 NTSTATUS smb_register_vfs(int version, const char *name, vfs_op_tuple *vfs_op_tuples)
179 struct vfs_init_function_entry *entry = backends;
181 if ((version != SMB_VFS_INTERFACE_VERSION)) {
182 DEBUG(0, ("Failed to register vfs module.\n"
183 "The module was compiled against SMB_VFS_INTERFACE_VERSION %d,\n"
184 "current SMB_VFS_INTERFACE_VERSION is %d.\n"
185 "Please recompile against the current Samba Version!\n",
186 version, SMB_VFS_INTERFACE_VERSION));
187 return NT_STATUS_OBJECT_TYPE_MISMATCH;
190 if (!name || !name[0] || !vfs_op_tuples) {
191 DEBUG(0,("smb_register_vfs() called with NULL pointer or empty name!\n"));
192 return NT_STATUS_INVALID_PARAMETER;
195 if (vfs_find_backend_entry(name)) {
196 DEBUG(0,("VFS module %s already loaded!\n", name));
197 return NT_STATUS_OBJECT_NAME_COLLISION;
200 entry = SMB_XMALLOC_P(struct vfs_init_function_entry);
201 entry->name = smb_xstrdup(name);
202 entry->vfs_op_tuples = vfs_op_tuples;
204 DLIST_ADD(backends, entry);
205 DEBUG(5, ("Successfully added vfs backend '%s'\n", name));
209 /****************************************************************************
210 initialise default vfs hooks
211 ****************************************************************************/
213 static void vfs_init_default(connection_struct *conn)
215 DEBUG(3, ("Initialising default vfs hooks\n"));
217 memcpy(&conn->vfs.ops, &default_vfs.ops, sizeof(default_vfs.ops));
218 memcpy(&conn->vfs_opaque.ops, &default_vfs.ops, sizeof(default_vfs.ops));
221 /****************************************************************************
222 initialise custom vfs hooks
223 ****************************************************************************/
225 BOOL vfs_init_custom(connection_struct *conn, const char *vfs_object)
228 char *module_name = NULL;
229 char *module_param = NULL, *p;
231 vfs_handle_struct *handle;
232 struct vfs_init_function_entry *entry;
234 if (!conn||!vfs_object||!vfs_object[0]) {
235 DEBUG(0,("vfs_init_custon() called with NULL pointer or emtpy vfs_object!\n"));
243 DEBUG(3, ("Initialising custom vfs hooks from [%s]\n", vfs_object));
245 module_name = smb_xstrdup(vfs_object);
247 p = strchr_m(module_name, ':');
252 trim_char(module_param, ' ', ' ');
255 trim_char(module_name, ' ', ' ');
257 /* First, try to load the module with the new module system */
258 if((entry = vfs_find_backend_entry(module_name)) ||
259 (NT_STATUS_IS_OK(smb_probe_module("vfs", module_name)) &&
260 (entry = vfs_find_backend_entry(module_name)))) {
262 DEBUGADD(5,("Successfully loaded vfs module [%s] with the new modules system\n", vfs_object));
264 if ((ops = entry->vfs_op_tuples) == NULL) {
265 DEBUG(0, ("entry->vfs_op_tuples==NULL for [%s] failed\n", vfs_object));
266 SAFE_FREE(module_name);
270 DEBUG(0,("Can't find a vfs module [%s]\n",vfs_object));
271 SAFE_FREE(module_name);
275 handle = TALLOC_ZERO_P(conn->mem_ctx,vfs_handle_struct);
277 DEBUG(0,("talloc_zero() failed!\n"));
278 SAFE_FREE(module_name);
281 memcpy(&handle->vfs_next, &conn->vfs, sizeof(struct vfs_ops));
284 handle->param = talloc_strdup(conn->mem_ctx, module_param);
286 DLIST_ADD(conn->vfs_handles, handle);
288 for(i=0; ops[i].op != NULL; i++) {
289 DEBUG(5, ("Checking operation #%d (type %d, layer %d)\n", i, ops[i].type, ops[i].layer));
290 if(ops[i].layer == SMB_VFS_LAYER_OPAQUE) {
291 /* Check whether this operation was already made opaque by different module */
292 if(((void**)&conn->vfs_opaque.ops)[ops[i].type] == ((void**)&default_vfs.ops)[ops[i].type]) {
293 /* No, it isn't overloaded yet. Overload. */
294 DEBUGADD(5, ("Making operation type %d opaque [module %s]\n", ops[i].type, vfs_object));
295 ((void**)&conn->vfs_opaque.ops)[ops[i].type] = ops[i].op;
296 ((vfs_handle_struct **)&conn->vfs_opaque.handles)[ops[i].type] = handle;
299 /* Change current VFS disposition*/
300 DEBUGADD(5, ("Accepting operation type %d from module %s\n", ops[i].type, vfs_object));
301 ((void**)&conn->vfs.ops)[ops[i].type] = ops[i].op;
302 ((vfs_handle_struct **)&conn->vfs.handles)[ops[i].type] = handle;
305 SAFE_FREE(module_name);
309 /*****************************************************************
311 ******************************************************************/
313 BOOL smbd_vfs_init(connection_struct *conn)
315 const char **vfs_objects;
319 /* Normal share - initialise with disk access functions */
320 vfs_init_default(conn);
321 vfs_objects = lp_vfs_objects(SNUM(conn));
323 /* Override VFS functions if 'vfs object' was not specified*/
324 if (!vfs_objects || !vfs_objects[0])
327 for (i=0; vfs_objects[i] ;) {
331 for (j=i-1; j >= 0; j--) {
332 if (!vfs_init_custom(conn, vfs_objects[j])) {
333 DEBUG(0, ("smbd_vfs_init: vfs_init_custom failed for %s\n", vfs_objects[j]));
340 /*******************************************************************
341 Check if directory exists.
342 ********************************************************************/
344 BOOL vfs_directory_exist(connection_struct *conn, const char *dname, SMB_STRUCT_STAT *st)
352 if (SMB_VFS_STAT(conn,dname,st) != 0)
355 ret = S_ISDIR(st->st_mode);
362 /*******************************************************************
364 ********************************************************************/
366 int vfs_MkDir(connection_struct *conn, const char *name, mode_t mode)
369 SMB_STRUCT_STAT sbuf;
371 if(!(ret=SMB_VFS_MKDIR(conn, name, mode))) {
373 inherit_access_acl(conn, name, mode);
376 * Check if high bits should have been set,
377 * then (if bits are missing): add them.
378 * Consider bits automagically set by UNIX, i.e. SGID bit from parent dir.
380 if(mode & ~(S_IRWXU|S_IRWXG|S_IRWXO) &&
381 !SMB_VFS_STAT(conn,name,&sbuf) && (mode & ~sbuf.st_mode))
382 SMB_VFS_CHMOD(conn,name,sbuf.st_mode | (mode & ~sbuf.st_mode));
387 /*******************************************************************
388 Check if an object exists in the vfs.
389 ********************************************************************/
391 BOOL vfs_object_exist(connection_struct *conn,const char *fname,SMB_STRUCT_STAT *sbuf)
400 if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
405 /*******************************************************************
406 Check if a file exists in the vfs.
407 ********************************************************************/
409 BOOL vfs_file_exist(connection_struct *conn, const char *fname,SMB_STRUCT_STAT *sbuf)
418 if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
420 return(S_ISREG(sbuf->st_mode));
423 /****************************************************************************
424 Read data from fsp on the vfs. (note: EINTR re-read differs from vfs_write_data)
425 ****************************************************************************/
427 ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count)
431 while (total < byte_count)
433 ssize_t ret = SMB_VFS_READ(fsp, fsp->fh->fd, buf + total,
436 if (ret == 0) return total;
445 return (ssize_t)total;
448 ssize_t vfs_pread_data(files_struct *fsp, char *buf,
449 size_t byte_count, SMB_OFF_T offset)
453 while (total < byte_count)
455 ssize_t ret = SMB_VFS_PREAD(fsp, fsp->fh->fd, buf + total,
456 byte_count - total, offset + total);
458 if (ret == 0) return total;
467 return (ssize_t)total;
470 /****************************************************************************
471 Write data to a fd on the vfs.
472 ****************************************************************************/
474 ssize_t vfs_write_data(files_struct *fsp,const char *buffer,size_t N)
480 ret = SMB_VFS_WRITE(fsp,fsp->fh->fd,buffer + total,N - total);
489 return (ssize_t)total;
492 ssize_t vfs_pwrite_data(files_struct *fsp,const char *buffer,
493 size_t N, SMB_OFF_T offset)
499 ret = SMB_VFS_PWRITE(fsp, fsp->fh->fd, buffer + total,
500 N - total, offset + total);
509 return (ssize_t)total;
511 /****************************************************************************
512 An allocate file space call using the vfs interface.
513 Allocates space for a file from a filedescriptor.
514 Returns 0 on success, -1 on failure.
515 ****************************************************************************/
517 int vfs_allocate_file_space(files_struct *fsp, SMB_BIG_UINT len)
521 connection_struct *conn = fsp->conn;
522 SMB_BIG_UINT space_avail;
523 SMB_BIG_UINT bsize,dfree,dsize;
525 release_level_2_oplocks_on_change(fsp);
528 * Actually try and commit the space on disk....
531 DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", fsp->fsp_name, (double)len ));
533 if (((SMB_OFF_T)len) < 0) {
534 DEBUG(0,("vfs_allocate_file_space: %s negative len requested.\n", fsp->fsp_name ));
538 ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st);
542 if (len == (SMB_BIG_UINT)st.st_size)
545 if (len < (SMB_BIG_UINT)st.st_size) {
546 /* Shrink - use ftruncate. */
548 DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
549 fsp->fsp_name, (double)st.st_size ));
551 flush_write_cache(fsp, SIZECHANGE_FLUSH);
552 if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, (SMB_OFF_T)len)) != -1) {
553 set_filelen_write_cache(fsp, len);
558 /* Grow - we need to test if we have enough space. */
560 if (!lp_strict_allocate(SNUM(fsp->conn)))
564 len /= 1024; /* Len is now number of 1k blocks needed. */
565 space_avail = SMB_VFS_DISK_FREE(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize);
566 if (space_avail == (SMB_BIG_UINT)-1) {
570 DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %.0f, space avail = %.0f\n",
571 fsp->fsp_name, (double)st.st_size, (double)len, (double)space_avail ));
573 if (len > space_avail) {
581 /****************************************************************************
582 A vfs set_filelen call.
583 set the length of a file from a filedescriptor.
584 Returns 0 on success, -1 on failure.
585 ****************************************************************************/
587 int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
591 release_level_2_oplocks_on_change(fsp);
592 DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len));
593 flush_write_cache(fsp, SIZECHANGE_FLUSH);
594 if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, len)) != -1)
595 set_filelen_write_cache(fsp, len);
600 /****************************************************************************
601 A vfs fill sparse call.
602 Writes zeros from the end of file to len, if len is greater than EOF.
603 Used only by strict_sync.
604 Returns 0 on success, -1 on failure.
605 ****************************************************************************/
607 static char *sparse_buf;
608 #define SPARSE_BUF_WRITE_SIZE (32*1024)
610 int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len)
619 release_level_2_oplocks_on_change(fsp);
620 ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st);
625 if (len <= st.st_size) {
629 DEBUG(10,("vfs_fill_sparse: write zeros in file %s from len %.0f to len %.0f (%.0f bytes)\n",
630 fsp->fsp_name, (double)st.st_size, (double)len, (double)(len - st.st_size)));
632 flush_write_cache(fsp, SIZECHANGE_FLUSH);
635 sparse_buf = SMB_CALLOC_ARRAY(char, SPARSE_BUF_WRITE_SIZE);
643 num_to_write = len - st.st_size;
646 while (total < num_to_write) {
647 size_t curr_write_size = MIN(SPARSE_BUF_WRITE_SIZE, (num_to_write - total));
649 pwrite_ret = SMB_VFS_PWRITE(fsp, fsp->fh->fd, sparse_buf, curr_write_size, offset + total);
650 if (pwrite_ret == -1) {
651 DEBUG(10,("vfs_fill_sparse: SMB_VFS_PWRITE for file %s failed with error %s\n",
652 fsp->fsp_name, strerror(errno) ));
655 if (pwrite_ret == 0) {
662 set_filelen_write_cache(fsp, len);
666 /****************************************************************************
667 Transfer some data (n bytes) between two file_struct's.
668 ****************************************************************************/
670 static files_struct *in_fsp;
671 static files_struct *out_fsp;
673 static ssize_t read_fn(int fd, void *buf, size_t len)
675 return SMB_VFS_READ(in_fsp, fd, buf, len);
678 static ssize_t write_fn(int fd, const void *buf, size_t len)
680 return SMB_VFS_WRITE(out_fsp, fd, buf, len);
683 SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n)
688 return transfer_file_internal(in_fsp->fh->fd, out_fsp->fh->fd, n, read_fn, write_fn);
691 /*******************************************************************
692 A vfs_readdir wrapper which just returns the file name.
693 ********************************************************************/
695 char *vfs_readdirname(connection_struct *conn, void *p)
697 SMB_STRUCT_DIRENT *ptr= NULL;
703 ptr = SMB_VFS_READDIR(conn,p);
714 #ifdef HAVE_BROKEN_READDIR
715 /* using /usr/ucb/cc is BAD */
722 /*******************************************************************
723 A wrapper for vfs_chdir().
724 ********************************************************************/
726 int vfs_ChDir(connection_struct *conn, const char *path)
729 static pstring LastDir="";
731 if (strcsequal(path,"."))
734 if (*path == '/' && strcsequal(LastDir,path))
737 DEBUG(4,("vfs_ChDir to %s\n",path));
739 res = SMB_VFS_CHDIR(conn,path);
741 pstrcpy(LastDir,path);
745 /* number of list structures for a caching GetWd function. */
746 #define MAX_GETWDCACHE (50)
749 SMB_DEV_T dev; /* These *must* be compatible with the types returned in a stat() call. */
750 SMB_INO_T inode; /* These *must* be compatible with the types returned in a stat() call. */
751 char *dos_path; /* The pathname in DOS format. */
753 } ino_list[MAX_GETWDCACHE];
755 extern BOOL use_getwd_cache;
757 /****************************************************************************
758 Prompte a ptr (to make it recently used)
759 ****************************************************************************/
761 static void array_promote(char *array,int elsize,int element)
767 p = (char *)SMB_MALLOC(elsize);
770 DEBUG(5,("array_promote: malloc fail\n"));
774 memcpy(p,array + element * elsize, elsize);
775 memmove(array + elsize,array,elsize*element);
776 memcpy(array,p,elsize);
780 /*******************************************************************
781 Return the absolute current directory path - given a UNIX pathname.
782 Note that this path is returned in DOS format, not UNIX
783 format. Note this can be called with conn == NULL.
784 ********************************************************************/
786 char *vfs_GetWd(connection_struct *conn, char *path)
789 static BOOL getwd_cache_init = False;
790 SMB_STRUCT_STAT st, st2;
795 if (!use_getwd_cache)
796 return(SMB_VFS_GETWD(conn,path));
799 if (!getwd_cache_init) {
800 getwd_cache_init = True;
801 for (i=0;i<MAX_GETWDCACHE;i++) {
802 string_set(&ino_list[i].dos_path,"");
803 ino_list[i].valid = False;
807 /* Get the inode of the current directory, if this doesn't work we're
810 if (SMB_VFS_STAT(conn, ".",&st) == -1) {
811 /* Known to fail for root: the directory may be
812 * NFS-mounted and exported with root_squash (so has no root access). */
813 DEBUG(1,("vfs_GetWd: couldn't stat \".\" path=%s error %s (NFS problem ?)\n", path, strerror(errno) ));
814 return(SMB_VFS_GETWD(conn,path));
818 for (i=0; i<MAX_GETWDCACHE; i++) {
819 if (ino_list[i].valid) {
821 /* If we have found an entry with a matching inode and dev number
822 then find the inode number for the directory in the cached string.
823 If this agrees with that returned by the stat for the current
824 directory then all is o.k. (but make sure it is a directory all
827 if (st.st_ino == ino_list[i].inode && st.st_dev == ino_list[i].dev) {
828 if (SMB_VFS_STAT(conn,ino_list[i].dos_path,&st2) == 0) {
829 if (st.st_ino == st2.st_ino && st.st_dev == st2.st_dev &&
830 (st2.st_mode & S_IFMT) == S_IFDIR) {
831 pstrcpy (path, ino_list[i].dos_path);
833 /* promote it for future use */
834 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
837 /* If the inode is different then something's changed,
838 scrub the entry and start from scratch. */
839 ino_list[i].valid = False;
846 /* We don't have the information to hand so rely on traditional methods.
847 The very slow getcwd, which spawns a process on some systems, or the
848 not quite so bad getwd. */
850 if (!SMB_VFS_GETWD(conn,s)) {
851 DEBUG(0,("vfs_GetWd: SMB_VFS_GETWD call failed, errno %s\n",strerror(errno)));
857 DEBUG(5,("vfs_GetWd %s, inode %.0f, dev %.0f\n",s,(double)st.st_ino,(double)st.st_dev));
859 /* add it to the cache */
860 i = MAX_GETWDCACHE - 1;
861 string_set(&ino_list[i].dos_path,s);
862 ino_list[i].dev = st.st_dev;
863 ino_list[i].inode = st.st_ino;
864 ino_list[i].valid = True;
866 /* put it at the top of the list */
867 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
872 BOOL canonicalize_path(connection_struct *conn, pstring path)
874 #ifdef REALPATH_TAKES_NULL
875 char *resolved_name = SMB_VFS_REALPATH(conn,path,NULL);
876 if (!resolved_name) {
879 pstrcpy(path, resolved_name);
880 SAFE_FREE(resolved_name);
884 char resolved_name_buf[PATH_MAX+1];
886 pstring resolved_name_buf;
888 char *resolved_name = SMB_VFS_REALPATH(conn,path,resolved_name_buf);
889 if (!resolved_name) {
892 pstrcpy(path, resolved_name);
894 #endif /* REALPATH_TAKES_NULL */
897 /*******************************************************************
898 Reduce a file name, removing .. elements and checking that
899 it is below dir in the heirachy. This uses realpath.
900 ********************************************************************/
902 BOOL reduce_name(connection_struct *conn, const pstring fname)
904 #ifdef REALPATH_TAKES_NULL
905 BOOL free_resolved_name = True;
908 char resolved_name_buf[PATH_MAX+1];
910 pstring resolved_name_buf;
912 BOOL free_resolved_name = False;
914 char *resolved_name = NULL;
915 size_t con_path_len = strlen(conn->connectpath);
917 int saved_errno = errno;
919 DEBUG(3,("reduce_name [%s] [%s]\n", fname, conn->connectpath));
921 #ifdef REALPATH_TAKES_NULL
922 resolved_name = SMB_VFS_REALPATH(conn,fname,NULL);
924 resolved_name = SMB_VFS_REALPATH(conn,fname,resolved_name_buf);
927 if (!resolved_name) {
930 DEBUG(3,("reduce_name: Component not a directory in getting realpath for %s\n", fname));
936 fstring last_component;
937 /* Last component didn't exist. Remove it and try and canonicalise the directory. */
939 pstrcpy(tmp_fname, fname);
940 p = strrchr_m(tmp_fname, '/');
943 fstrcpy(last_component, p);
945 fstrcpy(last_component, tmp_fname);
946 pstrcpy(tmp_fname, ".");
949 #ifdef REALPATH_TAKES_NULL
950 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,NULL);
952 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,resolved_name_buf);
954 if (!resolved_name) {
955 DEBUG(3,("reduce_name: couldn't get realpath for %s\n", fname));
959 pstrcpy(tmp_fname, resolved_name);
960 pstrcat(tmp_fname, "/");
961 pstrcat(tmp_fname, last_component);
962 #ifdef REALPATH_TAKES_NULL
963 SAFE_FREE(resolved_name);
964 resolved_name = SMB_STRDUP(tmp_fname);
965 if (!resolved_name) {
966 DEBUG(0,("reduce_name: malloc fail for %s\n", tmp_fname));
972 safe_strcpy(resolved_name_buf, tmp_fname, PATH_MAX);
974 pstrcpy(resolved_name_buf, tmp_fname);
976 resolved_name = resolved_name_buf;
981 DEBUG(1,("reduce_name: couldn't get realpath for %s\n", fname));
982 /* Don't restore the saved errno. We need to return the error that
983 realpath caused here as it was not one of the cases we handle. JRA. */
988 DEBUG(10,("reduce_name realpath [%s] -> [%s]\n", fname, resolved_name));
990 if (*resolved_name != '/') {
991 DEBUG(0,("reduce_name: realpath doesn't return absolute paths !\n"));
992 if (free_resolved_name)
993 SAFE_FREE(resolved_name);
998 /* Check for widelinks allowed. */
999 if (!lp_widelinks(SNUM(conn)) && (strncmp(conn->connectpath, resolved_name, con_path_len) != 0)) {
1000 DEBUG(2, ("reduce_name: Bad access attempt: %s is a symlink outside the share path", fname));
1001 if (free_resolved_name)
1002 SAFE_FREE(resolved_name);
1007 /* Check if we are allowing users to follow symlinks */
1008 /* Patch from David Clerc <David.Clerc@cui.unige.ch>
1009 University of Geneva */
1012 if (!lp_symlinks(SNUM(conn))) {
1013 SMB_STRUCT_STAT statbuf;
1014 if ( (SMB_VFS_LSTAT(conn,fname,&statbuf) != -1) &&
1015 (S_ISLNK(statbuf.st_mode)) ) {
1016 if (free_resolved_name)
1017 SAFE_FREE(resolved_name);
1018 DEBUG(3,("reduce_name: denied: file path name %s is a symlink\n",resolved_name));
1025 DEBUG(3,("reduce_name: %s reduced to %s\n", fname, resolved_name));
1026 if (free_resolved_name)
1027 SAFE_FREE(resolved_name);
1028 errno = saved_errno;