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 */
104 /* Windows ACL operations. */
110 /* POSIX ACL operations. */
114 vfswrap_sys_acl_get_entry,
115 vfswrap_sys_acl_get_tag_type,
116 vfswrap_sys_acl_get_permset,
117 vfswrap_sys_acl_get_qualifier,
118 vfswrap_sys_acl_get_file,
119 vfswrap_sys_acl_get_fd,
120 vfswrap_sys_acl_clear_perms,
121 vfswrap_sys_acl_add_perm,
122 vfswrap_sys_acl_to_text,
123 vfswrap_sys_acl_init,
124 vfswrap_sys_acl_create_entry,
125 vfswrap_sys_acl_set_tag_type,
126 vfswrap_sys_acl_set_qualifier,
127 vfswrap_sys_acl_set_permset,
128 vfswrap_sys_acl_valid,
129 vfswrap_sys_acl_set_file,
130 vfswrap_sys_acl_set_fd,
131 vfswrap_sys_acl_delete_def_file,
132 vfswrap_sys_acl_get_perm,
133 vfswrap_sys_acl_free_text,
134 vfswrap_sys_acl_free_acl,
135 vfswrap_sys_acl_free_qualifier,
145 vfswrap_lremovexattr,
146 vfswrap_fremovexattr,
151 /* AIO operations. */
162 /****************************************************************************
163 maintain the list of available backends
164 ****************************************************************************/
166 static struct vfs_init_function_entry *vfs_find_backend_entry(const char *name)
168 struct vfs_init_function_entry *entry = backends;
171 if (strcmp(entry->name, name)==0) return entry;
178 NTSTATUS smb_register_vfs(int version, const char *name, vfs_op_tuple *vfs_op_tuples)
180 struct vfs_init_function_entry *entry = backends;
182 if ((version != SMB_VFS_INTERFACE_VERSION)) {
183 DEBUG(0, ("Failed to register vfs module.\n"
184 "The module was compiled against SMB_VFS_INTERFACE_VERSION %d,\n"
185 "current SMB_VFS_INTERFACE_VERSION is %d.\n"
186 "Please recompile against the current Samba Version!\n",
187 version, SMB_VFS_INTERFACE_VERSION));
188 return NT_STATUS_OBJECT_TYPE_MISMATCH;
191 if (!name || !name[0] || !vfs_op_tuples) {
192 DEBUG(0,("smb_register_vfs() called with NULL pointer or empty name!\n"));
193 return NT_STATUS_INVALID_PARAMETER;
196 if (vfs_find_backend_entry(name)) {
197 DEBUG(0,("VFS module %s already loaded!\n", name));
198 return NT_STATUS_OBJECT_NAME_COLLISION;
201 entry = SMB_XMALLOC_P(struct vfs_init_function_entry);
202 entry->name = smb_xstrdup(name);
203 entry->vfs_op_tuples = vfs_op_tuples;
205 DLIST_ADD(backends, entry);
206 DEBUG(5, ("Successfully added vfs backend '%s'\n", name));
210 /****************************************************************************
211 initialise default vfs hooks
212 ****************************************************************************/
214 static void vfs_init_default(connection_struct *conn)
216 DEBUG(3, ("Initialising default vfs hooks\n"));
218 memcpy(&conn->vfs.ops, &default_vfs.ops, sizeof(default_vfs.ops));
219 memcpy(&conn->vfs_opaque.ops, &default_vfs.ops, sizeof(default_vfs.ops));
222 /****************************************************************************
223 initialise custom vfs hooks
224 ****************************************************************************/
226 BOOL vfs_init_custom(connection_struct *conn, const char *vfs_object)
229 char *module_name = NULL;
230 char *module_param = NULL, *p;
232 vfs_handle_struct *handle;
233 struct vfs_init_function_entry *entry;
235 if (!conn||!vfs_object||!vfs_object[0]) {
236 DEBUG(0,("vfs_init_custon() called with NULL pointer or emtpy vfs_object!\n"));
244 DEBUG(3, ("Initialising custom vfs hooks from [%s]\n", vfs_object));
246 module_name = smb_xstrdup(vfs_object);
248 p = strchr_m(module_name, ':');
253 trim_char(module_param, ' ', ' ');
256 trim_char(module_name, ' ', ' ');
258 /* First, try to load the module with the new module system */
259 if((entry = vfs_find_backend_entry(module_name)) ||
260 (NT_STATUS_IS_OK(smb_probe_module("vfs", module_name)) &&
261 (entry = vfs_find_backend_entry(module_name)))) {
263 DEBUGADD(5,("Successfully loaded vfs module [%s] with the new modules system\n", vfs_object));
265 if ((ops = entry->vfs_op_tuples) == NULL) {
266 DEBUG(0, ("entry->vfs_op_tuples==NULL for [%s] failed\n", vfs_object));
267 SAFE_FREE(module_name);
271 DEBUG(0,("Can't find a vfs module [%s]\n",vfs_object));
272 SAFE_FREE(module_name);
276 handle = TALLOC_ZERO_P(conn->mem_ctx,vfs_handle_struct);
278 DEBUG(0,("talloc_zero() failed!\n"));
279 SAFE_FREE(module_name);
282 memcpy(&handle->vfs_next, &conn->vfs, sizeof(struct vfs_ops));
285 handle->param = talloc_strdup(conn->mem_ctx, module_param);
287 DLIST_ADD(conn->vfs_handles, handle);
289 for(i=0; ops[i].op != NULL; i++) {
290 DEBUG(5, ("Checking operation #%d (type %d, layer %d)\n", i, ops[i].type, ops[i].layer));
291 if(ops[i].layer == SMB_VFS_LAYER_OPAQUE) {
292 /* Check whether this operation was already made opaque by different module */
293 if(((void**)&conn->vfs_opaque.ops)[ops[i].type] == ((void**)&default_vfs.ops)[ops[i].type]) {
294 /* No, it isn't overloaded yet. Overload. */
295 DEBUGADD(5, ("Making operation type %d opaque [module %s]\n", ops[i].type, vfs_object));
296 ((void**)&conn->vfs_opaque.ops)[ops[i].type] = ops[i].op;
297 ((vfs_handle_struct **)&conn->vfs_opaque.handles)[ops[i].type] = handle;
300 /* Change current VFS disposition*/
301 DEBUGADD(5, ("Accepting operation type %d from module %s\n", ops[i].type, vfs_object));
302 ((void**)&conn->vfs.ops)[ops[i].type] = ops[i].op;
303 ((vfs_handle_struct **)&conn->vfs.handles)[ops[i].type] = handle;
306 SAFE_FREE(module_name);
310 /*****************************************************************
312 ******************************************************************/
314 BOOL smbd_vfs_init(connection_struct *conn)
316 const char **vfs_objects;
320 /* Normal share - initialise with disk access functions */
321 vfs_init_default(conn);
322 vfs_objects = lp_vfs_objects(SNUM(conn));
324 /* Override VFS functions if 'vfs object' was not specified*/
325 if (!vfs_objects || !vfs_objects[0])
328 for (i=0; vfs_objects[i] ;) {
332 for (j=i-1; j >= 0; j--) {
333 if (!vfs_init_custom(conn, vfs_objects[j])) {
334 DEBUG(0, ("smbd_vfs_init: vfs_init_custom failed for %s\n", vfs_objects[j]));
341 /*******************************************************************
342 Check if directory exists.
343 ********************************************************************/
345 BOOL vfs_directory_exist(connection_struct *conn, const char *dname, SMB_STRUCT_STAT *st)
353 if (SMB_VFS_STAT(conn,dname,st) != 0)
356 ret = S_ISDIR(st->st_mode);
363 /*******************************************************************
365 ********************************************************************/
367 int vfs_MkDir(connection_struct *conn, const char *name, mode_t mode)
370 SMB_STRUCT_STAT sbuf;
372 if(!(ret=SMB_VFS_MKDIR(conn, name, mode))) {
374 inherit_access_acl(conn, name, mode);
377 * Check if high bits should have been set,
378 * then (if bits are missing): add them.
379 * Consider bits automagically set by UNIX, i.e. SGID bit from parent dir.
381 if(mode & ~(S_IRWXU|S_IRWXG|S_IRWXO) &&
382 !SMB_VFS_STAT(conn,name,&sbuf) && (mode & ~sbuf.st_mode))
383 SMB_VFS_CHMOD(conn,name,sbuf.st_mode | (mode & ~sbuf.st_mode));
388 /*******************************************************************
389 Check if an object exists in the vfs.
390 ********************************************************************/
392 BOOL vfs_object_exist(connection_struct *conn,const char *fname,SMB_STRUCT_STAT *sbuf)
401 if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
406 /*******************************************************************
407 Check if a file exists in the vfs.
408 ********************************************************************/
410 BOOL vfs_file_exist(connection_struct *conn, const char *fname,SMB_STRUCT_STAT *sbuf)
419 if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
421 return(S_ISREG(sbuf->st_mode));
424 /****************************************************************************
425 Read data from fsp on the vfs. (note: EINTR re-read differs from vfs_write_data)
426 ****************************************************************************/
428 ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count)
432 while (total < byte_count)
434 ssize_t ret = SMB_VFS_READ(fsp, fsp->fh->fd, buf + total,
437 if (ret == 0) return total;
446 return (ssize_t)total;
449 ssize_t vfs_pread_data(files_struct *fsp, char *buf,
450 size_t byte_count, SMB_OFF_T offset)
454 while (total < byte_count)
456 ssize_t ret = SMB_VFS_PREAD(fsp, fsp->fh->fd, buf + total,
457 byte_count - total, offset + total);
459 if (ret == 0) return total;
468 return (ssize_t)total;
471 /****************************************************************************
472 Write data to a fd on the vfs.
473 ****************************************************************************/
475 ssize_t vfs_write_data(files_struct *fsp,const char *buffer,size_t N)
481 ret = SMB_VFS_WRITE(fsp,fsp->fh->fd,buffer + total,N - total);
490 return (ssize_t)total;
493 ssize_t vfs_pwrite_data(files_struct *fsp,const char *buffer,
494 size_t N, SMB_OFF_T offset)
500 ret = SMB_VFS_PWRITE(fsp, fsp->fh->fd, buffer + total,
501 N - total, offset + total);
510 return (ssize_t)total;
512 /****************************************************************************
513 An allocate file space call using the vfs interface.
514 Allocates space for a file from a filedescriptor.
515 Returns 0 on success, -1 on failure.
516 ****************************************************************************/
518 int vfs_allocate_file_space(files_struct *fsp, SMB_BIG_UINT len)
522 connection_struct *conn = fsp->conn;
523 SMB_BIG_UINT space_avail;
524 SMB_BIG_UINT bsize,dfree,dsize;
526 release_level_2_oplocks_on_change(fsp);
529 * Actually try and commit the space on disk....
532 DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", fsp->fsp_name, (double)len ));
534 if (((SMB_OFF_T)len) < 0) {
535 DEBUG(0,("vfs_allocate_file_space: %s negative len requested.\n", fsp->fsp_name ));
539 ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st);
543 if (len == (SMB_BIG_UINT)st.st_size)
546 if (len < (SMB_BIG_UINT)st.st_size) {
547 /* Shrink - use ftruncate. */
549 DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
550 fsp->fsp_name, (double)st.st_size ));
552 flush_write_cache(fsp, SIZECHANGE_FLUSH);
553 if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, (SMB_OFF_T)len)) != -1) {
554 set_filelen_write_cache(fsp, len);
559 /* Grow - we need to test if we have enough space. */
561 if (!lp_strict_allocate(SNUM(fsp->conn)))
565 len /= 1024; /* Len is now number of 1k blocks needed. */
566 space_avail = get_dfree_info(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize);
567 if (space_avail == (SMB_BIG_UINT)-1) {
571 DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %.0f, space avail = %.0f\n",
572 fsp->fsp_name, (double)st.st_size, (double)len, (double)space_avail ));
574 if (len > space_avail) {
582 /****************************************************************************
583 A vfs set_filelen call.
584 set the length of a file from a filedescriptor.
585 Returns 0 on success, -1 on failure.
586 ****************************************************************************/
588 int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
592 release_level_2_oplocks_on_change(fsp);
593 DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len));
594 flush_write_cache(fsp, SIZECHANGE_FLUSH);
595 if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, len)) != -1)
596 set_filelen_write_cache(fsp, len);
601 /****************************************************************************
602 A vfs fill sparse call.
603 Writes zeros from the end of file to len, if len is greater than EOF.
604 Used only by strict_sync.
605 Returns 0 on success, -1 on failure.
606 ****************************************************************************/
608 static char *sparse_buf;
609 #define SPARSE_BUF_WRITE_SIZE (32*1024)
611 int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len)
620 release_level_2_oplocks_on_change(fsp);
621 ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st);
626 if (len <= st.st_size) {
630 DEBUG(10,("vfs_fill_sparse: write zeros in file %s from len %.0f to len %.0f (%.0f bytes)\n",
631 fsp->fsp_name, (double)st.st_size, (double)len, (double)(len - st.st_size)));
633 flush_write_cache(fsp, SIZECHANGE_FLUSH);
636 sparse_buf = SMB_CALLOC_ARRAY(char, SPARSE_BUF_WRITE_SIZE);
644 num_to_write = len - st.st_size;
647 while (total < num_to_write) {
648 size_t curr_write_size = MIN(SPARSE_BUF_WRITE_SIZE, (num_to_write - total));
650 pwrite_ret = SMB_VFS_PWRITE(fsp, fsp->fh->fd, sparse_buf, curr_write_size, offset + total);
651 if (pwrite_ret == -1) {
652 DEBUG(10,("vfs_fill_sparse: SMB_VFS_PWRITE for file %s failed with error %s\n",
653 fsp->fsp_name, strerror(errno) ));
656 if (pwrite_ret == 0) {
663 set_filelen_write_cache(fsp, len);
667 /****************************************************************************
668 Transfer some data (n bytes) between two file_struct's.
669 ****************************************************************************/
671 static files_struct *in_fsp;
672 static files_struct *out_fsp;
674 static ssize_t read_fn(int fd, void *buf, size_t len)
676 return SMB_VFS_READ(in_fsp, fd, buf, len);
679 static ssize_t write_fn(int fd, const void *buf, size_t len)
681 return SMB_VFS_WRITE(out_fsp, fd, buf, len);
684 SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n)
689 return transfer_file_internal(in_fsp->fh->fd, out_fsp->fh->fd, n, read_fn, write_fn);
692 /*******************************************************************
693 A vfs_readdir wrapper which just returns the file name.
694 ********************************************************************/
696 char *vfs_readdirname(connection_struct *conn, void *p)
698 SMB_STRUCT_DIRENT *ptr= NULL;
704 ptr = SMB_VFS_READDIR(conn,p);
715 #ifdef HAVE_BROKEN_READDIR
716 /* using /usr/ucb/cc is BAD */
723 /*******************************************************************
724 A wrapper for vfs_chdir().
725 ********************************************************************/
727 int vfs_ChDir(connection_struct *conn, const char *path)
730 static pstring LastDir="";
732 if (strcsequal(path,"."))
735 if (*path == '/' && strcsequal(LastDir,path))
738 DEBUG(4,("vfs_ChDir to %s\n",path));
740 res = SMB_VFS_CHDIR(conn,path);
742 pstrcpy(LastDir,path);
746 /* number of list structures for a caching GetWd function. */
747 #define MAX_GETWDCACHE (50)
750 SMB_DEV_T dev; /* These *must* be compatible with the types returned in a stat() call. */
751 SMB_INO_T inode; /* These *must* be compatible with the types returned in a stat() call. */
752 char *dos_path; /* The pathname in DOS format. */
754 } ino_list[MAX_GETWDCACHE];
756 extern BOOL use_getwd_cache;
758 /****************************************************************************
759 Prompte a ptr (to make it recently used)
760 ****************************************************************************/
762 static void array_promote(char *array,int elsize,int element)
768 p = (char *)SMB_MALLOC(elsize);
771 DEBUG(5,("array_promote: malloc fail\n"));
775 memcpy(p,array + element * elsize, elsize);
776 memmove(array + elsize,array,elsize*element);
777 memcpy(array,p,elsize);
781 /*******************************************************************
782 Return the absolute current directory path - given a UNIX pathname.
783 Note that this path is returned in DOS format, not UNIX
784 format. Note this can be called with conn == NULL.
785 ********************************************************************/
787 char *vfs_GetWd(connection_struct *conn, char *path)
790 static BOOL getwd_cache_init = False;
791 SMB_STRUCT_STAT st, st2;
796 if (!use_getwd_cache)
797 return(SMB_VFS_GETWD(conn,path));
800 if (!getwd_cache_init) {
801 getwd_cache_init = True;
802 for (i=0;i<MAX_GETWDCACHE;i++) {
803 string_set(&ino_list[i].dos_path,"");
804 ino_list[i].valid = False;
808 /* Get the inode of the current directory, if this doesn't work we're
811 if (SMB_VFS_STAT(conn, ".",&st) == -1) {
812 /* Known to fail for root: the directory may be
813 * NFS-mounted and exported with root_squash (so has no root access). */
814 DEBUG(1,("vfs_GetWd: couldn't stat \".\" path=%s error %s (NFS problem ?)\n", path, strerror(errno) ));
815 return(SMB_VFS_GETWD(conn,path));
819 for (i=0; i<MAX_GETWDCACHE; i++) {
820 if (ino_list[i].valid) {
822 /* If we have found an entry with a matching inode and dev number
823 then find the inode number for the directory in the cached string.
824 If this agrees with that returned by the stat for the current
825 directory then all is o.k. (but make sure it is a directory all
828 if (st.st_ino == ino_list[i].inode && st.st_dev == ino_list[i].dev) {
829 if (SMB_VFS_STAT(conn,ino_list[i].dos_path,&st2) == 0) {
830 if (st.st_ino == st2.st_ino && st.st_dev == st2.st_dev &&
831 (st2.st_mode & S_IFMT) == S_IFDIR) {
832 pstrcpy (path, ino_list[i].dos_path);
834 /* promote it for future use */
835 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
838 /* If the inode is different then something's changed,
839 scrub the entry and start from scratch. */
840 ino_list[i].valid = False;
847 /* We don't have the information to hand so rely on traditional methods.
848 The very slow getcwd, which spawns a process on some systems, or the
849 not quite so bad getwd. */
851 if (!SMB_VFS_GETWD(conn,s)) {
852 DEBUG(0,("vfs_GetWd: SMB_VFS_GETWD call failed, errno %s\n",strerror(errno)));
858 DEBUG(5,("vfs_GetWd %s, inode %.0f, dev %.0f\n",s,(double)st.st_ino,(double)st.st_dev));
860 /* add it to the cache */
861 i = MAX_GETWDCACHE - 1;
862 string_set(&ino_list[i].dos_path,s);
863 ino_list[i].dev = st.st_dev;
864 ino_list[i].inode = st.st_ino;
865 ino_list[i].valid = True;
867 /* put it at the top of the list */
868 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
873 BOOL canonicalize_path(connection_struct *conn, pstring path)
875 #ifdef REALPATH_TAKES_NULL
876 char *resolved_name = SMB_VFS_REALPATH(conn,path,NULL);
877 if (!resolved_name) {
880 pstrcpy(path, resolved_name);
881 SAFE_FREE(resolved_name);
885 char resolved_name_buf[PATH_MAX+1];
887 pstring resolved_name_buf;
889 char *resolved_name = SMB_VFS_REALPATH(conn,path,resolved_name_buf);
890 if (!resolved_name) {
893 pstrcpy(path, resolved_name);
895 #endif /* REALPATH_TAKES_NULL */
898 /*******************************************************************
899 Reduce a file name, removing .. elements and checking that
900 it is below dir in the heirachy. This uses realpath.
901 ********************************************************************/
903 BOOL reduce_name(connection_struct *conn, const pstring fname)
905 #ifdef REALPATH_TAKES_NULL
906 BOOL free_resolved_name = True;
909 char resolved_name_buf[PATH_MAX+1];
911 pstring resolved_name_buf;
913 BOOL free_resolved_name = False;
915 char *resolved_name = NULL;
916 size_t con_path_len = strlen(conn->connectpath);
918 int saved_errno = errno;
920 DEBUG(3,("reduce_name [%s] [%s]\n", fname, conn->connectpath));
922 #ifdef REALPATH_TAKES_NULL
923 resolved_name = SMB_VFS_REALPATH(conn,fname,NULL);
925 resolved_name = SMB_VFS_REALPATH(conn,fname,resolved_name_buf);
928 if (!resolved_name) {
931 DEBUG(3,("reduce_name: Component not a directory in getting realpath for %s\n", fname));
937 fstring last_component;
938 /* Last component didn't exist. Remove it and try and canonicalise the directory. */
940 pstrcpy(tmp_fname, fname);
941 p = strrchr_m(tmp_fname, '/');
944 fstrcpy(last_component, p);
946 fstrcpy(last_component, tmp_fname);
947 pstrcpy(tmp_fname, ".");
950 #ifdef REALPATH_TAKES_NULL
951 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,NULL);
953 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,resolved_name_buf);
955 if (!resolved_name) {
956 DEBUG(3,("reduce_name: couldn't get realpath for %s\n", fname));
960 pstrcpy(tmp_fname, resolved_name);
961 pstrcat(tmp_fname, "/");
962 pstrcat(tmp_fname, last_component);
963 #ifdef REALPATH_TAKES_NULL
964 SAFE_FREE(resolved_name);
965 resolved_name = SMB_STRDUP(tmp_fname);
966 if (!resolved_name) {
967 DEBUG(0,("reduce_name: malloc fail for %s\n", tmp_fname));
973 safe_strcpy(resolved_name_buf, tmp_fname, PATH_MAX);
975 pstrcpy(resolved_name_buf, tmp_fname);
977 resolved_name = resolved_name_buf;
982 DEBUG(1,("reduce_name: couldn't get realpath for %s\n", fname));
983 /* Don't restore the saved errno. We need to return the error that
984 realpath caused here as it was not one of the cases we handle. JRA. */
989 DEBUG(10,("reduce_name realpath [%s] -> [%s]\n", fname, resolved_name));
991 if (*resolved_name != '/') {
992 DEBUG(0,("reduce_name: realpath doesn't return absolute paths !\n"));
993 if (free_resolved_name)
994 SAFE_FREE(resolved_name);
999 /* Check for widelinks allowed. */
1000 if (!lp_widelinks(SNUM(conn)) && (strncmp(conn->connectpath, resolved_name, con_path_len) != 0)) {
1001 DEBUG(2, ("reduce_name: Bad access attempt: %s is a symlink outside the share path", fname));
1002 if (free_resolved_name)
1003 SAFE_FREE(resolved_name);
1008 /* Check if we are allowing users to follow symlinks */
1009 /* Patch from David Clerc <David.Clerc@cui.unige.ch>
1010 University of Geneva */
1013 if (!lp_symlinks(SNUM(conn))) {
1014 SMB_STRUCT_STAT statbuf;
1015 if ( (SMB_VFS_LSTAT(conn,fname,&statbuf) != -1) &&
1016 (S_ISLNK(statbuf.st_mode)) ) {
1017 if (free_resolved_name)
1018 SAFE_FREE(resolved_name);
1019 DEBUG(3,("reduce_name: denied: file path name %s is a symlink\n",resolved_name));
1026 DEBUG(3,("reduce_name: %s reduced to %s\n", fname, resolved_name));
1027 if (free_resolved_name)
1028 SAFE_FREE(resolved_name);
1029 errno = saved_errno;