r2947: applying changes for 2.2.12
[Samba.git] / source / smbd / vfs.c
blob3d3fb9c39ef6b7e00bdb3958e832d66b2fc424dd
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
4 VFS initialisation and support functions
5 Copyright (C) Tim Potter 1999
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "includes.h"
24 /* Some structures to help us initialise the vfs operations table */
26 struct vfs_syminfo {
27 char *name;
28 void *fptr;
31 /* Default vfs hooks. WARNING: The order of these initialisers is
32 very important. They must be in the same order as defined in
33 vfs.h. Change at your own peril. */
35 struct vfs_ops default_vfs_ops = {
37 /* Disk operations */
39 vfswrap_dummy_connect,
40 vfswrap_dummy_disconnect,
41 vfswrap_disk_free,
43 /* Directory operations */
45 vfswrap_opendir,
46 vfswrap_readdir,
47 vfswrap_mkdir,
48 vfswrap_rmdir,
49 vfswrap_closedir,
51 /* File operations */
53 vfswrap_open,
54 vfswrap_close,
55 vfswrap_read,
56 vfswrap_write,
57 vfswrap_lseek,
58 vfswrap_sendfile,
59 vfswrap_rename,
60 vfswrap_fsync,
61 vfswrap_stat,
62 vfswrap_fstat,
63 vfswrap_lstat,
64 vfswrap_unlink,
65 vfswrap_chmod,
66 vfswrap_fchmod,
67 vfswrap_chown,
68 vfswrap_fchown,
69 vfswrap_chdir,
70 vfswrap_getwd,
71 vfswrap_utime,
72 vfswrap_ftruncate,
73 vfswrap_lock,
74 vfswrap_symlink,
75 vfswrap_readlink,
76 vfswrap_link,
77 vfswrap_mknod,
78 vfswrap_realpath,
80 vfswrap_fget_nt_acl,
81 vfswrap_get_nt_acl,
82 vfswrap_fset_nt_acl,
83 vfswrap_set_nt_acl,
85 /* POSIX ACL operations. */
86 #if defined(HAVE_NO_ACLS)
87 NULL,
88 NULL,
89 #else
90 vfswrap_chmod_acl,
91 vfswrap_fchmod_acl,
92 #endif
93 vfswrap_sys_acl_get_entry,
94 vfswrap_sys_acl_get_tag_type,
95 vfswrap_sys_acl_get_permset,
96 vfswrap_sys_acl_get_qualifier,
97 vfswrap_sys_acl_get_file,
98 vfswrap_sys_acl_get_fd,
99 vfswrap_sys_acl_clear_perms,
100 vfswrap_sys_acl_add_perm,
101 vfswrap_sys_acl_to_text,
102 vfswrap_sys_acl_init,
103 vfswrap_sys_acl_create_entry,
104 vfswrap_sys_acl_set_tag_type,
105 vfswrap_sys_acl_set_qualifier,
106 vfswrap_sys_acl_set_permset,
107 vfswrap_sys_acl_valid,
108 vfswrap_sys_acl_set_file,
109 vfswrap_sys_acl_set_fd,
110 vfswrap_sys_acl_delete_def_file,
111 vfswrap_sys_acl_get_perm,
112 vfswrap_sys_acl_free_text,
113 vfswrap_sys_acl_free_acl,
114 vfswrap_sys_acl_free_qualifier
117 /****************************************************************************
118 initialise default vfs hooks
119 ****************************************************************************/
121 static BOOL vfs_init_default(connection_struct *conn)
123 DEBUG(3, ("Initialising default vfs hooks\n"));
125 memcpy(&conn->vfs_ops, &default_vfs_ops, sizeof(struct vfs_ops));
126 return True;
129 /****************************************************************************
130 initialise custom vfs hooks
131 ****************************************************************************/
133 static BOOL vfs_init_custom(connection_struct *conn)
135 int vfs_version = -1;
136 struct vfs_ops *ops, *(*init_fptr)(int *, struct vfs_ops *);
138 DEBUG(3, ("Initialising custom vfs hooks from %s\n", lp_vfsobj(SNUM(conn))));
140 /* Open object file */
142 if ((conn->dl_handle = sys_dlopen(lp_vfsobj(SNUM(conn)), RTLD_NOW | RTLD_GLOBAL)) == NULL) {
143 DEBUG(0, ("Error opening %s: %s\n", lp_vfsobj(SNUM(conn)), sys_dlerror()));
144 return False;
147 /* Get handle on vfs_init() symbol */
149 init_fptr = (struct vfs_ops *(*)(int *, struct vfs_ops *))sys_dlsym(conn->dl_handle, "vfs_init");
151 if (init_fptr == NULL) {
152 DEBUG(0, ("No vfs_init() symbol found in %s\n", lp_vfsobj(SNUM(conn))));
153 return False;
156 /* Initialise vfs_ops structure */
158 conn->vfs_ops = default_vfs_ops;
160 if ((ops = init_fptr(&vfs_version, &default_vfs_ops)) == NULL) {
161 DEBUG(0, ("vfs_init function from %s failed\n", lp_vfsobj(SNUM(conn))));
162 return False;
165 if (vfs_version != SMB_VFS_INTERFACE_VERSION) {
166 DEBUG(0, ("vfs_init returned wrong interface version info (was %d, should be %d)\n",
167 vfs_version, SMB_VFS_INTERFACE_VERSION ));
168 return False;
171 if (ops != &conn->vfs_ops) {
172 memcpy(&conn->vfs_ops, ops, sizeof(struct vfs_ops));
175 return True;
178 /*****************************************************************
179 Generic VFS init.
180 ******************************************************************/
182 BOOL smbd_vfs_init(connection_struct *conn)
184 if (*lp_vfsobj(SNUM(conn))) {
185 /* Loadable object file */
187 if (!vfs_init_custom(conn)) {
188 DEBUG(0, ("smbd_vfs_init: vfs_init_custom failed\n"));
189 return False;
192 return True;
195 /* Normal share - initialise with disk access functions */
197 return vfs_init_default(conn);
200 /*******************************************************************
201 Check if directory exists.
202 ********************************************************************/
204 BOOL vfs_directory_exist(connection_struct *conn, const char *dname, SMB_STRUCT_STAT *st)
206 SMB_STRUCT_STAT st2;
207 BOOL ret;
209 if (!st)
210 st = &st2;
212 if (vfs_stat(conn,dname,st) != 0)
213 return(False);
215 ret = S_ISDIR(st->st_mode);
216 if(!ret)
217 errno = ENOTDIR;
219 return ret;
222 /*******************************************************************
223 vfs mkdir wrapper that calls dos_to_unix.
224 ********************************************************************/
226 int vfs_mkdir(connection_struct *conn, char *const fname, mode_t mode)
228 int ret;
229 pstring name;
230 SMB_STRUCT_STAT sbuf;
232 pstrcpy(name,dos_to_unix_static(fname)); /* paranoia copy */
233 if(!(ret=conn->vfs_ops.mkdir(conn,name,mode))) {
235 * Check if high bits should have been set,
236 * then (if bits are missing): add them.
237 * Consider bits automagically set by UNIX, i.e. SGID bit from parent dir.
239 if(mode & ~(S_IRWXU|S_IRWXG|S_IRWXO) &&
240 !vfs_stat(conn,name,&sbuf) && (mode & ~sbuf.st_mode))
241 vfs_chmod(conn,name,sbuf.st_mode | (mode & ~sbuf.st_mode));
243 return ret;
246 /*******************************************************************
247 vfs getwd wrapper that calls dos_to_unix.
248 ********************************************************************/
250 char *vfs_getwd(connection_struct *conn, char *unix_path)
252 char *wd;
253 wd = conn->vfs_ops.getwd(conn,unix_path);
254 if (wd)
255 unix_to_dos(wd);
256 return wd;
259 /*******************************************************************
260 Check if an object exists in the vfs.
261 ********************************************************************/
263 BOOL vfs_object_exist(connection_struct *conn, const char *fname,SMB_STRUCT_STAT *sbuf)
265 SMB_STRUCT_STAT st;
267 if (!sbuf)
268 sbuf = &st;
270 ZERO_STRUCTP(sbuf);
272 if (vfs_stat(conn,fname,sbuf) == -1)
273 return(False);
274 return True;
277 /*******************************************************************
278 Check if a file exists in the vfs.
279 ********************************************************************/
281 BOOL vfs_file_exist(connection_struct *conn, const char *fname,SMB_STRUCT_STAT *sbuf)
283 SMB_STRUCT_STAT st;
285 if (!sbuf)
286 sbuf = &st;
288 ZERO_STRUCTP(sbuf);
290 if (vfs_stat(conn,fname,sbuf) == -1)
291 return False;
292 return(S_ISREG(sbuf->st_mode));
295 /****************************************************************************
296 Read data from fsp on the vfs. (note: EINTR re-read differs from vfs_write_data)
297 ****************************************************************************/
299 ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count)
301 size_t total=0;
303 while (total < byte_count)
305 ssize_t ret = fsp->conn->vfs_ops.read(fsp, fsp->fd, buf + total,
306 byte_count - total);
308 if (ret == 0) return total;
309 if (ret == -1) {
310 if (errno == EINTR)
311 continue;
312 else
313 return -1;
315 total += ret;
317 return (ssize_t)total;
320 /****************************************************************************
321 Write data to a fd on the vfs.
322 ****************************************************************************/
324 ssize_t vfs_write_data(files_struct *fsp,const char *buffer,size_t N)
326 size_t total=0;
327 ssize_t ret;
329 while (total < N) {
330 ret = fsp->conn->vfs_ops.write(fsp,fsp->fd,buffer + total,N - total);
332 if (ret == -1)
333 return -1;
334 if (ret == 0)
335 return total;
337 total += ret;
340 return (ssize_t)total;
343 /****************************************************************************
344 An allocate file space call using the vfs interface.
345 Allocates space for a file from a filedescriptor.
346 Returns 0 on success, -1 on failure.
347 ****************************************************************************/
349 int vfs_allocate_file_space(files_struct *fsp, SMB_BIG_UINT len)
351 int ret;
352 SMB_STRUCT_STAT st;
353 connection_struct *conn = fsp->conn;
354 struct vfs_ops *vfs_ops = &conn->vfs_ops;
355 SMB_BIG_UINT space_avail;
356 SMB_BIG_UINT bsize,dfree,dsize;
358 release_level_2_oplocks_on_change(fsp);
361 * Actually try and commit the space on disk....
364 DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", fsp->fsp_name, (double)len ));
366 if (((SMB_OFF_T)len) < 0) {
367 DEBUG(0,("vfs_allocate_file_space: %s negative len requested.\n", fsp->fsp_name ));
368 return -1;
371 ret = vfs_fstat(fsp,fsp->fd,&st);
372 if (ret == -1)
373 return ret;
375 if (len == (SMB_BIG_UINT)st.st_size)
376 return 0;
378 if (len < (SMB_BIG_UINT)st.st_size) {
379 /* Shrink - use ftruncate. */
381 DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
382 fsp->fsp_name, (double)st.st_size ));
384 flush_write_cache(fsp, SIZECHANGE_FLUSH);
385 if ((ret = vfs_ops->ftruncate(fsp, fsp->fd, (SMB_OFF_T)len)) != -1) {
386 set_filelen_write_cache(fsp, len);
388 return ret;
391 /* Grow - we need to test if we have enough space. */
393 if (!lp_strict_allocate(SNUM(fsp->conn)))
394 return 0;
396 len -= st.st_size;
397 len /= 1024; /* Len is now number of 1k blocks needed. */
398 space_avail = conn->vfs_ops.disk_free(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize);
400 DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %.0f, space avail = %.0f\n",
401 fsp->fsp_name, (double)st.st_size, (double)len, (double)space_avail ));
403 if (len > space_avail) {
404 errno = ENOSPC;
405 return -1;
408 return 0;
411 /****************************************************************************
412 A vfs set_filelen call.
413 set the length of a file from a filedescriptor.
414 Returns 0 on success, -1 on failure.
415 ****************************************************************************/
417 int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
419 int ret;
421 release_level_2_oplocks_on_change(fsp);
422 DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len));
423 flush_write_cache(fsp, SIZECHANGE_FLUSH);
424 if ((ret = fsp->conn->vfs_ops.ftruncate(fsp, fsp->fd, len)) != -1)
425 set_filelen_write_cache(fsp, len);
427 return ret;
430 /****************************************************************************
431 Transfer some data (n bytes) between two file_struct's.
432 ****************************************************************************/
434 static files_struct *in_fsp;
435 static files_struct *out_fsp;
437 static ssize_t read_fn(int fd, void *buf, size_t len)
439 return in_fsp->conn->vfs_ops.read(in_fsp, fd, buf, len);
442 static ssize_t write_fn(int fd, const void *buf, size_t len)
444 return out_fsp->conn->vfs_ops.write(out_fsp, fd, buf, len);
447 SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n)
449 in_fsp = in;
450 out_fsp = out;
452 return transfer_file_internal(in_fsp->fd, out_fsp->fd, n, read_fn, write_fn);
455 /*******************************************************************
456 A vfs_readdir wrapper which just returns the file name.
457 ********************************************************************/
459 char *vfs_readdirname(connection_struct *conn, void *p)
461 struct dirent *ptr;
462 char *dname;
464 if (!p)
465 return(NULL);
467 ptr = (struct dirent *)conn->vfs_ops.readdir(conn,p);
468 if (!ptr)
469 return(NULL);
471 dname = ptr->d_name;
473 #ifdef NEXT2
474 if (telldir(p) < 0)
475 return(NULL);
476 #endif
478 #ifdef HAVE_BROKEN_READDIR
479 /* using /usr/ucb/cc is BAD */
480 dname = dname - 2;
481 #endif
484 static pstring buf;
485 memcpy(buf, dname, NAMLEN(ptr)+1);
486 unix_to_dos(buf);
487 dname = buf;
490 return(dname);
493 /* VFS options not quite working yet */
495 #if 0
497 /***************************************************************************
498 handle the interpretation of the vfs option parameter
499 *************************************************************************/
500 static BOOL handle_vfs_option(char *pszParmValue, char **ptr)
502 struct vfs_options *new_option, **options = (struct vfs_options **)ptr;
503 int i;
505 /* Create new vfs option */
507 new_option = (struct vfs_options *)malloc(sizeof(*new_option));
508 if (new_option == NULL) {
509 return False;
512 ZERO_STRUCTP(new_option);
514 /* Get name and value */
516 new_option->name = strtok(pszParmValue, "=");
518 if (new_option->name == NULL) {
519 return False;
522 while(isspace(*new_option->name)) {
523 new_option->name++;
526 for (i = strlen(new_option->name); i > 0; i--) {
527 if (!isspace(new_option->name[i - 1])) break;
530 new_option->name[i] = '\0';
531 new_option->name = strdup(new_option->name);
533 new_option->value = strtok(NULL, "=");
535 if (new_option->value != NULL) {
537 while(isspace(*new_option->value)) {
538 new_option->value++;
541 for (i = strlen(new_option->value); i > 0; i--) {
542 if (!isspace(new_option->value[i - 1])) break;
545 new_option->value[i] = '\0';
546 new_option->value = strdup(new_option->value);
549 /* Add to list */
551 DLIST_ADD(*options, new_option);
553 return True;
556 #endif
559 /*******************************************************************
560 A wrapper for vfs_chdir().
561 ********************************************************************/
563 int vfs_ChDir(connection_struct *conn, const char *path)
565 int res;
566 static pstring LastDir="";
568 if (strcsequal(path,"."))
569 return(0);
571 if (*path == '/' && strcsequal(LastDir,path))
572 return(0);
574 DEBUG(3,("vfs_ChDir to %s\n",path));
576 res = vfs_chdir(conn,path);
577 if (!res)
578 pstrcpy(LastDir,path);
579 return(res);
582 /* number of list structures for a caching GetWd function. */
583 #define MAX_GETWDCACHE (50)
585 struct {
586 SMB_DEV_T dev; /* These *must* be compatible with the types returned in a stat() call. */
587 SMB_INO_T inode; /* These *must* be compatible with the types returned in a stat() call. */
588 char *dos_path; /* The pathname in DOS format. */
589 BOOL valid;
590 } ino_list[MAX_GETWDCACHE];
592 extern BOOL use_getwd_cache;
594 /****************************************************************************
595 Prompte a ptr (to make it recently used)
596 ****************************************************************************/
598 static void array_promote(char *array,int elsize,int element)
600 char *p;
601 if (element == 0)
602 return;
604 p = (char *)malloc(elsize);
606 if (!p) {
607 DEBUG(5,("array_promote: malloc fail\n"));
608 return;
611 memcpy(p,array + element * elsize, elsize);
612 memmove(array + elsize,array,elsize*element);
613 memcpy(array,p,elsize);
614 SAFE_FREE(p);
617 /*******************************************************************
618 Return the absolute current directory path - given a UNIX pathname.
619 Note that this path is returned in DOS format, not UNIX
620 format. Note this can be called with conn == NULL.
621 ********************************************************************/
623 char *vfs_GetWd(connection_struct *conn, char *path)
625 pstring s;
626 static BOOL getwd_cache_init = False;
627 SMB_STRUCT_STAT st, st2;
628 int i;
630 *s = 0;
632 if (!use_getwd_cache)
633 return(vfs_getwd(conn,path));
635 /* init the cache */
636 if (!getwd_cache_init) {
637 getwd_cache_init = True;
638 for (i=0;i<MAX_GETWDCACHE;i++) {
639 string_set(&ino_list[i].dos_path,"");
640 ino_list[i].valid = False;
644 /* Get the inode of the current directory, if this doesn't work we're
645 in trouble :-) */
647 if (vfs_stat(conn, ".",&st) == -1) {
648 DEBUG(0,("Very strange, couldn't stat \".\" path=%s\n", path));
649 return(vfs_getwd(conn,path));
653 for (i=0; i<MAX_GETWDCACHE; i++) {
654 if (ino_list[i].valid) {
656 /* If we have found an entry with a matching inode and dev number
657 then find the inode number for the directory in the cached string.
658 If this agrees with that returned by the stat for the current
659 directory then all is o.k. (but make sure it is a directory all
660 the same...) */
662 if (st.st_ino == ino_list[i].inode && st.st_dev == ino_list[i].dev) {
663 if (vfs_stat(conn,ino_list[i].dos_path,&st2) == 0) {
664 if (st.st_ino == st2.st_ino && st.st_dev == st2.st_dev &&
665 (st2.st_mode & S_IFMT) == S_IFDIR) {
666 pstrcpy (path, ino_list[i].dos_path);
668 /* promote it for future use */
669 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
670 return (path);
672 } else {
673 /* If the inode is different then something's changed,
674 scrub the entry and start from scratch. */
675 ino_list[i].valid = False;
682 /* We don't have the information to hand so rely on traditional methods.
683 The very slow getcwd, which spawns a process on some systems, or the
684 not quite so bad getwd. */
686 if (!vfs_getwd(conn,s)) {
687 DEBUG(0,("vfs_GetWd: vfs_getwd call failed, errno %s\n",strerror(errno)));
688 return (NULL);
691 pstrcpy(path,s);
693 DEBUG(5,("vfs_GetWd %s, inode %.0f, dev %.0f\n",s,(double)st.st_ino,(double)st.st_dev));
695 /* add it to the cache */
696 i = MAX_GETWDCACHE - 1;
697 string_set(&ino_list[i].dos_path,s);
698 ino_list[i].dev = st.st_dev;
699 ino_list[i].inode = st.st_ino;
700 ino_list[i].valid = True;
702 /* put it at the top of the list */
703 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
705 return (path);
709 /* check if the file 'nmae' is a symlink, in that case check that it point to
710 a file that reside under the 'dir' tree */
712 static BOOL readlink_check(connection_struct *conn, char *dir, char *name)
714 BOOL ret = True;
715 pstring flink;
716 pstring cleanlink;
717 pstring savedir;
718 pstring realdir;
719 size_t reallen;
721 if (!vfs_GetWd(conn, savedir)) {
722 DEBUG(0,("couldn't vfs_GetWd for %s %s\n", name, dir));
723 return False;
726 if (vfs_ChDir(conn, dir) != 0) {
727 DEBUG(0,("couldn't vfs_ChDir to %s\n", dir));
728 return False;
731 if (!vfs_GetWd(conn, realdir)) {
732 DEBUG(0,("couldn't vfs_GetWd for %s\n", dir));
733 vfs_ChDir(conn, savedir);
734 return(False);
737 reallen = strlen(realdir);
738 if (realdir[reallen -1] == '/') {
739 reallen--;
740 realdir[reallen] = 0;
743 if (conn->vfs_ops.readlink(conn, name, flink, sizeof(pstring) -1) != -1) {
744 DEBUG(3,("reduce_name: file path name %s is a symlink\nChecking it's path\n", name));
745 if (*flink == '/') {
746 pstrcpy(cleanlink, flink);
747 } else {
748 pstrcpy(cleanlink, realdir);
749 pstrcat(cleanlink, "/");
750 pstrcat(cleanlink, flink);
752 unix_clean_name(cleanlink);
754 if (strncmp(cleanlink, realdir, reallen) != 0) {
755 DEBUG(2,("Bad access attempt? s=%s dir=%s newname=%s l=%d\n", name, realdir, cleanlink, (int)reallen));
756 ret = False;
760 vfs_ChDir(conn, savedir);
762 return ret;
765 /*******************************************************************
766 Reduce a file name, removing .. elements and checking that
767 it is below dir in the heirachy. This uses vfs_GetWd() and so must be run
768 on the system that has the referenced file system.
769 Widelinks are allowed if widelinks is true.
770 ********************************************************************/
772 BOOL reduce_name(connection_struct *conn, char *s,char *dir,BOOL widelinks)
774 #ifndef REDUCE_PATHS
775 return True;
776 #else
777 pstring dir2;
778 pstring wd;
779 pstring base_name;
780 pstring newname;
781 char *p=NULL;
782 BOOL relative = (*s != '/');
784 *dir2 = *wd = *base_name = *newname = 0;
786 if (widelinks) {
787 /* can't have a leading .. */
788 if (strncmp(s,"..",2) == 0 && (s[2]==0 || s[2]=='/')) {
789 DEBUG(3,("Illegal file name? (%s)\n",s));
790 return(False);
793 if (strlen(s) == 0)
794 pstrcpy(s,"./");
796 return(True);
799 DEBUG(3,("reduce_name [%s] [%s]\n",s,dir));
801 /* remove any double slashes */
802 all_string_sub(s,"//","/",0);
804 pstrcpy(base_name,s);
805 p = strrchr(base_name,'/');
807 if (!p)
808 return readlink_check(conn, dir, s);
810 if (!vfs_GetWd(conn,wd)) {
811 DEBUG(0,("couldn't vfs_GetWd for %s %s\n",s,dir));
812 return(False);
815 if (vfs_ChDir(conn,dir) != 0) {
816 DEBUG(0,("couldn't vfs_ChDir to %s\n",dir));
817 return(False);
820 if (!vfs_GetWd(conn,dir2)) {
821 DEBUG(0,("couldn't vfs_GetWd for %s\n",dir));
822 vfs_ChDir(conn,wd);
823 return(False);
826 if (p && (p != base_name)) {
827 *p = 0;
828 if (strcmp(p+1,".")==0)
829 p[1]=0;
830 if (strcmp(p+1,"..")==0)
831 *p = '/';
834 if (vfs_ChDir(conn,base_name) != 0) {
835 vfs_ChDir(conn,wd);
836 DEBUG(3,("couldn't vfs_ChDir for %s %s basename=%s\n",s,dir,base_name));
837 return(False);
840 if (!vfs_GetWd(conn,newname)) {
841 vfs_ChDir(conn,wd);
842 DEBUG(2,("couldn't get vfs_GetWd for %s %s\n",s,base_name));
843 return(False);
846 if (p && (p != base_name)) {
847 pstrcat(newname,"/");
848 pstrcat(newname,p+1);
852 size_t l = strlen(dir2);
853 if (dir2[l-1] == '/')
854 l--;
856 if (strncmp(newname,dir2,l) != 0) {
857 vfs_ChDir(conn,wd);
858 DEBUG(2,("Bad access attempt? s=%s dir=%s newname=%s l=%d\n",s,dir2,newname,(int)l));
859 return(False);
862 if (!readlink_check(conn, dir, newname)) {
863 DEBUG(2, ("Bad access attemt? %s is a symlink outside the share path", s));
864 return(False);
867 if (relative) {
868 if (newname[l] == '/')
869 pstrcpy(s,newname + l + 1);
870 else
871 pstrcpy(s,newname+l);
872 } else
873 pstrcpy(s,newname);
876 vfs_ChDir(conn,wd);
878 if (strlen(s) == 0)
879 pstrcpy(s,"./");
881 DEBUG(3,("reduced to %s\n",s));
882 return(True);
883 #endif