2 Unix SMB/Netbios implementation.
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.
24 /* Some structures to help us initialise the vfs operations table */
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 static struct vfs_ops default_vfs_ops = {
39 vfswrap_dummy_connect,
40 vfswrap_dummy_disconnect,
43 /* Directory operations */
81 #if defined(HAVE_NO_ACLS)
90 /****************************************************************************
91 initialise default vfs hooks
92 ****************************************************************************/
94 static BOOL vfs_init_default(connection_struct *conn)
96 DEBUG(3, ("Initialising default vfs hooks\n"));
98 memcpy(&conn->vfs_ops, &default_vfs_ops, sizeof(struct vfs_ops));
102 /****************************************************************************
103 initialise custom vfs hooks
104 ****************************************************************************/
107 static BOOL vfs_init_custom(connection_struct *conn)
109 int vfs_version = -1;
110 struct vfs_ops *ops, *(*init_fptr)(int *, struct vfs_ops *);
112 DEBUG(3, ("Initialising custom vfs hooks from %s\n",
113 lp_vfsobj(SNUM(conn))));
115 /* Open object file */
116 if ((conn->dl_handle = sys_dlopen(lp_vfsobj(SNUM(conn)),
117 RTLD_NOW | RTLD_GLOBAL)) == NULL) {
118 DEBUG(0, ("Error opening %s: %s\n", lp_vfsobj(SNUM(conn)), sys_dlerror()));
122 /* Get handle on vfs_init() symbol */
123 init_fptr = (struct vfs_ops *(*)(int *, struct vfs_ops *))sys_dlsym(conn->dl_handle, "vfs_init");
125 if (init_fptr == NULL) {
126 DEBUG(0, ("No vfs_init() symbol found in %s\n",
127 lp_vfsobj(SNUM(conn))));
131 /* Initialise vfs_ops structure */
132 conn->vfs_ops = default_vfs_ops;
134 if ((ops = init_fptr(&vfs_version, &conn->vfs_ops)) == NULL) {
135 DEBUG(0, ("vfs_init function from %s failed\n", lp_vfsobj(SNUM(conn))));
139 if (vfs_version != SMB_VFS_INTERFACE_VERSION) {
140 DEBUG(0, ("vfs_init returned wrong interface version info (was %d, should be %d)\n",
141 vfs_version, SMB_VFS_INTERFACE_VERSION ));
145 if (ops != &conn->vfs_ops) {
146 memcpy(&conn->vfs_ops, ops, sizeof(struct vfs_ops));
153 /*****************************************************************
155 ******************************************************************/
157 BOOL smbd_vfs_init(connection_struct *conn)
159 if (*lp_vfsobj(SNUM(conn))) {
162 /* Loadable object file */
164 if (!vfs_init_custom(conn)) {
165 DEBUG(0, ("smbd_vfs_init: vfs_init_custom failed\n"));
171 DEBUG(0, ("smbd_vfs_init: No libdl present - cannot use VFS objects\n"));
176 /* Normal share - initialise with disk access functions */
178 return vfs_init_default(conn);
181 /*******************************************************************
182 Check if directory exists.
183 ********************************************************************/
185 BOOL vfs_directory_exist(connection_struct *conn, const char *dname, SMB_STRUCT_STAT *st)
193 if (vfs_stat(conn,dname,st) != 0)
196 ret = S_ISDIR(st->st_mode);
203 /*******************************************************************
205 ********************************************************************/
206 char *vfs_getwd(connection_struct *conn, char *path)
208 return conn->vfs_ops.getwd(conn,path);
211 /*******************************************************************
213 ********************************************************************/
215 int vfs_mkdir(connection_struct *conn, const char *name, mode_t mode)
218 SMB_STRUCT_STAT sbuf;
220 if(!(ret=conn->vfs_ops.mkdir(conn,name,mode))) {
222 * Check if high bits should have been set,
223 * then (if bits are missing): add them.
224 * Consider bits automagically set by UNIX, i.e. SGID bit from parent dir.
226 if(mode & ~(S_IRWXU|S_IRWXG|S_IRWXO) &&
227 !vfs_stat(conn,name,&sbuf) && (mode & ~sbuf.st_mode))
228 vfs_chmod(conn,name,sbuf.st_mode | (mode & ~sbuf.st_mode));
233 /*******************************************************************
234 Check if an object exists in the vfs.
235 ********************************************************************/
237 BOOL vfs_object_exist(connection_struct *conn,const char *fname,SMB_STRUCT_STAT *sbuf)
246 if (vfs_stat(conn,fname,sbuf) == -1)
251 /*******************************************************************
252 Check if a file exists in the vfs.
253 ********************************************************************/
255 BOOL vfs_file_exist(connection_struct *conn,char *fname,SMB_STRUCT_STAT *sbuf)
264 if (vfs_stat(conn,fname,sbuf) == -1)
266 return(S_ISREG(sbuf->st_mode));
269 /****************************************************************************
270 Read data from fsp on the vfs. (note: EINTR re-read differs from vfs_write_data)
271 ****************************************************************************/
273 ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count)
277 while (total < byte_count)
279 ssize_t ret = fsp->conn->vfs_ops.read(fsp, fsp->fd, buf + total,
282 if (ret == 0) return total;
291 return (ssize_t)total;
294 /****************************************************************************
295 Write data to a fd on the vfs.
296 ****************************************************************************/
298 ssize_t vfs_write_data(files_struct *fsp,const char *buffer,size_t N)
304 ret = fsp->conn->vfs_ops.write(fsp,fsp->fd,buffer + total,N - total);
313 return (ssize_t)total;
316 /****************************************************************************
317 An allocate file space call using the vfs interface.
318 Allocates space for a file from a filedescriptor.
319 Returns 0 on success, -1 on failure.
320 ****************************************************************************/
322 int vfs_allocate_file_space(files_struct *fsp, SMB_OFF_T len)
326 connection_struct *conn = fsp->conn;
327 struct vfs_ops *vfs_ops = &conn->vfs_ops;
328 SMB_OFF_T space_avail;
329 SMB_BIG_UINT bsize,dfree,dsize;
331 release_level_2_oplocks_on_change(fsp);
334 * Actually try and commit the space on disk....
337 DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", fsp->fsp_name, (double)len ));
339 ret = vfs_fstat(fsp,fsp->fd,&st);
343 if (len == st.st_size)
346 if (len < st.st_size) {
347 /* Shrink - use ftruncate. */
349 DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
350 fsp->fsp_name, (double)st.st_size ));
352 if ((ret = vfs_ops->ftruncate(fsp, fsp->fd, len)) != -1) {
353 set_filelen_write_cache(fsp, len);
358 /* Grow - we need to test if we have enough space. */
360 if (!lp_strict_allocate(SNUM(fsp->conn)))
364 len /= 1024; /* Len is now number of 1k blocks needed. */
365 space_avail = (SMB_OFF_T)conn->vfs_ops.disk_free(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize);
367 DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %lu, space avail = %lu\n",
368 fsp->fsp_name, (double)st.st_size, (unsigned long)len, (unsigned long)space_avail ));
370 if (len > space_avail) {
378 /****************************************************************************
379 A vfs set_filelen call.
380 set the length of a file from a filedescriptor.
381 Returns 0 on success, -1 on failure.
382 ****************************************************************************/
384 int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
388 release_level_2_oplocks_on_change(fsp);
389 DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len));
390 if ((ret = fsp->conn->vfs_ops.ftruncate(fsp, fsp->fd, len)) != -1)
391 set_filelen_write_cache(fsp, len);
396 /****************************************************************************
397 Transfer some data (n bytes) between two file_struct's.
398 ****************************************************************************/
400 static files_struct *in_fsp;
401 static files_struct *out_fsp;
403 static ssize_t read_fn(int fd, void *buf, size_t len)
405 return in_fsp->conn->vfs_ops.read(in_fsp, fd, buf, len);
408 static ssize_t write_fn(int fd, const void *buf, size_t len)
410 return out_fsp->conn->vfs_ops.write(out_fsp, fd, buf, len);
413 SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n)
418 return transfer_file_internal(in_fsp->fd, out_fsp->fd, n, read_fn, write_fn);
421 /*******************************************************************
422 A vfs_readdir wrapper which just returns the file name.
423 ********************************************************************/
425 char *vfs_readdirname(connection_struct *conn, void *p)
433 ptr = (struct dirent *)conn->vfs_ops.readdir(conn,p);
444 #ifdef HAVE_BROKEN_READDIR
445 /* using /usr/ucb/cc is BAD */
452 /* VFS options not quite working yet */
456 /***************************************************************************
457 handle the interpretation of the vfs option parameter
458 *************************************************************************/
459 static BOOL handle_vfs_option(char *pszParmValue, char **ptr)
461 struct vfs_options *new_option, **options = (struct vfs_options **)ptr;
464 /* Create new vfs option */
466 new_option = (struct vfs_options *)malloc(sizeof(*new_option));
467 if (new_option == NULL) {
471 ZERO_STRUCTP(new_option);
473 /* Get name and value */
475 new_option->name = strtok(pszParmValue, "=");
477 if (new_option->name == NULL) {
481 while(isspace(*new_option->name)) {
485 for (i = strlen(new_option->name); i > 0; i--) {
486 if (!isspace(new_option->name[i - 1])) break;
489 new_option->name[i] = '\0';
490 new_option->name = strdup(new_option->name);
492 new_option->value = strtok(NULL, "=");
494 if (new_option->value != NULL) {
496 while(isspace(*new_option->value)) {
500 for (i = strlen(new_option->value); i > 0; i--) {
501 if (!isspace(new_option->value[i - 1])) break;
504 new_option->value[i] = '\0';
505 new_option->value = strdup(new_option->value);
510 DLIST_ADD(*options, new_option);
518 /*******************************************************************
519 A wrapper for vfs_chdir().
520 ********************************************************************/
522 int vfs_ChDir(connection_struct *conn, char *path)
525 static pstring LastDir="";
527 if (strcsequal(path,"."))
530 if (*path == '/' && strcsequal(LastDir,path))
533 DEBUG(3,("vfs_ChDir to %s\n",path));
535 res = vfs_chdir(conn,path);
537 pstrcpy(LastDir,path);
541 /* number of list structures for a caching GetWd function. */
542 #define MAX_GETWDCACHE (50)
546 SMB_DEV_T dev; /* These *must* be compatible with the types returned in a stat() call. */
547 SMB_INO_T inode; /* These *must* be compatible with the types returned in a stat() call. */
548 char *dos_path; /* The pathname in DOS format. */
550 } ino_list[MAX_GETWDCACHE];
552 extern BOOL use_getwd_cache;
554 /****************************************************************************
555 Prompte a ptr (to make it recently used)
556 ****************************************************************************/
558 static void array_promote(char *array,int elsize,int element)
564 p = (char *)malloc(elsize);
567 DEBUG(5,("array_promote: malloc fail\n"));
571 memcpy(p,array + element * elsize, elsize);
572 memmove(array + elsize,array,elsize*element);
573 memcpy(array,p,elsize);
577 /*******************************************************************
578 Return the absolute current directory path - given a UNIX pathname.
579 Note that this path is returned in DOS format, not UNIX
580 format. Note this can be called with conn == NULL.
581 ********************************************************************/
583 char *vfs_GetWd(connection_struct *conn, char *path)
586 static BOOL getwd_cache_init = False;
587 SMB_STRUCT_STAT st, st2;
592 if (!use_getwd_cache)
593 return(vfs_getwd(conn,path));
596 if (!getwd_cache_init)
598 getwd_cache_init = True;
599 for (i=0;i<MAX_GETWDCACHE;i++)
601 string_set(&ino_list[i].dos_path,"");
602 ino_list[i].valid = False;
606 /* Get the inode of the current directory, if this doesn't work we're
609 if (vfs_stat(conn, ".",&st) == -1)
611 DEBUG(0,("Very strange, couldn't stat \".\" path=%s\n", path));
612 return(vfs_getwd(conn,path));
616 for (i=0; i<MAX_GETWDCACHE; i++)
617 if (ino_list[i].valid)
620 /* If we have found an entry with a matching inode and dev number
621 then find the inode number for the directory in the cached string.
622 If this agrees with that returned by the stat for the current
623 directory then all is o.k. (but make sure it is a directory all
626 if (st.st_ino == ino_list[i].inode &&
627 st.st_dev == ino_list[i].dev)
629 if (vfs_stat(conn,ino_list[i].dos_path,&st2) == 0)
631 if (st.st_ino == st2.st_ino &&
632 st.st_dev == st2.st_dev &&
633 (st2.st_mode & S_IFMT) == S_IFDIR)
635 pstrcpy (path, ino_list[i].dos_path);
637 /* promote it for future use */
638 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
643 /* If the inode is different then something's changed,
644 scrub the entry and start from scratch. */
645 ino_list[i].valid = False;
652 /* We don't have the information to hand so rely on traditional methods.
653 The very slow getcwd, which spawns a process on some systems, or the
654 not quite so bad getwd. */
656 if (!vfs_getwd(conn,s))
658 DEBUG(0,("vfs_GetWd: vfs_getwd call failed, errno %s\n",strerror(errno)));
664 DEBUG(5,("vfs_GetWd %s, inode %.0f, dev %.0f\n",s,(double)st.st_ino,(double)st.st_dev));
666 /* add it to the cache */
667 i = MAX_GETWDCACHE - 1;
668 string_set(&ino_list[i].dos_path,s);
669 ino_list[i].dev = st.st_dev;
670 ino_list[i].inode = st.st_ino;
671 ino_list[i].valid = True;
673 /* put it at the top of the list */
674 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
679 /*******************************************************************
680 Reduce a file name, removing .. elements and checking that
681 it is below dir in the heirachy. This uses vfs_GetWd() and so must be run
682 on the system that has the referenced file system.
683 Widelinks are allowed if widelinks is true.
684 ********************************************************************/
686 BOOL reduce_name(connection_struct *conn, char *s,char *dir,BOOL widelinks)
696 BOOL relative = (*s != '/');
698 *dir2 = *wd = *base_name = *newname = 0;
703 /* can't have a leading .. */
704 if (strncmp(s,"..",2) == 0 && (s[2]==0 || s[2]=='/'))
706 DEBUG(3,("Illegal file name? (%s)\n",s));
716 DEBUG(3,("reduce_name [%s] [%s]\n",s,dir));
718 /* remove any double slashes */
719 all_string_sub(s,"//","/",0);
721 pstrcpy(base_name,s);
722 p = strrchr_m(base_name,'/');
727 if (!vfs_GetWd(conn,wd))
729 DEBUG(0,("couldn't vfs_GetWd for %s %s\n",s,dir));
733 if (vfs_ChDir(conn,dir) != 0)
735 DEBUG(0,("couldn't vfs_ChDir to %s\n",dir));
739 if (!vfs_GetWd(conn,dir2))
741 DEBUG(0,("couldn't vfs_GetWd for %s\n",dir));
746 if (p && (p != base_name))
749 if (strcmp(p+1,".")==0)
751 if (strcmp(p+1,"..")==0)
755 if (vfs_ChDir(conn,base_name) != 0)
758 DEBUG(3,("couldn't vfs_ChDir for %s %s basename=%s\n",s,dir,base_name));
762 if (!vfs_GetWd(conn,newname))
765 DEBUG(2,("couldn't get vfs_GetWd for %s %s\n",s,dir2));
769 if (p && (p != base_name))
771 pstrcat(newname,"/");
772 pstrcat(newname,p+1);
776 size_t l = strlen(dir2);
777 if (dir2[l-1] == '/')
780 if (strncmp(newname,dir2,l) != 0)
783 DEBUG(2,("Bad access attempt? s=%s dir=%s newname=%s l=%d\n",s,dir2,newname,(int)l));
789 if (newname[l] == '/')
790 pstrcpy(s,newname + l + 1);
792 pstrcpy(s,newname+l);
803 DEBUG(3,("reduced to %s\n",s));