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 /*******************************************************************
310 Check if an object exists in the vfs.
311 ********************************************************************/
313 BOOL
vfs_object_exist(connection_struct
*conn
,const char *fname
,SMB_STRUCT_STAT
*sbuf
)
322 if (SMB_VFS_STAT(conn
,fname
,sbuf
) == -1)
327 /*******************************************************************
328 Check if a file exists in the vfs.
329 ********************************************************************/
331 BOOL
vfs_file_exist(connection_struct
*conn
, const char *fname
,SMB_STRUCT_STAT
*sbuf
)
340 if (SMB_VFS_STAT(conn
,fname
,sbuf
) == -1)
342 return(S_ISREG(sbuf
->st_mode
));
345 /****************************************************************************
346 Read data from fsp on the vfs. (note: EINTR re-read differs from vfs_write_data)
347 ****************************************************************************/
349 ssize_t
vfs_read_data(files_struct
*fsp
, char *buf
, size_t byte_count
)
353 while (total
< byte_count
)
355 ssize_t ret
= SMB_VFS_READ(fsp
, fsp
->fh
->fd
, buf
+ total
,
358 if (ret
== 0) return total
;
367 return (ssize_t
)total
;
370 ssize_t
vfs_pread_data(files_struct
*fsp
, char *buf
,
371 size_t byte_count
, SMB_OFF_T offset
)
375 while (total
< byte_count
)
377 ssize_t ret
= SMB_VFS_PREAD(fsp
, fsp
->fh
->fd
, buf
+ total
,
378 byte_count
- total
, offset
+ total
);
380 if (ret
== 0) return total
;
389 return (ssize_t
)total
;
392 /****************************************************************************
393 Write data to a fd on the vfs.
394 ****************************************************************************/
396 ssize_t
vfs_write_data(files_struct
*fsp
,const char *buffer
,size_t N
)
402 ret
= SMB_VFS_WRITE(fsp
,fsp
->fh
->fd
,buffer
+ total
,N
- total
);
411 return (ssize_t
)total
;
414 ssize_t
vfs_pwrite_data(files_struct
*fsp
,const char *buffer
,
415 size_t N
, SMB_OFF_T offset
)
421 ret
= SMB_VFS_PWRITE(fsp
, fsp
->fh
->fd
, buffer
+ total
,
422 N
- total
, offset
+ total
);
431 return (ssize_t
)total
;
433 /****************************************************************************
434 An allocate file space call using the vfs interface.
435 Allocates space for a file from a filedescriptor.
436 Returns 0 on success, -1 on failure.
437 ****************************************************************************/
439 int vfs_allocate_file_space(files_struct
*fsp
, SMB_BIG_UINT len
)
443 connection_struct
*conn
= fsp
->conn
;
444 SMB_BIG_UINT space_avail
;
445 SMB_BIG_UINT bsize
,dfree
,dsize
;
447 release_level_2_oplocks_on_change(fsp
);
450 * Actually try and commit the space on disk....
453 DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", fsp
->fsp_name
, (double)len
));
455 if (((SMB_OFF_T
)len
) < 0) {
456 DEBUG(0,("vfs_allocate_file_space: %s negative len requested.\n", fsp
->fsp_name
));
461 ret
= SMB_VFS_FSTAT(fsp
,fsp
->fh
->fd
,&st
);
465 if (len
== (SMB_BIG_UINT
)st
.st_size
)
468 if (len
< (SMB_BIG_UINT
)st
.st_size
) {
469 /* Shrink - use ftruncate. */
471 DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
472 fsp
->fsp_name
, (double)st
.st_size
));
474 flush_write_cache(fsp
, SIZECHANGE_FLUSH
);
475 if ((ret
= SMB_VFS_FTRUNCATE(fsp
, fsp
->fh
->fd
, (SMB_OFF_T
)len
)) != -1) {
476 set_filelen_write_cache(fsp
, len
);
481 /* Grow - we need to test if we have enough space. */
483 if (!lp_strict_allocate(SNUM(fsp
->conn
)))
487 len
/= 1024; /* Len is now number of 1k blocks needed. */
488 space_avail
= get_dfree_info(conn
,fsp
->fsp_name
,False
,&bsize
,&dfree
,&dsize
);
489 if (space_avail
== (SMB_BIG_UINT
)-1) {
493 DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %.0f, space avail = %.0f\n",
494 fsp
->fsp_name
, (double)st
.st_size
, (double)len
, (double)space_avail
));
496 if (len
> space_avail
) {
504 /****************************************************************************
505 A vfs set_filelen call.
506 set the length of a file from a filedescriptor.
507 Returns 0 on success, -1 on failure.
508 ****************************************************************************/
510 int vfs_set_filelen(files_struct
*fsp
, SMB_OFF_T len
)
514 release_level_2_oplocks_on_change(fsp
);
515 DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp
->fsp_name
, (double)len
));
516 flush_write_cache(fsp
, SIZECHANGE_FLUSH
);
517 if ((ret
= SMB_VFS_FTRUNCATE(fsp
, fsp
->fh
->fd
, len
)) != -1) {
518 set_filelen_write_cache(fsp
, len
);
519 notify_fname(fsp
->conn
, NOTIFY_ACTION_MODIFIED
,
520 FILE_NOTIFY_CHANGE_SIZE
521 | FILE_NOTIFY_CHANGE_ATTRIBUTES
,
528 /****************************************************************************
529 A vfs fill sparse call.
530 Writes zeros from the end of file to len, if len is greater than EOF.
531 Used only by strict_sync.
532 Returns 0 on success, -1 on failure.
533 ****************************************************************************/
535 static char *sparse_buf
;
536 #define SPARSE_BUF_WRITE_SIZE (32*1024)
538 int vfs_fill_sparse(files_struct
*fsp
, SMB_OFF_T len
)
547 release_level_2_oplocks_on_change(fsp
);
548 ret
= SMB_VFS_FSTAT(fsp
,fsp
->fh
->fd
,&st
);
553 if (len
<= st
.st_size
) {
557 DEBUG(10,("vfs_fill_sparse: write zeros in file %s from len %.0f to len %.0f (%.0f bytes)\n",
558 fsp
->fsp_name
, (double)st
.st_size
, (double)len
, (double)(len
- st
.st_size
)));
560 flush_write_cache(fsp
, SIZECHANGE_FLUSH
);
563 sparse_buf
= SMB_CALLOC_ARRAY(char, SPARSE_BUF_WRITE_SIZE
);
571 num_to_write
= len
- st
.st_size
;
574 while (total
< num_to_write
) {
575 size_t curr_write_size
= MIN(SPARSE_BUF_WRITE_SIZE
, (num_to_write
- total
));
577 pwrite_ret
= SMB_VFS_PWRITE(fsp
, fsp
->fh
->fd
, sparse_buf
, curr_write_size
, offset
+ total
);
578 if (pwrite_ret
== -1) {
579 DEBUG(10,("vfs_fill_sparse: SMB_VFS_PWRITE for file %s failed with error %s\n",
580 fsp
->fsp_name
, strerror(errno
) ));
583 if (pwrite_ret
== 0) {
590 set_filelen_write_cache(fsp
, len
);
594 /****************************************************************************
595 Transfer some data (n bytes) between two file_struct's.
596 ****************************************************************************/
598 static files_struct
*in_fsp
;
599 static files_struct
*out_fsp
;
601 static ssize_t
read_fn(int fd
, void *buf
, size_t len
)
603 return SMB_VFS_READ(in_fsp
, fd
, buf
, len
);
606 static ssize_t
write_fn(int fd
, const void *buf
, size_t len
)
608 return SMB_VFS_WRITE(out_fsp
, fd
, buf
, len
);
611 SMB_OFF_T
vfs_transfer_file(files_struct
*in
, files_struct
*out
, SMB_OFF_T n
)
616 return transfer_file_internal(in_fsp
->fh
->fd
, out_fsp
->fh
->fd
, n
, read_fn
, write_fn
);
619 /*******************************************************************
620 A vfs_readdir wrapper which just returns the file name.
621 ********************************************************************/
623 char *vfs_readdirname(connection_struct
*conn
, void *p
)
625 SMB_STRUCT_DIRENT
*ptr
= NULL
;
631 ptr
= SMB_VFS_READDIR(conn
, (DIR *)p
);
642 #ifdef HAVE_BROKEN_READDIR_NAME
643 /* using /usr/ucb/cc is BAD */
650 /*******************************************************************
651 A wrapper for vfs_chdir().
652 ********************************************************************/
654 int vfs_ChDir(connection_struct
*conn
, const char *path
)
657 static pstring LastDir
="";
659 if (strcsequal(path
,"."))
662 if (*path
== '/' && strcsequal(LastDir
,path
))
665 DEBUG(4,("vfs_ChDir to %s\n",path
));
667 res
= SMB_VFS_CHDIR(conn
,path
);
669 pstrcpy(LastDir
,path
);
673 /* number of list structures for a caching GetWd function. */
674 #define MAX_GETWDCACHE (50)
677 SMB_DEV_T dev
; /* These *must* be compatible with the types returned in a stat() call. */
678 SMB_INO_T inode
; /* These *must* be compatible with the types returned in a stat() call. */
679 char *dos_path
; /* The pathname in DOS format. */
681 } ino_list
[MAX_GETWDCACHE
];
683 extern BOOL use_getwd_cache
;
685 /****************************************************************************
686 Prompte a ptr (to make it recently used)
687 ****************************************************************************/
689 static void array_promote(char *array
,int elsize
,int element
)
695 p
= (char *)SMB_MALLOC(elsize
);
698 DEBUG(5,("array_promote: malloc fail\n"));
702 memcpy(p
,array
+ element
* elsize
, elsize
);
703 memmove(array
+ elsize
,array
,elsize
*element
);
704 memcpy(array
,p
,elsize
);
708 /*******************************************************************
709 Return the absolute current directory path - given a UNIX pathname.
710 Note that this path is returned in DOS format, not UNIX
711 format. Note this can be called with conn == NULL.
712 ********************************************************************/
714 char *vfs_GetWd(connection_struct
*conn
, char *path
)
717 static BOOL getwd_cache_init
= False
;
718 SMB_STRUCT_STAT st
, st2
;
723 if (!use_getwd_cache
)
724 return(SMB_VFS_GETWD(conn
,path
));
727 if (!getwd_cache_init
) {
728 getwd_cache_init
= True
;
729 for (i
=0;i
<MAX_GETWDCACHE
;i
++) {
730 string_set(&ino_list
[i
].dos_path
,"");
731 ino_list
[i
].valid
= False
;
735 /* Get the inode of the current directory, if this doesn't work we're
738 if (SMB_VFS_STAT(conn
, ".",&st
) == -1) {
739 /* Known to fail for root: the directory may be
740 * NFS-mounted and exported with root_squash (so has no root access). */
741 DEBUG(1,("vfs_GetWd: couldn't stat \".\" path=%s error %s (NFS problem ?)\n", path
, strerror(errno
) ));
742 return(SMB_VFS_GETWD(conn
,path
));
746 for (i
=0; i
<MAX_GETWDCACHE
; i
++) {
747 if (ino_list
[i
].valid
) {
749 /* If we have found an entry with a matching inode and dev number
750 then find the inode number for the directory in the cached string.
751 If this agrees with that returned by the stat for the current
752 directory then all is o.k. (but make sure it is a directory all
755 if (st
.st_ino
== ino_list
[i
].inode
&& st
.st_dev
== ino_list
[i
].dev
) {
756 if (SMB_VFS_STAT(conn
,ino_list
[i
].dos_path
,&st2
) == 0) {
757 if (st
.st_ino
== st2
.st_ino
&& st
.st_dev
== st2
.st_dev
&&
758 (st2
.st_mode
& S_IFMT
) == S_IFDIR
) {
759 pstrcpy (path
, ino_list
[i
].dos_path
);
761 /* promote it for future use */
762 array_promote((char *)&ino_list
[0],sizeof(ino_list
[0]),i
);
765 /* If the inode is different then something's changed,
766 scrub the entry and start from scratch. */
767 ino_list
[i
].valid
= False
;
774 /* We don't have the information to hand so rely on traditional methods.
775 The very slow getcwd, which spawns a process on some systems, or the
776 not quite so bad getwd. */
778 if (!SMB_VFS_GETWD(conn
,s
)) {
779 DEBUG(0,("vfs_GetWd: SMB_VFS_GETWD call failed, errno %s\n",strerror(errno
)));
785 DEBUG(5,("vfs_GetWd %s, inode %.0f, dev %.0f\n",s
,(double)st
.st_ino
,(double)st
.st_dev
));
787 /* add it to the cache */
788 i
= MAX_GETWDCACHE
- 1;
789 string_set(&ino_list
[i
].dos_path
,s
);
790 ino_list
[i
].dev
= st
.st_dev
;
791 ino_list
[i
].inode
= st
.st_ino
;
792 ino_list
[i
].valid
= True
;
794 /* put it at the top of the list */
795 array_promote((char *)&ino_list
[0],sizeof(ino_list
[0]),i
);
800 /*******************************************************************
801 Reduce a file name, removing .. elements and checking that
802 it is below dir in the heirachy. This uses realpath.
803 ********************************************************************/
805 NTSTATUS
reduce_name(connection_struct
*conn
, const pstring fname
)
807 #ifdef REALPATH_TAKES_NULL
808 BOOL free_resolved_name
= True
;
811 char resolved_name_buf
[PATH_MAX
+1];
813 pstring resolved_name_buf
;
815 BOOL free_resolved_name
= False
;
817 char *resolved_name
= NULL
;
818 size_t con_path_len
= strlen(conn
->connectpath
);
821 DEBUG(3,("reduce_name [%s] [%s]\n", fname
, conn
->connectpath
));
823 #ifdef REALPATH_TAKES_NULL
824 resolved_name
= SMB_VFS_REALPATH(conn
,fname
,NULL
);
826 resolved_name
= SMB_VFS_REALPATH(conn
,fname
,resolved_name_buf
);
829 if (!resolved_name
) {
832 DEBUG(3,("reduce_name: Component not a directory in getting realpath for %s\n", fname
));
833 return map_nt_error_from_unix(errno
);
837 fstring last_component
;
838 /* Last component didn't exist. Remove it and try and canonicalise the directory. */
840 pstrcpy(tmp_fname
, fname
);
841 p
= strrchr_m(tmp_fname
, '/');
844 fstrcpy(last_component
, p
);
846 fstrcpy(last_component
, tmp_fname
);
847 pstrcpy(tmp_fname
, ".");
850 #ifdef REALPATH_TAKES_NULL
851 resolved_name
= SMB_VFS_REALPATH(conn
,tmp_fname
,NULL
);
853 resolved_name
= SMB_VFS_REALPATH(conn
,tmp_fname
,resolved_name_buf
);
855 if (!resolved_name
) {
856 DEBUG(3,("reduce_name: couldn't get realpath for %s\n", fname
));
857 return map_nt_error_from_unix(errno
);
859 pstrcpy(tmp_fname
, resolved_name
);
860 pstrcat(tmp_fname
, "/");
861 pstrcat(tmp_fname
, last_component
);
862 #ifdef REALPATH_TAKES_NULL
863 SAFE_FREE(resolved_name
);
864 resolved_name
= SMB_STRDUP(tmp_fname
);
865 if (!resolved_name
) {
866 DEBUG(0,("reduce_name: malloc fail for %s\n", tmp_fname
));
867 return NT_STATUS_NO_MEMORY
;
871 safe_strcpy(resolved_name_buf
, tmp_fname
, PATH_MAX
);
873 pstrcpy(resolved_name_buf
, tmp_fname
);
875 resolved_name
= resolved_name_buf
;
880 DEBUG(1,("reduce_name: couldn't get realpath for %s\n", fname
));
881 return map_nt_error_from_unix(errno
);
885 DEBUG(10,("reduce_name realpath [%s] -> [%s]\n", fname
, resolved_name
));
887 if (*resolved_name
!= '/') {
888 DEBUG(0,("reduce_name: realpath doesn't return absolute paths !\n"));
889 if (free_resolved_name
) {
890 SAFE_FREE(resolved_name
);
892 return NT_STATUS_OBJECT_NAME_INVALID
;
895 /* Check for widelinks allowed. */
896 if (!lp_widelinks(SNUM(conn
)) && (strncmp(conn
->connectpath
, resolved_name
, con_path_len
) != 0)) {
897 DEBUG(2, ("reduce_name: Bad access attempt: %s is a symlink outside the share path", fname
));
898 if (free_resolved_name
) {
899 SAFE_FREE(resolved_name
);
901 return NT_STATUS_ACCESS_DENIED
;
904 /* Check if we are allowing users to follow symlinks */
905 /* Patch from David Clerc <David.Clerc@cui.unige.ch>
906 University of Geneva */
909 if (!lp_symlinks(SNUM(conn
))) {
910 SMB_STRUCT_STAT statbuf
;
911 if ( (SMB_VFS_LSTAT(conn
,fname
,&statbuf
) != -1) &&
912 (S_ISLNK(statbuf
.st_mode
)) ) {
913 if (free_resolved_name
) {
914 SAFE_FREE(resolved_name
);
916 DEBUG(3,("reduce_name: denied: file path name %s is a symlink\n",resolved_name
));
917 return NT_STATUS_ACCESS_DENIED
;
922 DEBUG(3,("reduce_name: %s reduced to %s\n", fname
, resolved_name
));
923 if (free_resolved_name
) {
924 SAFE_FREE(resolved_name
);