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 3 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, see <http://www.gnu.org/licenses/>.
22 This work was sponsored by Optifacio Software Services, Inc.
28 #define DBGC_CLASS DBGC_VFS
32 struct vfs_init_function_entry {
34 vfs_op_tuple *vfs_op_tuples;
35 struct vfs_init_function_entry *prev, *next;
38 static struct vfs_init_function_entry *backends = NULL;
40 /****************************************************************************
41 maintain the list of available backends
42 ****************************************************************************/
44 static struct vfs_init_function_entry *vfs_find_backend_entry(const char *name)
46 struct vfs_init_function_entry *entry = backends;
48 DEBUG(10, ("vfs_find_backend_entry called for %s\n", name));
51 if (strcmp(entry->name, name)==0) return entry;
58 NTSTATUS smb_register_vfs(int version, const char *name, vfs_op_tuple *vfs_op_tuples)
60 struct vfs_init_function_entry *entry = backends;
62 if ((version != SMB_VFS_INTERFACE_VERSION)) {
63 DEBUG(0, ("Failed to register vfs module.\n"
64 "The module was compiled against SMB_VFS_INTERFACE_VERSION %d,\n"
65 "current SMB_VFS_INTERFACE_VERSION is %d.\n"
66 "Please recompile against the current Samba Version!\n",
67 version, SMB_VFS_INTERFACE_VERSION));
68 return NT_STATUS_OBJECT_TYPE_MISMATCH;
71 if (!name || !name[0] || !vfs_op_tuples) {
72 DEBUG(0,("smb_register_vfs() called with NULL pointer or empty name!\n"));
73 return NT_STATUS_INVALID_PARAMETER;
76 if (vfs_find_backend_entry(name)) {
77 DEBUG(0,("VFS module %s already loaded!\n", name));
78 return NT_STATUS_OBJECT_NAME_COLLISION;
81 entry = SMB_XMALLOC_P(struct vfs_init_function_entry);
82 entry->name = smb_xstrdup(name);
83 entry->vfs_op_tuples = vfs_op_tuples;
85 DLIST_ADD(backends, entry);
86 DEBUG(5, ("Successfully added vfs backend '%s'\n", name));
90 /****************************************************************************
91 initialise default vfs hooks
92 ****************************************************************************/
94 static void vfs_init_default(connection_struct *conn)
96 DEBUG(3, ("Initialising default vfs hooks\n"));
97 vfs_init_custom(conn, DEFAULT_VFS_MODULE_NAME);
100 /****************************************************************************
101 initialise custom vfs hooks
102 ****************************************************************************/
104 static inline void vfs_set_operation(struct vfs_ops * vfs, vfs_op_type which,
105 struct vfs_handle_struct * handle, void * op)
107 ((struct vfs_handle_struct **)&vfs->handles)[which] = handle;
108 ((void **)(void *)&vfs->ops)[which] = op;
111 bool vfs_init_custom(connection_struct *conn, const char *vfs_object)
114 char *module_path = NULL;
115 char *module_name = NULL;
116 char *module_param = NULL, *p;
118 vfs_handle_struct *handle;
119 struct vfs_init_function_entry *entry;
121 if (!conn||!vfs_object||!vfs_object[0]) {
122 DEBUG(0,("vfs_init_custon() called with NULL pointer or emtpy vfs_object!\n"));
130 DEBUG(3, ("Initialising custom vfs hooks from [%s]\n", vfs_object));
132 module_path = smb_xstrdup(vfs_object);
134 p = strchr_m(module_path, ':');
139 trim_char(module_param, ' ', ' ');
142 trim_char(module_path, ' ', ' ');
144 module_name = smb_xstrdup(module_path);
146 if ((module_name[0] == '/') &&
147 (strcmp(module_path, DEFAULT_VFS_MODULE_NAME) != 0)) {
150 * Extract the module name from the path. Just use the base
151 * name of the last path component.
154 SAFE_FREE(module_name);
155 module_name = smb_xstrdup(strrchr_m(module_path, '/')+1);
157 p = strchr_m(module_name, '.');
164 /* First, try to load the module with the new module system */
165 if((entry = vfs_find_backend_entry(module_name)) ||
166 (NT_STATUS_IS_OK(smb_probe_module("vfs", module_path)) &&
167 (entry = vfs_find_backend_entry(module_name)))) {
169 DEBUGADD(5,("Successfully loaded vfs module [%s] with the new modules system\n", vfs_object));
171 if ((ops = entry->vfs_op_tuples) == NULL) {
172 DEBUG(0, ("entry->vfs_op_tuples==NULL for [%s] failed\n", vfs_object));
176 DEBUG(0,("Can't find a vfs module [%s]\n",vfs_object));
180 handle = TALLOC_ZERO_P(conn->mem_ctx,vfs_handle_struct);
182 DEBUG(0,("TALLOC_ZERO() failed!\n"));
185 memcpy(&handle->vfs_next, &conn->vfs, sizeof(struct vfs_ops));
188 handle->param = talloc_strdup(conn->mem_ctx, module_param);
190 DLIST_ADD(conn->vfs_handles, handle);
192 for(i=0; ops[i].op != NULL; i++) {
193 DEBUG(5, ("Checking operation #%d (type %d, layer %d)\n", i, ops[i].type, ops[i].layer));
194 if(ops[i].layer == SMB_VFS_LAYER_OPAQUE) {
195 /* If this operation was already made opaque by different module, it
196 * will be overridden here.
198 DEBUGADD(5, ("Making operation type %d opaque [module %s]\n", ops[i].type, vfs_object));
199 vfs_set_operation(&conn->vfs_opaque, ops[i].type, handle, ops[i].op);
201 /* Change current VFS disposition*/
202 DEBUGADD(5, ("Accepting operation type %d from module %s\n", ops[i].type, vfs_object));
203 vfs_set_operation(&conn->vfs, ops[i].type, handle, ops[i].op);
206 SAFE_FREE(module_path);
207 SAFE_FREE(module_name);
211 SAFE_FREE(module_path);
212 SAFE_FREE(module_name);
216 /*****************************************************************
217 Allow VFS modules to extend files_struct with VFS-specific state.
218 This will be ok for small numbers of extensions, but might need to
219 be refactored if it becomes more widely used.
220 ******************************************************************/
222 #define EXT_DATA_AREA(e) ((uint8 *)(e) + sizeof(struct vfs_fsp_data))
224 void *vfs_add_fsp_extension_notype(vfs_handle_struct *handle, files_struct *fsp, size_t ext_size)
226 struct vfs_fsp_data *ext;
229 /* Prevent VFS modules adding multiple extensions. */
230 if ((ext_data = vfs_fetch_fsp_extension(handle, fsp))) {
234 ext = (struct vfs_fsp_data *)TALLOC_ZERO(
235 handle->conn->mem_ctx, sizeof(struct vfs_fsp_data) + ext_size);
241 ext->next = fsp->vfs_extension;
242 fsp->vfs_extension = ext;
243 return EXT_DATA_AREA(ext);
246 void vfs_remove_fsp_extension(vfs_handle_struct *handle, files_struct *fsp)
248 struct vfs_fsp_data *curr;
249 struct vfs_fsp_data *prev;
251 for (curr = fsp->vfs_extension, prev = NULL;
253 prev = curr, curr = curr->next) {
254 if (curr->owner == handle) {
256 prev->next = curr->next;
258 fsp->vfs_extension = curr->next;
266 void *vfs_fetch_fsp_extension(vfs_handle_struct *handle, files_struct *fsp)
268 struct vfs_fsp_data *head;
270 for (head = fsp->vfs_extension; head; head = head->next) {
271 if (head->owner == handle) {
272 return EXT_DATA_AREA(head);
281 /*****************************************************************
283 ******************************************************************/
285 bool smbd_vfs_init(connection_struct *conn)
287 const char **vfs_objects;
291 /* Normal share - initialise with disk access functions */
292 vfs_init_default(conn);
293 vfs_objects = lp_vfs_objects(SNUM(conn));
295 /* Override VFS functions if 'vfs object' was not specified*/
296 if (!vfs_objects || !vfs_objects[0])
299 for (i=0; vfs_objects[i] ;) {
303 for (j=i-1; j >= 0; j--) {
304 if (!vfs_init_custom(conn, vfs_objects[j])) {
305 DEBUG(0, ("smbd_vfs_init: vfs_init_custom failed for %s\n", vfs_objects[j]));
312 /*******************************************************************
313 Check if directory exists.
314 ********************************************************************/
316 bool vfs_directory_exist(connection_struct *conn, const char *dname, SMB_STRUCT_STAT *st)
324 if (SMB_VFS_STAT(conn,dname,st) != 0)
327 ret = S_ISDIR(st->st_mode);
334 /*******************************************************************
335 Check if an object exists in the vfs.
336 ********************************************************************/
338 bool vfs_object_exist(connection_struct *conn,const char *fname,SMB_STRUCT_STAT *sbuf)
347 if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
352 /*******************************************************************
353 Check if a file exists in the vfs.
354 ********************************************************************/
356 bool vfs_file_exist(connection_struct *conn, const char *fname,SMB_STRUCT_STAT *sbuf)
365 if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
367 return(S_ISREG(sbuf->st_mode));
370 /****************************************************************************
371 Read data from fsp on the vfs. (note: EINTR re-read differs from vfs_write_data)
372 ****************************************************************************/
374 ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count)
378 while (total < byte_count)
380 ssize_t ret = SMB_VFS_READ(fsp, fsp->fh->fd, buf + total,
383 if (ret == 0) return total;
392 return (ssize_t)total;
395 ssize_t vfs_pread_data(files_struct *fsp, char *buf,
396 size_t byte_count, SMB_OFF_T offset)
400 while (total < byte_count)
402 ssize_t ret = SMB_VFS_PREAD(fsp, fsp->fh->fd, buf + total,
403 byte_count - total, offset + total);
405 if (ret == 0) return total;
414 return (ssize_t)total;
417 /****************************************************************************
418 Write data to a fd on the vfs.
419 ****************************************************************************/
421 ssize_t vfs_write_data(struct smb_request *req,
429 if (req && req->unread_bytes) {
430 SMB_ASSERT(req->unread_bytes == N);
431 /* VFS_RECVFILE must drain the socket
432 * before returning. */
433 req->unread_bytes = 0;
434 return SMB_VFS_RECVFILE(smbd_server_fd(),
442 ret = SMB_VFS_WRITE(fsp,fsp->fh->fd,buffer + total,N - total);
451 return (ssize_t)total;
454 ssize_t vfs_pwrite_data(struct smb_request *req,
463 if (req && req->unread_bytes) {
464 SMB_ASSERT(req->unread_bytes == N);
465 /* VFS_RECVFILE must drain the socket
466 * before returning. */
467 req->unread_bytes = 0;
468 return SMB_VFS_RECVFILE(smbd_server_fd(),
476 ret = SMB_VFS_PWRITE(fsp, fsp->fh->fd, buffer + total,
477 N - total, offset + total);
486 return (ssize_t)total;
488 /****************************************************************************
489 An allocate file space call using the vfs interface.
490 Allocates space for a file from a filedescriptor.
491 Returns 0 on success, -1 on failure.
492 ****************************************************************************/
494 int vfs_allocate_file_space(files_struct *fsp, SMB_BIG_UINT len)
498 connection_struct *conn = fsp->conn;
499 SMB_BIG_UINT space_avail;
500 SMB_BIG_UINT bsize,dfree,dsize;
502 release_level_2_oplocks_on_change(fsp);
505 * Actually try and commit the space on disk....
508 DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", fsp->fsp_name, (double)len ));
510 if (((SMB_OFF_T)len) < 0) {
511 DEBUG(0,("vfs_allocate_file_space: %s negative len requested.\n", fsp->fsp_name ));
516 ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st);
520 if (len == (SMB_BIG_UINT)st.st_size)
523 if (len < (SMB_BIG_UINT)st.st_size) {
524 /* Shrink - use ftruncate. */
526 DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
527 fsp->fsp_name, (double)st.st_size ));
529 flush_write_cache(fsp, SIZECHANGE_FLUSH);
530 if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, (SMB_OFF_T)len)) != -1) {
531 set_filelen_write_cache(fsp, len);
536 /* Grow - we need to test if we have enough space. */
538 if (!lp_strict_allocate(SNUM(fsp->conn)))
542 len /= 1024; /* Len is now number of 1k blocks needed. */
543 space_avail = get_dfree_info(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize);
544 if (space_avail == (SMB_BIG_UINT)-1) {
548 DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %.0f, space avail = %.0f\n",
549 fsp->fsp_name, (double)st.st_size, (double)len, (double)space_avail ));
551 if (len > space_avail) {
559 /****************************************************************************
560 A vfs set_filelen call.
561 set the length of a file from a filedescriptor.
562 Returns 0 on success, -1 on failure.
563 ****************************************************************************/
565 int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
569 release_level_2_oplocks_on_change(fsp);
570 DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len));
571 flush_write_cache(fsp, SIZECHANGE_FLUSH);
572 if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, len)) != -1) {
573 set_filelen_write_cache(fsp, len);
574 notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED,
575 FILE_NOTIFY_CHANGE_SIZE
576 | FILE_NOTIFY_CHANGE_ATTRIBUTES,
583 /****************************************************************************
584 A vfs fill sparse call.
585 Writes zeros from the end of file to len, if len is greater than EOF.
586 Used only by strict_sync.
587 Returns 0 on success, -1 on failure.
588 ****************************************************************************/
590 static char *sparse_buf;
591 #define SPARSE_BUF_WRITE_SIZE (32*1024)
593 int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len)
602 release_level_2_oplocks_on_change(fsp);
603 ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st);
608 if (len <= st.st_size) {
612 DEBUG(10,("vfs_fill_sparse: write zeros in file %s from len %.0f to len %.0f (%.0f bytes)\n",
613 fsp->fsp_name, (double)st.st_size, (double)len, (double)(len - st.st_size)));
615 flush_write_cache(fsp, SIZECHANGE_FLUSH);
618 sparse_buf = SMB_CALLOC_ARRAY(char, SPARSE_BUF_WRITE_SIZE);
626 num_to_write = len - st.st_size;
629 while (total < num_to_write) {
630 size_t curr_write_size = MIN(SPARSE_BUF_WRITE_SIZE, (num_to_write - total));
632 pwrite_ret = SMB_VFS_PWRITE(fsp, fsp->fh->fd, sparse_buf, curr_write_size, offset + total);
633 if (pwrite_ret == -1) {
634 DEBUG(10,("vfs_fill_sparse: SMB_VFS_PWRITE for file %s failed with error %s\n",
635 fsp->fsp_name, strerror(errno) ));
638 if (pwrite_ret == 0) {
645 set_filelen_write_cache(fsp, len);
649 /****************************************************************************
650 Transfer some data (n bytes) between two file_struct's.
651 ****************************************************************************/
653 static files_struct *in_fsp;
654 static files_struct *out_fsp;
656 static ssize_t read_fn(int fd, void *buf, size_t len)
658 return SMB_VFS_READ(in_fsp, fd, buf, len);
661 static ssize_t write_fn(int fd, const void *buf, size_t len)
663 return SMB_VFS_WRITE(out_fsp, fd, buf, len);
666 SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n)
671 return transfer_file_internal(in_fsp->fh->fd, out_fsp->fh->fd, n, read_fn, write_fn);
674 /*******************************************************************
675 A vfs_readdir wrapper which just returns the file name.
676 ********************************************************************/
678 char *vfs_readdirname(connection_struct *conn, void *p)
680 SMB_STRUCT_DIRENT *ptr= NULL;
686 ptr = SMB_VFS_READDIR(conn, (DIR *)p);
697 #ifdef HAVE_BROKEN_READDIR_NAME
698 /* using /usr/ucb/cc is BAD */
705 /*******************************************************************
706 A wrapper for vfs_chdir().
707 ********************************************************************/
709 int vfs_ChDir(connection_struct *conn, const char *path)
712 static char *LastDir = NULL;
715 LastDir = SMB_STRDUP("");
718 if (strcsequal(path,"."))
721 if (*path == '/' && strcsequal(LastDir,path))
724 DEBUG(4,("vfs_ChDir to %s\n",path));
726 res = SMB_VFS_CHDIR(conn,path);
729 LastDir = SMB_STRDUP(path);
734 /* number of list structures for a caching GetWd function. */
735 #define MAX_GETWDCACHE (50)
738 SMB_DEV_T dev; /* These *must* be compatible with the types returned in a stat() call. */
739 SMB_INO_T inode; /* These *must* be compatible with the types returned in a stat() call. */
740 char *path; /* The pathname. */
742 } ino_list[MAX_GETWDCACHE];
744 extern bool use_getwd_cache;
746 /****************************************************************************
747 Prompte a ptr (to make it recently used)
748 ****************************************************************************/
750 static void array_promote(char *array,int elsize,int element)
756 p = (char *)SMB_MALLOC(elsize);
759 DEBUG(5,("array_promote: malloc fail\n"));
763 memcpy(p,array + element * elsize, elsize);
764 memmove(array + elsize,array,elsize*element);
765 memcpy(array,p,elsize);
769 /*******************************************************************
770 Return the absolute current directory path - given a UNIX pathname.
771 Note that this path is returned in DOS format, not UNIX
772 format. Note this can be called with conn == NULL.
773 ********************************************************************/
775 char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn)
782 static bool getwd_cache_init = False;
783 SMB_STRUCT_STAT st, st2;
789 if (!use_getwd_cache) {
791 ret = SMB_VFS_GETWD(conn,s);
793 DEBUG(0,("vfs_GetWd: SMB_VFS_GETWD call failed, "
794 "errno %s\n",strerror(errno)));
797 return talloc_strdup(ctx, ret);
801 if (!getwd_cache_init) {
802 getwd_cache_init = True;
803 for (i=0;i<MAX_GETWDCACHE;i++) {
804 string_set(&ino_list[i].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 \".\" error %s "
822 for (i=0; i<MAX_GETWDCACHE; i++) {
823 if (ino_list[i].valid) {
825 /* If we have found an entry with a matching inode and dev number
826 then find the inode number for the directory in the cached string.
827 If this agrees with that returned by the stat for the current
828 directory then all is o.k. (but make sure it is a directory all
831 if (st.st_ino == ino_list[i].inode && st.st_dev == ino_list[i].dev) {
832 if (SMB_VFS_STAT(conn,ino_list[i].path,&st2) == 0) {
833 if (st.st_ino == st2.st_ino && st.st_dev == st2.st_dev &&
834 (st2.st_mode & S_IFMT) == S_IFDIR) {
836 ret = talloc_strdup(ctx,
839 /* promote it for future use */
840 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
846 /* If the inode is different then something's changed,
847 scrub the entry and start from scratch. */
848 ino_list[i].valid = False;
855 /* We don't have the information to hand so rely on traditional
856 * methods. The very slow getcwd, which spawns a process on some
857 * systems, or the not quite so bad getwd. */
859 if (!SMB_VFS_GETWD(conn,s)) {
860 DEBUG(0,("vfs_GetWd: SMB_VFS_GETWD call failed, errno %s\n",
865 ret = talloc_strdup(ctx,s);
867 DEBUG(5,("vfs_GetWd %s, inode %.0f, dev %.0f\n",
868 s,(double)st.st_ino,(double)st.st_dev));
870 /* add it to the cache */
871 i = MAX_GETWDCACHE - 1;
872 string_set(&ino_list[i].path,s);
873 ino_list[i].dev = st.st_dev;
874 ino_list[i].inode = st.st_ino;
875 ino_list[i].valid = True;
877 /* put it at the top of the list */
878 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
886 /*******************************************************************
887 Reduce a file name, removing .. elements and checking that
888 it is below dir in the heirachy. This uses realpath.
889 ********************************************************************/
891 NTSTATUS check_reduced_name(connection_struct *conn, const char *fname)
893 #ifdef REALPATH_TAKES_NULL
894 bool free_resolved_name = True;
897 char resolved_name_buf[PATH_MAX+1];
899 pstring resolved_name_buf;
901 bool free_resolved_name = False;
903 char *resolved_name = NULL;
904 size_t con_path_len = strlen(conn->connectpath);
907 DEBUG(3,("reduce_name [%s] [%s]\n", fname, conn->connectpath));
909 #ifdef REALPATH_TAKES_NULL
910 resolved_name = SMB_VFS_REALPATH(conn,fname,NULL);
912 resolved_name = SMB_VFS_REALPATH(conn,fname,resolved_name_buf);
915 if (!resolved_name) {
918 DEBUG(3,("reduce_name: Component not a directory in getting realpath for %s\n", fname));
919 return map_nt_error_from_unix(errno);
922 TALLOC_CTX *tmp_ctx = talloc_stackframe();
923 char *tmp_fname = NULL;
924 char *last_component = NULL;
925 /* Last component didn't exist. Remove it and try and canonicalise the directory. */
927 tmp_fname = talloc_strdup(tmp_ctx, fname);
929 TALLOC_FREE(tmp_ctx);
930 return NT_STATUS_NO_MEMORY;
932 p = strrchr_m(tmp_fname, '/');
937 last_component = tmp_fname;
938 tmp_fname = talloc_strdup(tmp_ctx,
941 TALLOC_FREE(tmp_ctx);
942 return NT_STATUS_NO_MEMORY;
946 #ifdef REALPATH_TAKES_NULL
947 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,NULL);
949 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,resolved_name_buf);
951 if (!resolved_name) {
952 DEBUG(3,("reduce_name: couldn't get realpath for %s\n", fname));
953 TALLOC_FREE(tmp_ctx);
954 return map_nt_error_from_unix(errno);
956 tmp_fname = talloc_asprintf(tmp_ctx,
961 TALLOC_FREE(tmp_ctx);
962 return NT_STATUS_NO_MEMORY;
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));
969 return NT_STATUS_NO_MEMORY;
973 safe_strcpy(resolved_name_buf, tmp_fname, PATH_MAX);
975 pstrcpy(resolved_name_buf, tmp_fname);
977 resolved_name = resolved_name_buf;
979 TALLOC_FREE(tmp_ctx);
983 DEBUG(1,("reduce_name: couldn't get realpath for %s\n", fname));
984 return map_nt_error_from_unix(errno);
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);
995 return NT_STATUS_OBJECT_NAME_INVALID;
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);
1004 return NT_STATUS_ACCESS_DENIED;
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);
1019 DEBUG(3,("reduce_name: denied: file path name %s is a symlink\n",resolved_name));
1020 return NT_STATUS_ACCESS_DENIED;
1025 DEBUG(3,("reduce_name: %s reduced to %s\n", fname, resolved_name));
1026 if (free_resolved_name) {
1027 SAFE_FREE(resolved_name);
1029 return NT_STATUS_OK;