2 Unix SMB/Netbios implementation.
4 VFS initialisation and support functions
5 Copyright (C) Tim Potter 1999
6 Copyright (C) Alexander Bokovoy 2002
7 Copyright (C) James Peach 2006
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 This work was sponsored by Optifacio Software Services, Inc.
29 #define DBGC_CLASS DBGC_VFS
33 struct vfs_init_function_entry {
35 vfs_op_tuple *vfs_op_tuples;
36 struct vfs_init_function_entry *prev, *next;
39 static struct vfs_init_function_entry *backends = NULL;
41 /****************************************************************************
42 maintain the list of available backends
43 ****************************************************************************/
45 static struct vfs_init_function_entry *vfs_find_backend_entry(const char *name)
47 struct vfs_init_function_entry *entry = backends;
50 if (strcmp(entry->name, name)==0) return entry;
57 NTSTATUS smb_register_vfs(int version, const char *name, vfs_op_tuple *vfs_op_tuples)
59 struct vfs_init_function_entry *entry = backends;
61 if ((version != SMB_VFS_INTERFACE_VERSION)) {
62 DEBUG(0, ("Failed to register vfs module.\n"
63 "The module was compiled against SMB_VFS_INTERFACE_VERSION %d,\n"
64 "current SMB_VFS_INTERFACE_VERSION is %d.\n"
65 "Please recompile against the current Samba Version!\n",
66 version, SMB_VFS_INTERFACE_VERSION));
67 return NT_STATUS_OBJECT_TYPE_MISMATCH;
70 if (!name || !name[0] || !vfs_op_tuples) {
71 DEBUG(0,("smb_register_vfs() called with NULL pointer or empty name!\n"));
72 return NT_STATUS_INVALID_PARAMETER;
75 if (vfs_find_backend_entry(name)) {
76 DEBUG(0,("VFS module %s already loaded!\n", name));
77 return NT_STATUS_OBJECT_NAME_COLLISION;
80 entry = SMB_XMALLOC_P(struct vfs_init_function_entry);
81 entry->name = smb_xstrdup(name);
82 entry->vfs_op_tuples = vfs_op_tuples;
84 DLIST_ADD(backends, entry);
85 DEBUG(5, ("Successfully added vfs backend '%s'\n", name));
89 /****************************************************************************
90 initialise default vfs hooks
91 ****************************************************************************/
93 static void vfs_init_default(connection_struct *conn)
95 DEBUG(3, ("Initialising default vfs hooks\n"));
96 vfs_init_custom(conn, DEFAULT_VFS_MODULE_NAME);
99 /****************************************************************************
100 initialise custom vfs hooks
101 ****************************************************************************/
103 static inline void vfs_set_operation(struct vfs_ops * vfs, vfs_op_type which,
104 struct vfs_handle_struct * handle, void * op)
106 ((struct vfs_handle_struct **)&vfs->handles)[which] = handle;
107 ((void **)(void *)&vfs->ops)[which] = op;
110 BOOL vfs_init_custom(connection_struct *conn, const char *vfs_object)
113 char *module_name = NULL;
114 char *module_param = NULL, *p;
116 vfs_handle_struct *handle;
117 struct vfs_init_function_entry *entry;
119 if (!conn||!vfs_object||!vfs_object[0]) {
120 DEBUG(0,("vfs_init_custon() called with NULL pointer or emtpy vfs_object!\n"));
128 DEBUG(3, ("Initialising custom vfs hooks from [%s]\n", vfs_object));
130 module_name = smb_xstrdup(vfs_object);
132 p = strchr_m(module_name, ':');
137 trim_char(module_param, ' ', ' ');
140 trim_char(module_name, ' ', ' ');
142 /* First, try to load the module with the new module system */
143 if((entry = vfs_find_backend_entry(module_name)) ||
144 (NT_STATUS_IS_OK(smb_probe_module("vfs", module_name)) &&
145 (entry = vfs_find_backend_entry(module_name)))) {
147 DEBUGADD(5,("Successfully loaded vfs module [%s] with the new modules system\n", vfs_object));
149 if ((ops = entry->vfs_op_tuples) == NULL) {
150 DEBUG(0, ("entry->vfs_op_tuples==NULL for [%s] failed\n", vfs_object));
151 SAFE_FREE(module_name);
155 DEBUG(0,("Can't find a vfs module [%s]\n",vfs_object));
156 SAFE_FREE(module_name);
160 handle = TALLOC_ZERO_P(conn->mem_ctx,vfs_handle_struct);
162 DEBUG(0,("talloc_zero() failed!\n"));
163 SAFE_FREE(module_name);
166 memcpy(&handle->vfs_next, &conn->vfs, sizeof(struct vfs_ops));
169 handle->param = talloc_strdup(conn->mem_ctx, module_param);
171 DLIST_ADD(conn->vfs_handles, handle);
173 for(i=0; ops[i].op != NULL; i++) {
174 DEBUG(5, ("Checking operation #%d (type %d, layer %d)\n", i, ops[i].type, ops[i].layer));
175 if(ops[i].layer == SMB_VFS_LAYER_OPAQUE) {
176 /* If this operation was already made opaque by different module, it
177 * will be overridded here.
179 DEBUGADD(5, ("Making operation type %d opaque [module %s]\n", ops[i].type, vfs_object));
180 vfs_set_operation(&conn->vfs_opaque, ops[i].type, handle, ops[i].op);
182 /* Change current VFS disposition*/
183 DEBUGADD(5, ("Accepting operation type %d from module %s\n", ops[i].type, vfs_object));
184 vfs_set_operation(&conn->vfs, ops[i].type, handle, ops[i].op);
187 SAFE_FREE(module_name);
191 /*****************************************************************
192 Allow VFS modules to extend files_struct with VFS-specific state.
193 This will be ok for small numbers of extensions, but might need to
194 be refactored if it becomes more widely used.
195 ******************************************************************/
197 #define EXT_DATA_AREA(e) ((uint8 *)(e) + sizeof(struct vfs_fsp_data))
199 void *vfs_add_fsp_extension_notype(vfs_handle_struct *handle, files_struct *fsp, size_t ext_size)
201 struct vfs_fsp_data *ext;
204 /* Prevent VFS modules adding multiple extensions. */
205 if ((ext_data = vfs_fetch_fsp_extension(handle, fsp))) {
209 ext = (struct vfs_fsp_data *)TALLOC_ZERO(
210 handle->conn->mem_ctx, sizeof(struct vfs_fsp_data) + ext_size);
216 ext->next = fsp->vfs_extension;
217 fsp->vfs_extension = ext;
218 return EXT_DATA_AREA(ext);
221 void vfs_remove_fsp_extension(vfs_handle_struct *handle, files_struct *fsp)
223 struct vfs_fsp_data *curr;
224 struct vfs_fsp_data *prev;
226 for (curr = fsp->vfs_extension, prev = NULL;
228 prev = curr, curr = curr->next) {
229 if (curr->owner == handle) {
231 prev->next = curr->next;
233 fsp->vfs_extension = curr->next;
241 void *vfs_fetch_fsp_extension(vfs_handle_struct *handle, files_struct *fsp)
243 struct vfs_fsp_data *head;
245 for (head = fsp->vfs_extension; head; head = head->next) {
246 if (head->owner == handle) {
247 return EXT_DATA_AREA(head);
256 /*****************************************************************
258 ******************************************************************/
260 BOOL smbd_vfs_init(connection_struct *conn)
262 const char **vfs_objects;
266 /* Normal share - initialise with disk access functions */
267 vfs_init_default(conn);
268 vfs_objects = lp_vfs_objects(SNUM(conn));
270 /* Override VFS functions if 'vfs object' was not specified*/
271 if (!vfs_objects || !vfs_objects[0])
274 for (i=0; vfs_objects[i] ;) {
278 for (j=i-1; j >= 0; j--) {
279 if (!vfs_init_custom(conn, vfs_objects[j])) {
280 DEBUG(0, ("smbd_vfs_init: vfs_init_custom failed for %s\n", vfs_objects[j]));
287 /*******************************************************************
288 Check if directory exists.
289 ********************************************************************/
291 BOOL vfs_directory_exist(connection_struct *conn, const char *dname, SMB_STRUCT_STAT *st)
299 if (SMB_VFS_STAT(conn,dname,st) != 0)
302 ret = S_ISDIR(st->st_mode);
309 /*******************************************************************
311 ********************************************************************/
313 int vfs_MkDir(connection_struct *conn, const char *name, mode_t mode)
316 SMB_STRUCT_STAT sbuf;
318 if ((ret=SMB_VFS_MKDIR(conn, name, mode)) != 0) {
322 if (lp_inherit_perms(SNUM(conn))) {
323 inherit_access_acl(conn, name, mode);
327 * Check if high bits should have been set,
328 * then (if bits are missing): add them.
329 * Consider bits automagically set by UNIX, i.e. SGID bit from parent
332 if (mode & ~(S_IRWXU|S_IRWXG|S_IRWXO)
333 && (SMB_VFS_STAT(conn,name,&sbuf) == 0)
334 && (mode & ~sbuf.st_mode)) {
335 SMB_VFS_CHMOD(conn,name,sbuf.st_mode | (mode & ~sbuf.st_mode));
340 /*******************************************************************
341 Check if an object exists in the vfs.
342 ********************************************************************/
344 BOOL vfs_object_exist(connection_struct *conn,const char *fname,SMB_STRUCT_STAT *sbuf)
353 if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
358 /*******************************************************************
359 Check if a file exists in the vfs.
360 ********************************************************************/
362 BOOL vfs_file_exist(connection_struct *conn, const char *fname,SMB_STRUCT_STAT *sbuf)
371 if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
373 return(S_ISREG(sbuf->st_mode));
376 /****************************************************************************
377 Read data from fsp on the vfs. (note: EINTR re-read differs from vfs_write_data)
378 ****************************************************************************/
380 ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count)
384 while (total < byte_count)
386 ssize_t ret = SMB_VFS_READ(fsp, fsp->fh->fd, buf + total,
389 if (ret == 0) return total;
398 return (ssize_t)total;
401 ssize_t vfs_pread_data(files_struct *fsp, char *buf,
402 size_t byte_count, SMB_OFF_T offset)
406 while (total < byte_count)
408 ssize_t ret = SMB_VFS_PREAD(fsp, fsp->fh->fd, buf + total,
409 byte_count - total, offset + total);
411 if (ret == 0) return total;
420 return (ssize_t)total;
423 /****************************************************************************
424 Write data to a fd on the vfs.
425 ****************************************************************************/
427 ssize_t vfs_write_data(files_struct *fsp,const char *buffer,size_t N)
433 ret = SMB_VFS_WRITE(fsp,fsp->fh->fd,buffer + total,N - total);
442 return (ssize_t)total;
445 ssize_t vfs_pwrite_data(files_struct *fsp,const char *buffer,
446 size_t N, SMB_OFF_T offset)
452 ret = SMB_VFS_PWRITE(fsp, fsp->fh->fd, buffer + total,
453 N - total, offset + total);
462 return (ssize_t)total;
464 /****************************************************************************
465 An allocate file space call using the vfs interface.
466 Allocates space for a file from a filedescriptor.
467 Returns 0 on success, -1 on failure.
468 ****************************************************************************/
470 int vfs_allocate_file_space(files_struct *fsp, SMB_BIG_UINT len)
474 connection_struct *conn = fsp->conn;
475 SMB_BIG_UINT space_avail;
476 SMB_BIG_UINT bsize,dfree,dsize;
478 release_level_2_oplocks_on_change(fsp);
481 * Actually try and commit the space on disk....
484 DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", fsp->fsp_name, (double)len ));
486 if (((SMB_OFF_T)len) < 0) {
487 DEBUG(0,("vfs_allocate_file_space: %s negative len requested.\n", fsp->fsp_name ));
491 ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st);
495 if (len == (SMB_BIG_UINT)st.st_size)
498 if (len < (SMB_BIG_UINT)st.st_size) {
499 /* Shrink - use ftruncate. */
501 DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
502 fsp->fsp_name, (double)st.st_size ));
504 flush_write_cache(fsp, SIZECHANGE_FLUSH);
505 if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, (SMB_OFF_T)len)) != -1) {
506 set_filelen_write_cache(fsp, len);
511 /* Grow - we need to test if we have enough space. */
513 if (!lp_strict_allocate(SNUM(fsp->conn)))
517 len /= 1024; /* Len is now number of 1k blocks needed. */
518 space_avail = get_dfree_info(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize);
519 if (space_avail == (SMB_BIG_UINT)-1) {
523 DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %.0f, space avail = %.0f\n",
524 fsp->fsp_name, (double)st.st_size, (double)len, (double)space_avail ));
526 if (len > space_avail) {
534 /****************************************************************************
535 A vfs set_filelen call.
536 set the length of a file from a filedescriptor.
537 Returns 0 on success, -1 on failure.
538 ****************************************************************************/
540 int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
544 release_level_2_oplocks_on_change(fsp);
545 DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len));
546 flush_write_cache(fsp, SIZECHANGE_FLUSH);
547 if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, len)) != -1)
548 set_filelen_write_cache(fsp, len);
553 /****************************************************************************
554 A vfs fill sparse call.
555 Writes zeros from the end of file to len, if len is greater than EOF.
556 Used only by strict_sync.
557 Returns 0 on success, -1 on failure.
558 ****************************************************************************/
560 static char *sparse_buf;
561 #define SPARSE_BUF_WRITE_SIZE (32*1024)
563 int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len)
572 release_level_2_oplocks_on_change(fsp);
573 ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st);
578 if (len <= st.st_size) {
582 DEBUG(10,("vfs_fill_sparse: write zeros in file %s from len %.0f to len %.0f (%.0f bytes)\n",
583 fsp->fsp_name, (double)st.st_size, (double)len, (double)(len - st.st_size)));
585 flush_write_cache(fsp, SIZECHANGE_FLUSH);
588 sparse_buf = SMB_CALLOC_ARRAY(char, SPARSE_BUF_WRITE_SIZE);
596 num_to_write = len - st.st_size;
599 while (total < num_to_write) {
600 size_t curr_write_size = MIN(SPARSE_BUF_WRITE_SIZE, (num_to_write - total));
602 pwrite_ret = SMB_VFS_PWRITE(fsp, fsp->fh->fd, sparse_buf, curr_write_size, offset + total);
603 if (pwrite_ret == -1) {
604 DEBUG(10,("vfs_fill_sparse: SMB_VFS_PWRITE for file %s failed with error %s\n",
605 fsp->fsp_name, strerror(errno) ));
608 if (pwrite_ret == 0) {
615 set_filelen_write_cache(fsp, len);
619 /****************************************************************************
620 Transfer some data (n bytes) between two file_struct's.
621 ****************************************************************************/
623 static files_struct *in_fsp;
624 static files_struct *out_fsp;
626 static ssize_t read_fn(int fd, void *buf, size_t len)
628 return SMB_VFS_READ(in_fsp, fd, buf, len);
631 static ssize_t write_fn(int fd, const void *buf, size_t len)
633 return SMB_VFS_WRITE(out_fsp, fd, buf, len);
636 SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n)
641 return transfer_file_internal(in_fsp->fh->fd, out_fsp->fh->fd, n, read_fn, write_fn);
644 /*******************************************************************
645 A vfs_readdir wrapper which just returns the file name.
646 ********************************************************************/
648 char *vfs_readdirname(connection_struct *conn, void *p)
650 SMB_STRUCT_DIRENT *ptr= NULL;
656 ptr = SMB_VFS_READDIR(conn, (DIR *)p);
667 #ifdef HAVE_BROKEN_READDIR_NAME
668 /* using /usr/ucb/cc is BAD */
675 /*******************************************************************
676 A wrapper for vfs_chdir().
677 ********************************************************************/
679 int vfs_ChDir(connection_struct *conn, const char *path)
682 static pstring LastDir="";
684 if (strcsequal(path,"."))
687 if (*path == '/' && strcsequal(LastDir,path))
690 DEBUG(4,("vfs_ChDir to %s\n",path));
692 res = SMB_VFS_CHDIR(conn,path);
694 pstrcpy(LastDir,path);
698 /* number of list structures for a caching GetWd function. */
699 #define MAX_GETWDCACHE (50)
702 SMB_DEV_T dev; /* These *must* be compatible with the types returned in a stat() call. */
703 SMB_INO_T inode; /* These *must* be compatible with the types returned in a stat() call. */
704 char *dos_path; /* The pathname in DOS format. */
706 } ino_list[MAX_GETWDCACHE];
708 extern BOOL use_getwd_cache;
710 /****************************************************************************
711 Prompte a ptr (to make it recently used)
712 ****************************************************************************/
714 static void array_promote(char *array,int elsize,int element)
720 p = (char *)SMB_MALLOC(elsize);
723 DEBUG(5,("array_promote: malloc fail\n"));
727 memcpy(p,array + element * elsize, elsize);
728 memmove(array + elsize,array,elsize*element);
729 memcpy(array,p,elsize);
733 /*******************************************************************
734 Return the absolute current directory path - given a UNIX pathname.
735 Note that this path is returned in DOS format, not UNIX
736 format. Note this can be called with conn == NULL.
737 ********************************************************************/
739 char *vfs_GetWd(connection_struct *conn, char *path)
742 static BOOL getwd_cache_init = False;
743 SMB_STRUCT_STAT st, st2;
748 if (!use_getwd_cache)
749 return(SMB_VFS_GETWD(conn,path));
752 if (!getwd_cache_init) {
753 getwd_cache_init = True;
754 for (i=0;i<MAX_GETWDCACHE;i++) {
755 string_set(&ino_list[i].dos_path,"");
756 ino_list[i].valid = False;
760 /* Get the inode of the current directory, if this doesn't work we're
763 if (SMB_VFS_STAT(conn, ".",&st) == -1) {
764 /* Known to fail for root: the directory may be
765 * NFS-mounted and exported with root_squash (so has no root access). */
766 DEBUG(1,("vfs_GetWd: couldn't stat \".\" path=%s error %s (NFS problem ?)\n", path, strerror(errno) ));
767 return(SMB_VFS_GETWD(conn,path));
771 for (i=0; i<MAX_GETWDCACHE; i++) {
772 if (ino_list[i].valid) {
774 /* If we have found an entry with a matching inode and dev number
775 then find the inode number for the directory in the cached string.
776 If this agrees with that returned by the stat for the current
777 directory then all is o.k. (but make sure it is a directory all
780 if (st.st_ino == ino_list[i].inode && st.st_dev == ino_list[i].dev) {
781 if (SMB_VFS_STAT(conn,ino_list[i].dos_path,&st2) == 0) {
782 if (st.st_ino == st2.st_ino && st.st_dev == st2.st_dev &&
783 (st2.st_mode & S_IFMT) == S_IFDIR) {
784 pstrcpy (path, ino_list[i].dos_path);
786 /* promote it for future use */
787 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
790 /* If the inode is different then something's changed,
791 scrub the entry and start from scratch. */
792 ino_list[i].valid = False;
799 /* We don't have the information to hand so rely on traditional methods.
800 The very slow getcwd, which spawns a process on some systems, or the
801 not quite so bad getwd. */
803 if (!SMB_VFS_GETWD(conn,s)) {
804 DEBUG(0,("vfs_GetWd: SMB_VFS_GETWD call failed, errno %s\n",strerror(errno)));
810 DEBUG(5,("vfs_GetWd %s, inode %.0f, dev %.0f\n",s,(double)st.st_ino,(double)st.st_dev));
812 /* add it to the cache */
813 i = MAX_GETWDCACHE - 1;
814 string_set(&ino_list[i].dos_path,s);
815 ino_list[i].dev = st.st_dev;
816 ino_list[i].inode = st.st_ino;
817 ino_list[i].valid = True;
819 /* put it at the top of the list */
820 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
825 BOOL canonicalize_path(connection_struct *conn, pstring path)
827 #ifdef REALPATH_TAKES_NULL
828 char *resolved_name = SMB_VFS_REALPATH(conn,path,NULL);
829 if (!resolved_name) {
832 pstrcpy(path, resolved_name);
833 SAFE_FREE(resolved_name);
837 char resolved_name_buf[PATH_MAX+1];
839 pstring resolved_name_buf;
841 char *resolved_name = SMB_VFS_REALPATH(conn,path,resolved_name_buf);
842 if (!resolved_name) {
845 pstrcpy(path, resolved_name);
847 #endif /* REALPATH_TAKES_NULL */
850 /*******************************************************************
851 Reduce a file name, removing .. elements and checking that
852 it is below dir in the heirachy. This uses realpath.
853 ********************************************************************/
855 BOOL reduce_name(connection_struct *conn, const pstring fname)
857 #ifdef REALPATH_TAKES_NULL
858 BOOL free_resolved_name = True;
861 char resolved_name_buf[PATH_MAX+1];
863 pstring resolved_name_buf;
865 BOOL free_resolved_name = False;
867 char *resolved_name = NULL;
868 size_t con_path_len = strlen(conn->connectpath);
870 int saved_errno = errno;
872 DEBUG(3,("reduce_name [%s] [%s]\n", fname, conn->connectpath));
874 #ifdef REALPATH_TAKES_NULL
875 resolved_name = SMB_VFS_REALPATH(conn,fname,NULL);
877 resolved_name = SMB_VFS_REALPATH(conn,fname,resolved_name_buf);
880 if (!resolved_name) {
883 DEBUG(3,("reduce_name: Component not a directory in getting realpath for %s\n", fname));
889 fstring last_component;
890 /* Last component didn't exist. Remove it and try and canonicalise the directory. */
892 pstrcpy(tmp_fname, fname);
893 p = strrchr_m(tmp_fname, '/');
896 fstrcpy(last_component, p);
898 fstrcpy(last_component, tmp_fname);
899 pstrcpy(tmp_fname, ".");
902 #ifdef REALPATH_TAKES_NULL
903 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,NULL);
905 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,resolved_name_buf);
907 if (!resolved_name) {
908 DEBUG(3,("reduce_name: couldn't get realpath for %s\n", fname));
912 pstrcpy(tmp_fname, resolved_name);
913 pstrcat(tmp_fname, "/");
914 pstrcat(tmp_fname, last_component);
915 #ifdef REALPATH_TAKES_NULL
916 SAFE_FREE(resolved_name);
917 resolved_name = SMB_STRDUP(tmp_fname);
918 if (!resolved_name) {
919 DEBUG(0,("reduce_name: malloc fail for %s\n", tmp_fname));
925 safe_strcpy(resolved_name_buf, tmp_fname, PATH_MAX);
927 pstrcpy(resolved_name_buf, tmp_fname);
929 resolved_name = resolved_name_buf;
934 DEBUG(1,("reduce_name: couldn't get realpath for %s\n", fname));
935 /* Don't restore the saved errno. We need to return the error that
936 realpath caused here as it was not one of the cases we handle. JRA. */
941 DEBUG(10,("reduce_name realpath [%s] -> [%s]\n", fname, resolved_name));
943 if (*resolved_name != '/') {
944 DEBUG(0,("reduce_name: realpath doesn't return absolute paths !\n"));
945 if (free_resolved_name)
946 SAFE_FREE(resolved_name);
951 /* Check for widelinks allowed. */
952 if (!lp_widelinks(SNUM(conn)) && (strncmp(conn->connectpath, resolved_name, con_path_len) != 0)) {
953 DEBUG(2, ("reduce_name: Bad access attempt: %s is a symlink outside the share path", fname));
954 if (free_resolved_name)
955 SAFE_FREE(resolved_name);
960 /* Check if we are allowing users to follow symlinks */
961 /* Patch from David Clerc <David.Clerc@cui.unige.ch>
962 University of Geneva */
965 if (!lp_symlinks(SNUM(conn))) {
966 SMB_STRUCT_STAT statbuf;
967 if ( (SMB_VFS_LSTAT(conn,fname,&statbuf) != -1) &&
968 (S_ISLNK(statbuf.st_mode)) ) {
969 if (free_resolved_name)
970 SAFE_FREE(resolved_name);
971 DEBUG(3,("reduce_name: denied: file path name %s is a symlink\n",resolved_name));
978 DEBUG(3,("reduce_name: %s reduced to %s\n", fname, resolved_name));
979 if (free_resolved_name)
980 SAFE_FREE(resolved_name);