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 struct vfs_ops default_vfs_ops = {
39 vfswrap_dummy_connect,
40 vfswrap_dummy_disconnect,
43 /* Directory operations */
84 /* POSIX ACL operations. */
85 #if defined(HAVE_NO_ACLS)
92 vfswrap_sys_acl_get_entry,
93 vfswrap_sys_acl_get_tag_type,
94 vfswrap_sys_acl_get_permset,
95 vfswrap_sys_acl_get_qualifier,
96 vfswrap_sys_acl_get_file,
97 vfswrap_sys_acl_get_fd,
98 vfswrap_sys_acl_clear_perms,
99 vfswrap_sys_acl_add_perm,
100 vfswrap_sys_acl_to_text,
101 vfswrap_sys_acl_init,
102 vfswrap_sys_acl_create_entry,
103 vfswrap_sys_acl_set_tag_type,
104 vfswrap_sys_acl_set_qualifier,
105 vfswrap_sys_acl_set_permset,
106 vfswrap_sys_acl_valid,
107 vfswrap_sys_acl_set_file,
108 vfswrap_sys_acl_set_fd,
109 vfswrap_sys_acl_delete_def_file,
110 vfswrap_sys_acl_get_perm,
111 vfswrap_sys_acl_free_text,
112 vfswrap_sys_acl_free_acl,
113 vfswrap_sys_acl_free_qualifier
116 /****************************************************************************
117 initialise default vfs hooks
118 ****************************************************************************/
120 static BOOL vfs_init_default(connection_struct *conn)
122 DEBUG(3, ("Initialising default vfs hooks\n"));
124 memcpy(&conn->vfs_ops, &default_vfs_ops, sizeof(struct vfs_ops));
128 /****************************************************************************
129 initialise custom vfs hooks
130 ****************************************************************************/
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",
139 lp_vfsobj(SNUM(conn))));
141 /* Open object file */
143 if ((conn->dl_handle = sys_dlopen(lp_vfsobj(SNUM(conn)), RTLD_NOW | RTLD_GLOBAL)) == NULL) {
144 DEBUG(0, ("Error opening %s: %s\n", lp_vfsobj(SNUM(conn)), dlerror()));
148 /* Get handle on vfs_init() symbol */
150 init_fptr = (struct vfs_ops *(*)(int *, struct vfs_ops *))sys_dlsym(conn->dl_handle, "vfs_init");
152 if (init_fptr == NULL) {
153 DEBUG(0, ("No vfs_init() symbol found in %s\n",
154 lp_vfsobj(SNUM(conn))));
158 /* Initialise vfs_ops structure */
160 conn->vfs_ops = default_vfs_ops;
162 if ((ops = init_fptr(&vfs_version, &default_vfs_ops)) == NULL) {
163 DEBUG(0, ("vfs_init function from %s failed\n", lp_vfsobj(SNUM(conn))));
167 if (vfs_version != SMB_VFS_INTERFACE_VERSION) {
168 DEBUG(0, ("vfs_init returned wrong interface version info (was %d, should be %d)\n",
169 vfs_version, SMB_VFS_INTERFACE_VERSION ));
173 if (ops != &conn->vfs_ops) {
174 memcpy(&conn->vfs_ops, ops, sizeof(struct vfs_ops));
181 /*****************************************************************
183 ******************************************************************/
185 BOOL smbd_vfs_init(connection_struct *conn)
187 if (*lp_vfsobj(SNUM(conn))) {
190 /* Loadable object file */
192 if (!vfs_init_custom(conn)) {
193 DEBUG(0, ("smbd_vfs_init: vfs_init_custom failed\n"));
199 DEBUG(0, ("smbd_vfs_init: No libdl present - cannot use VFS objects\n"));
204 /* Normal share - initialise with disk access functions */
206 return vfs_init_default(conn);
209 /*******************************************************************
210 Check if directory exists.
211 ********************************************************************/
213 BOOL vfs_directory_exist(connection_struct *conn, const char *dname, SMB_STRUCT_STAT *st)
221 if (vfs_stat(conn,dname,st) != 0)
224 ret = S_ISDIR(st->st_mode);
231 /*******************************************************************
233 ********************************************************************/
234 char *vfs_getwd(connection_struct *conn, char *path)
236 return conn->vfs_ops.getwd(conn,path);
239 /*******************************************************************
241 ********************************************************************/
243 int vfs_mkdir(connection_struct *conn, const char *name, mode_t mode)
246 SMB_STRUCT_STAT sbuf;
248 if(!(ret=conn->vfs_ops.mkdir(conn,name,mode))) {
250 * Check if high bits should have been set,
251 * then (if bits are missing): add them.
252 * Consider bits automagically set by UNIX, i.e. SGID bit from parent dir.
254 if(mode & ~(S_IRWXU|S_IRWXG|S_IRWXO) &&
255 !vfs_stat(conn,name,&sbuf) && (mode & ~sbuf.st_mode))
256 vfs_chmod(conn,name,sbuf.st_mode | (mode & ~sbuf.st_mode));
261 /*******************************************************************
262 Check if an object exists in the vfs.
263 ********************************************************************/
265 BOOL vfs_object_exist(connection_struct *conn,const char *fname,SMB_STRUCT_STAT *sbuf)
274 if (vfs_stat(conn,fname,sbuf) == -1)
279 /*******************************************************************
280 Check if a file exists in the vfs.
281 ********************************************************************/
283 BOOL vfs_file_exist(connection_struct *conn, const char *fname,SMB_STRUCT_STAT *sbuf)
292 if (vfs_stat(conn,fname,sbuf) == -1)
294 return(S_ISREG(sbuf->st_mode));
297 /****************************************************************************
298 Read data from fsp on the vfs. (note: EINTR re-read differs from vfs_write_data)
299 ****************************************************************************/
301 ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count)
305 while (total < byte_count)
307 ssize_t ret = fsp->conn->vfs_ops.read(fsp, fsp->fd, buf + total,
310 if (ret == 0) return total;
319 return (ssize_t)total;
322 /****************************************************************************
323 Write data to a fd on the vfs.
324 ****************************************************************************/
326 ssize_t vfs_write_data(files_struct *fsp,const char *buffer,size_t N)
332 ret = fsp->conn->vfs_ops.write(fsp,fsp->fd,buffer + total,N - total);
341 return (ssize_t)total;
344 /****************************************************************************
345 An allocate file space call using the vfs interface.
346 Allocates space for a file from a filedescriptor.
347 Returns 0 on success, -1 on failure.
348 ****************************************************************************/
350 int vfs_allocate_file_space(files_struct *fsp, SMB_OFF_T len)
354 connection_struct *conn = fsp->conn;
355 struct vfs_ops *vfs_ops = &conn->vfs_ops;
356 SMB_OFF_T space_avail;
357 SMB_BIG_UINT bsize,dfree,dsize;
359 release_level_2_oplocks_on_change(fsp);
362 * Actually try and commit the space on disk....
365 DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", fsp->fsp_name, (double)len ));
367 ret = vfs_fstat(fsp,fsp->fd,&st);
371 if (len == st.st_size)
374 if (len < st.st_size) {
375 /* Shrink - use ftruncate. */
377 DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
378 fsp->fsp_name, (double)st.st_size ));
380 flush_write_cache(fsp, SIZECHANGE_FLUSH);
381 if ((ret = vfs_ops->ftruncate(fsp, fsp->fd, len)) != -1) {
382 set_filelen_write_cache(fsp, len);
387 /* Grow - we need to test if we have enough space. */
389 if (!lp_strict_allocate(SNUM(fsp->conn)))
393 len /= 1024; /* Len is now number of 1k blocks needed. */
394 space_avail = (SMB_OFF_T)conn->vfs_ops.disk_free(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize);
396 DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %lu, space avail = %lu\n",
397 fsp->fsp_name, (double)st.st_size, (unsigned long)len, (unsigned long)space_avail ));
399 if (len > space_avail) {
407 /****************************************************************************
408 A vfs set_filelen call.
409 set the length of a file from a filedescriptor.
410 Returns 0 on success, -1 on failure.
411 ****************************************************************************/
413 int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
417 release_level_2_oplocks_on_change(fsp);
418 DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len));
419 flush_write_cache(fsp, SIZECHANGE_FLUSH);
420 if ((ret = fsp->conn->vfs_ops.ftruncate(fsp, fsp->fd, len)) != -1)
421 set_filelen_write_cache(fsp, len);
426 /****************************************************************************
427 Transfer some data (n bytes) between two file_struct's.
428 ****************************************************************************/
430 static files_struct *in_fsp;
431 static files_struct *out_fsp;
433 static ssize_t read_fn(int fd, void *buf, size_t len)
435 return in_fsp->conn->vfs_ops.read(in_fsp, fd, buf, len);
438 static ssize_t write_fn(int fd, const void *buf, size_t len)
440 return out_fsp->conn->vfs_ops.write(out_fsp, fd, buf, len);
443 SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n)
448 return transfer_file_internal(in_fsp->fd, out_fsp->fd, n, read_fn, write_fn);
451 /*******************************************************************
452 A vfs_readdir wrapper which just returns the file name.
453 ********************************************************************/
455 char *vfs_readdirname(connection_struct *conn, void *p)
463 ptr = (struct dirent *)conn->vfs_ops.readdir(conn,p);
474 #ifdef HAVE_BROKEN_READDIR
475 /* using /usr/ucb/cc is BAD */
482 /* VFS options not quite working yet */
486 /***************************************************************************
487 handle the interpretation of the vfs option parameter
488 *************************************************************************/
489 static BOOL handle_vfs_option(char *pszParmValue, char **ptr)
491 struct vfs_options *new_option, **options = (struct vfs_options **)ptr;
494 /* Create new vfs option */
496 new_option = (struct vfs_options *)malloc(sizeof(*new_option));
497 if (new_option == NULL) {
501 ZERO_STRUCTP(new_option);
503 /* Get name and value */
505 new_option->name = strtok(pszParmValue, "=");
507 if (new_option->name == NULL) {
511 while(isspace(*new_option->name)) {
515 for (i = strlen(new_option->name); i > 0; i--) {
516 if (!isspace(new_option->name[i - 1])) break;
519 new_option->name[i] = '\0';
520 new_option->name = strdup(new_option->name);
522 new_option->value = strtok(NULL, "=");
524 if (new_option->value != NULL) {
526 while(isspace(*new_option->value)) {
530 for (i = strlen(new_option->value); i > 0; i--) {
531 if (!isspace(new_option->value[i - 1])) break;
534 new_option->value[i] = '\0';
535 new_option->value = strdup(new_option->value);
540 DLIST_ADD(*options, new_option);
548 /*******************************************************************
549 A wrapper for vfs_chdir().
550 ********************************************************************/
552 int vfs_ChDir(connection_struct *conn, char *path)
555 static pstring LastDir="";
557 if (strcsequal(path,"."))
560 if (*path == '/' && strcsequal(LastDir,path))
563 DEBUG(3,("vfs_ChDir to %s\n",path));
565 res = vfs_chdir(conn,path);
567 pstrcpy(LastDir,path);
571 /* number of list structures for a caching GetWd function. */
572 #define MAX_GETWDCACHE (50)
576 SMB_DEV_T dev; /* These *must* be compatible with the types returned in a stat() call. */
577 SMB_INO_T inode; /* These *must* be compatible with the types returned in a stat() call. */
578 char *dos_path; /* The pathname in DOS format. */
580 } ino_list[MAX_GETWDCACHE];
582 extern BOOL use_getwd_cache;
584 /****************************************************************************
585 Prompte a ptr (to make it recently used)
586 ****************************************************************************/
588 static void array_promote(char *array,int elsize,int element)
594 p = (char *)malloc(elsize);
597 DEBUG(5,("array_promote: malloc fail\n"));
601 memcpy(p,array + element * elsize, elsize);
602 memmove(array + elsize,array,elsize*element);
603 memcpy(array,p,elsize);
607 /*******************************************************************
608 Return the absolute current directory path - given a UNIX pathname.
609 Note that this path is returned in DOS format, not UNIX
610 format. Note this can be called with conn == NULL.
611 ********************************************************************/
613 char *vfs_GetWd(connection_struct *conn, char *path)
616 static BOOL getwd_cache_init = False;
617 SMB_STRUCT_STAT st, st2;
622 if (!use_getwd_cache)
623 return(vfs_getwd(conn,path));
626 if (!getwd_cache_init)
628 getwd_cache_init = True;
629 for (i=0;i<MAX_GETWDCACHE;i++)
631 string_set(&ino_list[i].dos_path,"");
632 ino_list[i].valid = False;
636 /* Get the inode of the current directory, if this doesn't work we're
639 if (vfs_stat(conn, ".",&st) == -1)
641 DEBUG(0,("Very strange, couldn't stat \".\" path=%s\n", path));
642 return(vfs_getwd(conn,path));
646 for (i=0; i<MAX_GETWDCACHE; i++)
647 if (ino_list[i].valid)
650 /* If we have found an entry with a matching inode and dev number
651 then find the inode number for the directory in the cached string.
652 If this agrees with that returned by the stat for the current
653 directory then all is o.k. (but make sure it is a directory all
656 if (st.st_ino == ino_list[i].inode &&
657 st.st_dev == ino_list[i].dev)
659 if (vfs_stat(conn,ino_list[i].dos_path,&st2) == 0)
661 if (st.st_ino == st2.st_ino &&
662 st.st_dev == st2.st_dev &&
663 (st2.st_mode & S_IFMT) == S_IFDIR)
665 pstrcpy (path, ino_list[i].dos_path);
667 /* promote it for future use */
668 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
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))
688 DEBUG(0,("vfs_GetWd: vfs_getwd call failed, errno %s\n",strerror(errno)));
694 DEBUG(5,("vfs_GetWd %s, inode %.0f, dev %.0f\n",s,(double)st.st_ino,(double)st.st_dev));
696 /* add it to the cache */
697 i = MAX_GETWDCACHE - 1;
698 string_set(&ino_list[i].dos_path,s);
699 ino_list[i].dev = st.st_dev;
700 ino_list[i].inode = st.st_ino;
701 ino_list[i].valid = True;
703 /* put it at the top of the list */
704 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
709 /*******************************************************************
710 Reduce a file name, removing .. elements and checking that
711 it is below dir in the heirachy. This uses vfs_GetWd() and so must be run
712 on the system that has the referenced file system.
713 Widelinks are allowed if widelinks is true.
714 ********************************************************************/
716 BOOL reduce_name(connection_struct *conn, char *s,char *dir,BOOL widelinks)
726 BOOL relative = (*s != '/');
728 *dir2 = *wd = *base_name = *newname = 0;
733 /* can't have a leading .. */
734 if (strncmp(s,"..",2) == 0 && (s[2]==0 || s[2]=='/'))
736 DEBUG(3,("Illegal file name? (%s)\n",s));
746 DEBUG(3,("reduce_name [%s] [%s]\n",s,dir));
748 /* remove any double slashes */
749 all_string_sub(s,"//","/",0);
751 pstrcpy(base_name,s);
752 p = strrchr_m(base_name,'/');
757 if (!vfs_GetWd(conn,wd))
759 DEBUG(0,("couldn't vfs_GetWd for %s %s\n",s,dir));
763 if (vfs_ChDir(conn,dir) != 0)
765 DEBUG(0,("couldn't vfs_ChDir to %s\n",dir));
769 if (!vfs_GetWd(conn,dir2))
771 DEBUG(0,("couldn't vfs_GetWd for %s\n",dir));
776 if (p && (p != base_name))
779 if (strcmp(p+1,".")==0)
781 if (strcmp(p+1,"..")==0)
785 if (vfs_ChDir(conn,base_name) != 0)
788 DEBUG(3,("couldn't vfs_ChDir for %s %s basename=%s\n",s,dir,base_name));
792 if (!vfs_GetWd(conn,newname))
795 DEBUG(2,("couldn't get vfs_GetWd for %s %s\n",s,dir2));
799 if (p && (p != base_name))
801 pstrcat(newname,"/");
802 pstrcat(newname,p+1);
806 size_t l = strlen(dir2);
807 if (dir2[l-1] == '/')
810 if (strncmp(newname,dir2,l) != 0)
813 DEBUG(2,("Bad access attempt? s=%s dir=%s newname=%s l=%d\n",s,dir2,newname,(int)l));
819 if (newname[l] == '/')
820 pstrcpy(s,newname + l + 1);
822 pstrcpy(s,newname+l);
833 DEBUG(3,("reduced to %s\n",s));