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**)&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 = TALLOC_ZERO(handle->conn->mem_ctx,
210
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))) {
320
inherit_access_acl(conn, name, mode);
323
* Check if high bits should have been set,
324
* then (if bits are missing): add them.
325
* Consider bits automagically set by UNIX, i.e. SGID bit from parent dir.
327
if(mode & ~(S_IRWXU|S_IRWXG|S_IRWXO) &&
328
!SMB_VFS_STAT(conn,name,&sbuf) && (mode & ~sbuf.st_mode))
329
SMB_VFS_CHMOD(conn,name,sbuf.st_mode | (mode & ~sbuf.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(files_struct *fsp,const char *buffer,size_t N)
427
ret = SMB_VFS_WRITE(fsp,fsp->fh->fd,buffer + total,N - total);
436
return (ssize_t)total;
439
ssize_t vfs_pwrite_data(files_struct *fsp,const char *buffer,
440
size_t N, SMB_OFF_T offset)
446
ret = SMB_VFS_PWRITE(fsp, fsp->fh->fd, buffer + total,
447
N - total, offset + total);
456
return (ssize_t)total;
458
/****************************************************************************
459
An allocate file space call using the vfs interface.
460
Allocates space for a file from a filedescriptor.
461
Returns 0 on success, -1 on failure.
462
****************************************************************************/
464
int vfs_allocate_file_space(files_struct *fsp, SMB_BIG_UINT len)
468
connection_struct *conn = fsp->conn;
469
SMB_BIG_UINT space_avail;
470
SMB_BIG_UINT bsize,dfree,dsize;
472
release_level_2_oplocks_on_change(fsp);
475
* Actually try and commit the space on disk....
478
DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", fsp->fsp_name, (double)len ));
480
if (((SMB_OFF_T)len) < 0) {
481
DEBUG(0,("vfs_allocate_file_space: %s negative len requested.\n", fsp->fsp_name ));
485
ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st);
489
if (len == (SMB_BIG_UINT)st.st_size)
492
if (len < (SMB_BIG_UINT)st.st_size) {
493
/* Shrink - use ftruncate. */
495
DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
496
fsp->fsp_name, (double)st.st_size ));
498
flush_write_cache(fsp, SIZECHANGE_FLUSH);
499
if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, (SMB_OFF_T)len)) != -1) {
500
set_filelen_write_cache(fsp, len);
505
/* Grow - we need to test if we have enough space. */
507
if (!lp_strict_allocate(SNUM(fsp->conn)))
511
len /= 1024; /* Len is now number of 1k blocks needed. */
512
space_avail = get_dfree_info(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize);
513
if (space_avail == (SMB_BIG_UINT)-1) {
517
DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %.0f, space avail = %.0f\n",
518
fsp->fsp_name, (double)st.st_size, (double)len, (double)space_avail ));
520
if (len > space_avail) {
528
/****************************************************************************
529
A vfs set_filelen call.
530
set the length of a file from a filedescriptor.
531
Returns 0 on success, -1 on failure.
532
****************************************************************************/
534
int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
538
release_level_2_oplocks_on_change(fsp);
539
DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len));
540
flush_write_cache(fsp, SIZECHANGE_FLUSH);
541
if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, len)) != -1)
542
set_filelen_write_cache(fsp, len);
547
/****************************************************************************
548
A vfs fill sparse call.
549
Writes zeros from the end of file to len, if len is greater than EOF.
550
Used only by strict_sync.
551
Returns 0 on success, -1 on failure.
552
****************************************************************************/
554
static char *sparse_buf;
555
#define SPARSE_BUF_WRITE_SIZE (32*1024)
557
int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len)
566
release_level_2_oplocks_on_change(fsp);
567
ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st);
572
if (len <= st.st_size) {
576
DEBUG(10,("vfs_fill_sparse: write zeros in file %s from len %.0f to len %.0f (%.0f bytes)\n",
577
fsp->fsp_name, (double)st.st_size, (double)len, (double)(len - st.st_size)));
579
flush_write_cache(fsp, SIZECHANGE_FLUSH);
582
sparse_buf = SMB_CALLOC_ARRAY(char, SPARSE_BUF_WRITE_SIZE);
590
num_to_write = len - st.st_size;
593
while (total < num_to_write) {
594
size_t curr_write_size = MIN(SPARSE_BUF_WRITE_SIZE, (num_to_write - total));
596
pwrite_ret = SMB_VFS_PWRITE(fsp, fsp->fh->fd, sparse_buf, curr_write_size, offset + total);
597
if (pwrite_ret == -1) {
598
DEBUG(10,("vfs_fill_sparse: SMB_VFS_PWRITE for file %s failed with error %s\n",
599
fsp->fsp_name, strerror(errno) ));
602
if (pwrite_ret == 0) {
609
set_filelen_write_cache(fsp, len);
613
/****************************************************************************
614
Transfer some data (n bytes) between two file_struct's.
615
****************************************************************************/
617
static files_struct *in_fsp;
618
static files_struct *out_fsp;
620
static ssize_t read_fn(int fd, void *buf, size_t len)
622
return SMB_VFS_READ(in_fsp, fd, buf, len);
625
static ssize_t write_fn(int fd, const void *buf, size_t len)
627
return SMB_VFS_WRITE(out_fsp, fd, buf, len);
630
SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n)
635
return transfer_file_internal(in_fsp->fh->fd, out_fsp->fh->fd, n, read_fn, write_fn);
638
/*******************************************************************
639
A vfs_readdir wrapper which just returns the file name.
640
********************************************************************/
642
char *vfs_readdirname(connection_struct *conn, void *p)
644
SMB_STRUCT_DIRENT *ptr= NULL;
650
ptr = SMB_VFS_READDIR(conn,p);
661
#ifdef HAVE_BROKEN_READDIR_NAME
662
/* using /usr/ucb/cc is BAD */
669
/*******************************************************************
670
A wrapper for vfs_chdir().
671
********************************************************************/
673
int vfs_ChDir(connection_struct *conn, const char *path)
676
static pstring LastDir="";
678
if (strcsequal(path,"."))
681
if (*path == '/' && strcsequal(LastDir,path))
684
DEBUG(4,("vfs_ChDir to %s\n",path));
686
res = SMB_VFS_CHDIR(conn,path);
688
pstrcpy(LastDir,path);
692
/* number of list structures for a caching GetWd function. */
693
#define MAX_GETWDCACHE (50)
696
SMB_DEV_T dev; /* These *must* be compatible with the types returned in a stat() call. */
697
SMB_INO_T inode; /* These *must* be compatible with the types returned in a stat() call. */
698
char *dos_path; /* The pathname in DOS format. */
700
} ino_list[MAX_GETWDCACHE];
702
extern BOOL use_getwd_cache;
704
/****************************************************************************
705
Prompte a ptr (to make it recently used)
706
****************************************************************************/
708
static void array_promote(char *array,int elsize,int element)
714
p = (char *)SMB_MALLOC(elsize);
717
DEBUG(5,("array_promote: malloc fail\n"));
721
memcpy(p,array + element * elsize, elsize);
722
memmove(array + elsize,array,elsize*element);
723
memcpy(array,p,elsize);
727
/*******************************************************************
728
Return the absolute current directory path - given a UNIX pathname.
729
Note that this path is returned in DOS format, not UNIX
730
format. Note this can be called with conn == NULL.
731
********************************************************************/
733
char *vfs_GetWd(connection_struct *conn, char *path)
736
static BOOL getwd_cache_init = False;
737
SMB_STRUCT_STAT st, st2;
742
if (!use_getwd_cache)
743
return(SMB_VFS_GETWD(conn,path));
746
if (!getwd_cache_init) {
747
getwd_cache_init = True;
748
for (i=0;i<MAX_GETWDCACHE;i++) {
749
string_set(&ino_list[i].dos_path,"");
750
ino_list[i].valid = False;
754
/* Get the inode of the current directory, if this doesn't work we're
757
if (SMB_VFS_STAT(conn, ".",&st) == -1) {
758
/* Known to fail for root: the directory may be
759
* NFS-mounted and exported with root_squash (so has no root access). */
760
DEBUG(1,("vfs_GetWd: couldn't stat \".\" path=%s error %s (NFS problem ?)\n", path, strerror(errno) ));
761
return(SMB_VFS_GETWD(conn,path));
765
for (i=0; i<MAX_GETWDCACHE; i++) {
766
if (ino_list[i].valid) {
768
/* If we have found an entry with a matching inode and dev number
769
then find the inode number for the directory in the cached string.
770
If this agrees with that returned by the stat for the current
771
directory then all is o.k. (but make sure it is a directory all
774
if (st.st_ino == ino_list[i].inode && st.st_dev == ino_list[i].dev) {
775
if (SMB_VFS_STAT(conn,ino_list[i].dos_path,&st2) == 0) {
776
if (st.st_ino == st2.st_ino && st.st_dev == st2.st_dev &&
777
(st2.st_mode & S_IFMT) == S_IFDIR) {
778
pstrcpy (path, ino_list[i].dos_path);
780
/* promote it for future use */
781
array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
784
/* If the inode is different then something's changed,
785
scrub the entry and start from scratch. */
786
ino_list[i].valid = False;
793
/* We don't have the information to hand so rely on traditional methods.
794
The very slow getcwd, which spawns a process on some systems, or the
795
not quite so bad getwd. */
797
if (!SMB_VFS_GETWD(conn,s)) {
798
DEBUG(0,("vfs_GetWd: SMB_VFS_GETWD call failed, errno %s\n",strerror(errno)));
804
DEBUG(5,("vfs_GetWd %s, inode %.0f, dev %.0f\n",s,(double)st.st_ino,(double)st.st_dev));
806
/* add it to the cache */
807
i = MAX_GETWDCACHE - 1;
808
string_set(&ino_list[i].dos_path,s);
809
ino_list[i].dev = st.st_dev;
810
ino_list[i].inode = st.st_ino;
811
ino_list[i].valid = True;
813
/* put it at the top of the list */
814
array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
819
BOOL canonicalize_path(connection_struct *conn, pstring path)
821
#ifdef REALPATH_TAKES_NULL
822
char *resolved_name = SMB_VFS_REALPATH(conn,path,NULL);
823
if (!resolved_name) {
826
pstrcpy(path, resolved_name);
827
SAFE_FREE(resolved_name);
831
char resolved_name_buf[PATH_MAX+1];
833
pstring resolved_name_buf;
835
char *resolved_name = SMB_VFS_REALPATH(conn,path,resolved_name_buf);
836
if (!resolved_name) {
839
pstrcpy(path, resolved_name);
841
#endif /* REALPATH_TAKES_NULL */
844
/*******************************************************************
845
Reduce a file name, removing .. elements and checking that
846
it is below dir in the heirachy. This uses realpath.
847
********************************************************************/
849
BOOL reduce_name(connection_struct *conn, const pstring fname)
851
#ifdef REALPATH_TAKES_NULL
852
BOOL free_resolved_name = True;
855
char resolved_name_buf[PATH_MAX+1];
857
pstring resolved_name_buf;
859
BOOL free_resolved_name = False;
861
char *resolved_name = NULL;
862
size_t con_path_len = strlen(conn->connectpath);
864
int saved_errno = errno;
866
DEBUG(3,("reduce_name [%s] [%s]\n", fname, conn->connectpath));
868
#ifdef REALPATH_TAKES_NULL
869
resolved_name = SMB_VFS_REALPATH(conn,fname,NULL);
871
resolved_name = SMB_VFS_REALPATH(conn,fname,resolved_name_buf);
874
if (!resolved_name) {
877
DEBUG(3,("reduce_name: Component not a directory in getting realpath for %s\n", fname));
883
fstring last_component;
884
/* Last component didn't exist. Remove it and try and canonicalise the directory. */
886
pstrcpy(tmp_fname, fname);
887
p = strrchr_m(tmp_fname, '/');
890
fstrcpy(last_component, p);
892
fstrcpy(last_component, tmp_fname);
893
pstrcpy(tmp_fname, ".");
896
#ifdef REALPATH_TAKES_NULL
897
resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,NULL);
899
resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,resolved_name_buf);
901
if (!resolved_name) {
902
DEBUG(3,("reduce_name: couldn't get realpath for %s\n", fname));
906
pstrcpy(tmp_fname, resolved_name);
907
pstrcat(tmp_fname, "/");
908
pstrcat(tmp_fname, last_component);
909
#ifdef REALPATH_TAKES_NULL
910
SAFE_FREE(resolved_name);
911
resolved_name = SMB_STRDUP(tmp_fname);
912
if (!resolved_name) {
913
DEBUG(0,("reduce_name: malloc fail for %s\n", tmp_fname));
919
safe_strcpy(resolved_name_buf, tmp_fname, PATH_MAX);
921
pstrcpy(resolved_name_buf, tmp_fname);
923
resolved_name = resolved_name_buf;
928
DEBUG(1,("reduce_name: couldn't get realpath for %s\n", fname));
929
/* Don't restore the saved errno. We need to return the error that
930
realpath caused here as it was not one of the cases we handle. JRA. */
935
DEBUG(10,("reduce_name realpath [%s] -> [%s]\n", fname, resolved_name));
937
if (*resolved_name != '/') {
938
DEBUG(0,("reduce_name: realpath doesn't return absolute paths !\n"));
939
if (free_resolved_name)
940
SAFE_FREE(resolved_name);
945
/* Check for widelinks allowed. */
946
if (!lp_widelinks(SNUM(conn)) && (strncmp(conn->connectpath, resolved_name, con_path_len) != 0)) {
947
DEBUG(2, ("reduce_name: Bad access attempt: %s is a symlink outside the share path", fname));
948
if (free_resolved_name)
949
SAFE_FREE(resolved_name);
954
/* Check if we are allowing users to follow symlinks */
955
/* Patch from David Clerc <David.Clerc@cui.unige.ch>
956
University of Geneva */
959
if (!lp_symlinks(SNUM(conn))) {
960
SMB_STRUCT_STAT statbuf;
961
if ( (SMB_VFS_LSTAT(conn,fname,&statbuf) != -1) &&
962
(S_ISLNK(statbuf.st_mode)) ) {
963
if (free_resolved_name)
964
SAFE_FREE(resolved_name);
965
DEBUG(3,("reduce_name: denied: file path name %s is a symlink\n",resolved_name));
972
DEBUG(3,("reduce_name: %s reduced to %s\n", fname, resolved_name));
973
if (free_resolved_name)
974
SAFE_FREE(resolved_name);