2 Unix SMB/Netbios implementation.
4 VFS initialisation and support functions
5 Copyright (C) Tim Potter 1999
6 Copyright (C) Alexander Bokovoy 2002
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 This work was sponsored by Optifacio Software Services, Inc.
28 #define DBGC_CLASS DBGC_VFS
30 struct vfs_init_function_entry
{
32 vfs_op_tuple
*vfs_op_tuples
;
33 struct vfs_init_function_entry
*prev
, *next
;
36 static struct vfs_init_function_entry
*backends
= NULL
;
38 /* Some structures to help us initialise the vfs operations table */
45 /* Default vfs hooks. WARNING: The order of these initialisers is
46 very important. They must be in the same order as defined in
47 vfs.h. Change at your own peril. */
49 static struct vfs_ops default_vfs
= {
54 vfswrap_dummy_connect
,
55 vfswrap_dummy_disconnect
,
59 vfswrap_get_shadow_copy_data
,
61 /* Directory operations */
98 /* Windows ACL operations. */
104 /* POSIX ACL operations. */
108 vfswrap_sys_acl_get_entry
,
109 vfswrap_sys_acl_get_tag_type
,
110 vfswrap_sys_acl_get_permset
,
111 vfswrap_sys_acl_get_qualifier
,
112 vfswrap_sys_acl_get_file
,
113 vfswrap_sys_acl_get_fd
,
114 vfswrap_sys_acl_clear_perms
,
115 vfswrap_sys_acl_add_perm
,
116 vfswrap_sys_acl_to_text
,
117 vfswrap_sys_acl_init
,
118 vfswrap_sys_acl_create_entry
,
119 vfswrap_sys_acl_set_tag_type
,
120 vfswrap_sys_acl_set_qualifier
,
121 vfswrap_sys_acl_set_permset
,
122 vfswrap_sys_acl_valid
,
123 vfswrap_sys_acl_set_file
,
124 vfswrap_sys_acl_set_fd
,
125 vfswrap_sys_acl_delete_def_file
,
126 vfswrap_sys_acl_get_perm
,
127 vfswrap_sys_acl_free_text
,
128 vfswrap_sys_acl_free_acl
,
129 vfswrap_sys_acl_free_qualifier
,
139 vfswrap_lremovexattr
,
140 vfswrap_fremovexattr
,
147 /****************************************************************************
148 maintain the list of available backends
149 ****************************************************************************/
151 static struct vfs_init_function_entry
*vfs_find_backend_entry(const char *name
)
153 struct vfs_init_function_entry
*entry
= backends
;
156 if (strcmp(entry
->name
, name
)==0) return entry
;
163 NTSTATUS
smb_register_vfs(int version
, const char *name
, vfs_op_tuple
*vfs_op_tuples
)
165 struct vfs_init_function_entry
*entry
= backends
;
167 if ((version
!= SMB_VFS_INTERFACE_VERSION
)) {
168 DEBUG(0, ("Failed to register vfs module.\n"
169 "The module was compiled against SMB_VFS_INTERFACE_VERSION %d,\n"
170 "current SMB_VFS_INTERFACE_VERSION is %d.\n"
171 "Please recompile against the current Samba Version!\n",
172 version
, SMB_VFS_INTERFACE_VERSION
));
173 return NT_STATUS_OBJECT_TYPE_MISMATCH
;
176 if (!name
|| !name
[0] || !vfs_op_tuples
) {
177 DEBUG(0,("smb_register_vfs() called with NULL pointer or empty name!\n"));
178 return NT_STATUS_INVALID_PARAMETER
;
181 if (vfs_find_backend_entry(name
)) {
182 DEBUG(0,("VFS module %s already loaded!\n", name
));
183 return NT_STATUS_OBJECT_NAME_COLLISION
;
186 entry
= smb_xmalloc(sizeof(struct vfs_init_function_entry
));
187 entry
->name
= smb_xstrdup(name
);
188 entry
->vfs_op_tuples
= vfs_op_tuples
;
190 DLIST_ADD(backends
, entry
);
191 DEBUG(5, ("Successfully added vfs backend '%s'\n", name
));
195 /****************************************************************************
196 initialise default vfs hooks
197 ****************************************************************************/
199 static void vfs_init_default(connection_struct
*conn
)
201 DEBUG(3, ("Initialising default vfs hooks\n"));
203 memcpy(&conn
->vfs
.ops
, &default_vfs
.ops
, sizeof(default_vfs
.ops
));
204 memcpy(&conn
->vfs_opaque
.ops
, &default_vfs
.ops
, sizeof(default_vfs
.ops
));
207 /****************************************************************************
208 initialise custom vfs hooks
209 ****************************************************************************/
211 BOOL
vfs_init_custom(connection_struct
*conn
, const char *vfs_object
)
214 char *module_name
= NULL
;
215 char *module_param
= NULL
, *p
;
217 vfs_handle_struct
*handle
;
218 struct vfs_init_function_entry
*entry
;
220 if (!conn
||!vfs_object
||!vfs_object
[0]) {
221 DEBUG(0,("vfs_init_custon() called with NULL pointer or emtpy vfs_object!\n"));
225 if(!backends
) static_init_vfs
;
227 DEBUG(3, ("Initialising custom vfs hooks from [%s]\n", vfs_object
));
229 module_name
= smb_xstrdup(vfs_object
);
231 p
= strchr(module_name
, ':');
236 trim_string(module_param
, " ", " ");
239 trim_string(module_name
, " ", " ");
241 /* First, try to load the module with the new module system */
242 if((entry
= vfs_find_backend_entry(module_name
)) ||
243 (NT_STATUS_IS_OK(smb_probe_module("vfs", module_name
)) &&
244 (entry
= vfs_find_backend_entry(module_name
)))) {
246 DEBUGADD(5,("Successfully loaded vfs module [%s] with the new modules system\n", vfs_object
));
248 if ((ops
= entry
->vfs_op_tuples
) == NULL
) {
249 DEBUG(0, ("entry->vfs_op_tuples==NULL for [%s] failed\n", vfs_object
));
250 SAFE_FREE(module_name
);
254 DEBUG(0,("Can't find a vfs module [%s]\n",vfs_object
));
255 SAFE_FREE(module_name
);
259 handle
= (vfs_handle_struct
*)talloc_zero(conn
->mem_ctx
,sizeof(vfs_handle_struct
));
261 DEBUG(0,("talloc_zero() failed!\n"));
262 SAFE_FREE(module_name
);
265 memcpy(&handle
->vfs_next
, &conn
->vfs
, sizeof(struct vfs_ops
));
268 handle
->param
= talloc_strdup(conn
->mem_ctx
, module_param
);
270 DLIST_ADD(conn
->vfs_handles
, handle
);
272 for(i
=0; ops
[i
].op
!= NULL
; i
++) {
273 DEBUG(5, ("Checking operation #%d (type %d, layer %d)\n", i
, ops
[i
].type
, ops
[i
].layer
));
274 if(ops
[i
].layer
== SMB_VFS_LAYER_OPAQUE
) {
275 /* Check whether this operation was already made opaque by different module */
276 if(((void**)&conn
->vfs_opaque
.ops
)[ops
[i
].type
] == ((void**)&default_vfs
.ops
)[ops
[i
].type
]) {
277 /* No, it isn't overloaded yet. Overload. */
278 DEBUGADD(5, ("Making operation type %d opaque [module %s]\n", ops
[i
].type
, vfs_object
));
279 ((void**)&conn
->vfs_opaque
.ops
)[ops
[i
].type
] = ops
[i
].op
;
280 ((vfs_handle_struct
**)&conn
->vfs_opaque
.handles
)[ops
[i
].type
] = handle
;
283 /* Change current VFS disposition*/
284 DEBUGADD(5, ("Accepting operation type %d from module %s\n", ops
[i
].type
, vfs_object
));
285 ((void**)&conn
->vfs
.ops
)[ops
[i
].type
] = ops
[i
].op
;
286 ((vfs_handle_struct
**)&conn
->vfs
.handles
)[ops
[i
].type
] = handle
;
289 SAFE_FREE(module_name
);
293 /*****************************************************************
295 ******************************************************************/
297 BOOL
smbd_vfs_init(connection_struct
*conn
)
299 const char **vfs_objects
;
303 /* Normal share - initialise with disk access functions */
304 vfs_init_default(conn
);
305 vfs_objects
= lp_vfs_objects(SNUM(conn
));
307 /* Override VFS functions if 'vfs object' was not specified*/
308 if (!vfs_objects
|| !vfs_objects
[0])
311 for (i
=0; vfs_objects
[i
] ;) {
315 for (j
=i
-1; j
>= 0; j
--) {
316 if (!vfs_init_custom(conn
, vfs_objects
[j
])) {
317 DEBUG(0, ("smbd_vfs_init: vfs_init_custom failed for %s\n", vfs_objects
[j
]));
324 /*******************************************************************
325 Check if directory exists.
326 ********************************************************************/
328 BOOL
vfs_directory_exist(connection_struct
*conn
, const char *dname
, SMB_STRUCT_STAT
*st
)
336 if (SMB_VFS_STAT(conn
,dname
,st
) != 0)
339 ret
= S_ISDIR(st
->st_mode
);
346 /*******************************************************************
348 ********************************************************************/
350 int vfs_MkDir(connection_struct
*conn
, const char *name
, mode_t mode
)
353 SMB_STRUCT_STAT sbuf
;
355 if(!(ret
=SMB_VFS_MKDIR(conn
, name
, mode
))) {
357 inherit_access_acl(conn
, name
, mode
);
360 * Check if high bits should have been set,
361 * then (if bits are missing): add them.
362 * Consider bits automagically set by UNIX, i.e. SGID bit from parent dir.
364 if(mode
& ~(S_IRWXU
|S_IRWXG
|S_IRWXO
) &&
365 !SMB_VFS_STAT(conn
,name
,&sbuf
) && (mode
& ~sbuf
.st_mode
))
366 SMB_VFS_CHMOD(conn
,name
,sbuf
.st_mode
| (mode
& ~sbuf
.st_mode
));
371 /*******************************************************************
372 Check if an object exists in the vfs.
373 ********************************************************************/
375 BOOL
vfs_object_exist(connection_struct
*conn
,const char *fname
,SMB_STRUCT_STAT
*sbuf
)
384 if (SMB_VFS_STAT(conn
,fname
,sbuf
) == -1)
389 /*******************************************************************
390 Check if a file exists in the vfs.
391 ********************************************************************/
393 BOOL
vfs_file_exist(connection_struct
*conn
, const char *fname
,SMB_STRUCT_STAT
*sbuf
)
402 if (SMB_VFS_STAT(conn
,fname
,sbuf
) == -1)
404 return(S_ISREG(sbuf
->st_mode
));
407 /****************************************************************************
408 Read data from fsp on the vfs. (note: EINTR re-read differs from vfs_write_data)
409 ****************************************************************************/
411 ssize_t
vfs_read_data(files_struct
*fsp
, char *buf
, size_t byte_count
)
415 while (total
< byte_count
)
417 ssize_t ret
= SMB_VFS_READ(fsp
, fsp
->fd
, buf
+ total
,
420 if (ret
== 0) return total
;
429 return (ssize_t
)total
;
432 /****************************************************************************
433 Write data to a fd on the vfs.
434 ****************************************************************************/
436 ssize_t
vfs_write_data(files_struct
*fsp
,const char *buffer
,size_t N
)
442 ret
= SMB_VFS_WRITE(fsp
,fsp
->fd
,buffer
+ total
,N
- total
);
451 return (ssize_t
)total
;
454 /****************************************************************************
455 An allocate file space call using the vfs interface.
456 Allocates space for a file from a filedescriptor.
457 Returns 0 on success, -1 on failure.
458 ****************************************************************************/
460 int vfs_allocate_file_space(files_struct
*fsp
, SMB_BIG_UINT len
)
464 connection_struct
*conn
= fsp
->conn
;
465 SMB_BIG_UINT space_avail
;
466 SMB_BIG_UINT bsize
,dfree
,dsize
;
468 release_level_2_oplocks_on_change(fsp
);
471 * Actually try and commit the space on disk....
474 DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", fsp
->fsp_name
, (double)len
));
476 if (((SMB_OFF_T
)len
) < 0) {
477 DEBUG(0,("vfs_allocate_file_space: %s negative len requested.\n", fsp
->fsp_name
));
481 ret
= SMB_VFS_FSTAT(fsp
,fsp
->fd
,&st
);
485 if (len
== (SMB_BIG_UINT
)st
.st_size
)
488 if (len
< (SMB_BIG_UINT
)st
.st_size
) {
489 /* Shrink - use ftruncate. */
491 DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
492 fsp
->fsp_name
, (double)st
.st_size
));
494 flush_write_cache(fsp
, SIZECHANGE_FLUSH
);
495 if ((ret
= SMB_VFS_FTRUNCATE(fsp
, fsp
->fd
, (SMB_OFF_T
)len
)) != -1) {
496 set_filelen_write_cache(fsp
, len
);
501 /* Grow - we need to test if we have enough space. */
503 if (!lp_strict_allocate(SNUM(fsp
->conn
)))
507 len
/= 1024; /* Len is now number of 1k blocks needed. */
508 space_avail
= SMB_VFS_DISK_FREE(conn
,fsp
->fsp_name
,False
,&bsize
,&dfree
,&dsize
);
510 DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %.0f, space avail = %.0f\n",
511 fsp
->fsp_name
, (double)st
.st_size
, (double)len
, (double)space_avail
));
513 if (len
> space_avail
) {
521 /****************************************************************************
522 A vfs set_filelen call.
523 set the length of a file from a filedescriptor.
524 Returns 0 on success, -1 on failure.
525 ****************************************************************************/
527 int vfs_set_filelen(files_struct
*fsp
, SMB_OFF_T len
)
531 release_level_2_oplocks_on_change(fsp
);
532 DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp
->fsp_name
, (double)len
));
533 flush_write_cache(fsp
, SIZECHANGE_FLUSH
);
534 if ((ret
= SMB_VFS_FTRUNCATE(fsp
, fsp
->fd
, len
)) != -1)
535 set_filelen_write_cache(fsp
, len
);
540 /****************************************************************************
541 Transfer some data (n bytes) between two file_struct's.
542 ****************************************************************************/
544 static files_struct
*in_fsp
;
545 static files_struct
*out_fsp
;
547 static ssize_t
read_fn(int fd
, void *buf
, size_t len
)
549 return SMB_VFS_READ(in_fsp
, fd
, buf
, len
);
552 static ssize_t
write_fn(int fd
, const void *buf
, size_t len
)
554 return SMB_VFS_WRITE(out_fsp
, fd
, buf
, len
);
557 SMB_OFF_T
vfs_transfer_file(files_struct
*in
, files_struct
*out
, SMB_OFF_T n
)
562 return transfer_file_internal(in_fsp
->fd
, out_fsp
->fd
, n
, read_fn
, write_fn
);
565 /*******************************************************************
566 A vfs_readdir wrapper which just returns the file name.
567 ********************************************************************/
569 char *vfs_readdirname(connection_struct
*conn
, void *p
)
571 struct dirent
*ptr
= NULL
;
577 ptr
= (struct dirent
*)SMB_VFS_READDIR(conn
,p
);
588 #ifdef HAVE_BROKEN_READDIR
589 /* using /usr/ucb/cc is BAD */
596 /*******************************************************************
597 A wrapper for vfs_chdir().
598 ********************************************************************/
600 int vfs_ChDir(connection_struct
*conn
, const char *path
)
603 static pstring LastDir
="";
605 if (strcsequal(path
,"."))
608 if (*path
== '/' && strcsequal(LastDir
,path
))
611 DEBUG(4,("vfs_ChDir to %s\n",path
));
613 res
= SMB_VFS_CHDIR(conn
,path
);
615 pstrcpy(LastDir
,path
);
619 /* number of list structures for a caching GetWd function. */
620 #define MAX_GETWDCACHE (50)
623 SMB_DEV_T dev
; /* These *must* be compatible with the types returned in a stat() call. */
624 SMB_INO_T inode
; /* These *must* be compatible with the types returned in a stat() call. */
625 char *dos_path
; /* The pathname in DOS format. */
627 } ino_list
[MAX_GETWDCACHE
];
629 extern BOOL use_getwd_cache
;
631 /****************************************************************************
632 Prompte a ptr (to make it recently used)
633 ****************************************************************************/
635 static void array_promote(char *array
,int elsize
,int element
)
641 p
= (char *)malloc(elsize
);
644 DEBUG(5,("array_promote: malloc fail\n"));
648 memcpy(p
,array
+ element
* elsize
, elsize
);
649 memmove(array
+ elsize
,array
,elsize
*element
);
650 memcpy(array
,p
,elsize
);
654 /*******************************************************************
655 Return the absolute current directory path - given a UNIX pathname.
656 Note that this path is returned in DOS format, not UNIX
657 format. Note this can be called with conn == NULL.
658 ********************************************************************/
660 char *vfs_GetWd(connection_struct
*conn
, char *path
)
663 static BOOL getwd_cache_init
= False
;
664 SMB_STRUCT_STAT st
, st2
;
669 if (!use_getwd_cache
)
670 return(SMB_VFS_GETWD(conn
,path
));
673 if (!getwd_cache_init
) {
674 getwd_cache_init
= True
;
675 for (i
=0;i
<MAX_GETWDCACHE
;i
++) {
676 string_set(&ino_list
[i
].dos_path
,"");
677 ino_list
[i
].valid
= False
;
681 /* Get the inode of the current directory, if this doesn't work we're
684 if (SMB_VFS_STAT(conn
, ".",&st
) == -1) {
685 DEBUG(0,("Very strange, couldn't stat \".\" path=%s\n", path
));
686 return(SMB_VFS_GETWD(conn
,path
));
690 for (i
=0; i
<MAX_GETWDCACHE
; i
++) {
691 if (ino_list
[i
].valid
) {
693 /* If we have found an entry with a matching inode and dev number
694 then find the inode number for the directory in the cached string.
695 If this agrees with that returned by the stat for the current
696 directory then all is o.k. (but make sure it is a directory all
699 if (st
.st_ino
== ino_list
[i
].inode
&& st
.st_dev
== ino_list
[i
].dev
) {
700 if (SMB_VFS_STAT(conn
,ino_list
[i
].dos_path
,&st2
) == 0) {
701 if (st
.st_ino
== st2
.st_ino
&& st
.st_dev
== st2
.st_dev
&&
702 (st2
.st_mode
& S_IFMT
) == S_IFDIR
) {
703 pstrcpy (path
, ino_list
[i
].dos_path
);
705 /* promote it for future use */
706 array_promote((char *)&ino_list
[0],sizeof(ino_list
[0]),i
);
709 /* If the inode is different then something's changed,
710 scrub the entry and start from scratch. */
711 ino_list
[i
].valid
= False
;
718 /* We don't have the information to hand so rely on traditional methods.
719 The very slow getcwd, which spawns a process on some systems, or the
720 not quite so bad getwd. */
722 if (!SMB_VFS_GETWD(conn
,s
)) {
723 DEBUG(0,("vfs_GetWd: SMB_VFS_GETWD call failed, errno %s\n",strerror(errno
)));
729 DEBUG(5,("vfs_GetWd %s, inode %.0f, dev %.0f\n",s
,(double)st
.st_ino
,(double)st
.st_dev
));
731 /* add it to the cache */
732 i
= MAX_GETWDCACHE
- 1;
733 string_set(&ino_list
[i
].dos_path
,s
);
734 ino_list
[i
].dev
= st
.st_dev
;
735 ino_list
[i
].inode
= st
.st_ino
;
736 ino_list
[i
].valid
= True
;
738 /* put it at the top of the list */
739 array_promote((char *)&ino_list
[0],sizeof(ino_list
[0]),i
);
745 /* check if the file 'nmae' is a symlink, in that case check that it point to
746 a file that reside under the 'dir' tree */
748 static BOOL
readlink_check(connection_struct
*conn
, const char *dir
, char *name
)
757 if (!vfs_GetWd(conn
, savedir
)) {
758 DEBUG(0,("couldn't vfs_GetWd for %s %s\n", name
, dir
));
762 if (vfs_ChDir(conn
, dir
) != 0) {
763 DEBUG(0,("couldn't vfs_ChDir to %s\n", dir
));
767 if (!vfs_GetWd(conn
, realdir
)) {
768 DEBUG(0,("couldn't vfs_GetWd for %s\n", dir
));
769 vfs_ChDir(conn
, savedir
);
773 reallen
= strlen(realdir
);
774 if (realdir
[reallen
-1] == '/') {
776 realdir
[reallen
] = 0;
779 if (SMB_VFS_READLINK(conn
, name
, flink
, sizeof(pstring
) -1) != -1) {
780 DEBUG(3,("reduce_name: file path name %s is a symlink\nChecking it's path\n", name
));
782 pstrcpy(cleanlink
, flink
);
784 pstrcpy(cleanlink
, realdir
);
785 pstrcat(cleanlink
, "/");
786 pstrcat(cleanlink
, flink
);
788 unix_clean_name(cleanlink
);
790 if (strncmp(cleanlink
, realdir
, reallen
) != 0) {
791 DEBUG(2,("Bad access attempt? s=%s dir=%s newname=%s l=%d\n", name
, realdir
, cleanlink
, (int)reallen
));
796 vfs_ChDir(conn
, savedir
);
801 /*******************************************************************
802 Reduce a file name, removing .. elements and checking that
803 it is below dir in the heirachy. This uses vfs_GetWd() and so must be run
804 on the system that has the referenced file system.
805 Widelinks are allowed if widelinks is true.
806 ********************************************************************/
808 BOOL
reduce_name(connection_struct
*conn
, pstring s
, const char *dir
,BOOL widelinks
)
818 BOOL relative
= (*s
!= '/');
820 *dir2
= *wd
= *base_name
= *newname
= 0;
824 /* can't have a leading .. */
825 if (strncmp(s
,"..",2) == 0 && (s
[2]==0 || s
[2]=='/')) {
826 DEBUG(3,("Illegal file name? (%s)\n",s
));
836 DEBUG(3,("reduce_name [%s] [%s]\n",s
,dir
));
838 /* remove any double slashes */
839 all_string_sub(s
,"//","/",0);
841 pstrcpy(base_name
,s
);
842 p
= strrchr_m(base_name
,'/');
845 return readlink_check(conn
, dir
, s
);
847 if (!vfs_GetWd(conn
,wd
)) {
848 DEBUG(0,("couldn't vfs_GetWd for %s %s\n",s
,dir
));
852 if (vfs_ChDir(conn
,dir
) != 0) {
853 DEBUG(0,("couldn't vfs_ChDir to %s\n",dir
));
857 if (!vfs_GetWd(conn
,dir2
)) {
858 DEBUG(0,("couldn't vfs_GetWd for %s\n",dir
));
863 if (p
&& (p
!= base_name
)) {
865 if (strcmp(p
+1,".")==0)
867 if (strcmp(p
+1,"..")==0)
871 if (vfs_ChDir(conn
,base_name
) != 0) {
873 DEBUG(3,("couldn't vfs_ChDir for %s %s basename=%s\n",s
,dir
,base_name
));
877 if (!vfs_GetWd(conn
,newname
)) {
879 DEBUG(2,("couldn't get vfs_GetWd for %s %s\n",s
,base_name
));
883 if (p
&& (p
!= base_name
)) {
884 pstrcat(newname
,"/");
885 pstrcat(newname
,p
+1);
889 size_t l
= strlen(dir2
);
890 if (dir2
[l
-1] == '/')
893 if (strncmp(newname
,dir2
,l
) != 0) {
895 DEBUG(2,("Bad access attempt? s=%s dir=%s newname=%s l=%d\n",s
,dir2
,newname
,(int)l
));
899 if (!readlink_check(conn
, dir
, newname
)) {
900 DEBUG(2, ("Bad access attemt? %s is a symlink outside the share path", s
));
905 if (newname
[l
] == '/')
906 pstrcpy(s
,newname
+ l
+ 1);
908 pstrcpy(s
,newname
+l
);
918 DEBUG(3,("reduced to %s\n",s
));