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 ****************************************************************************/
132 static BOOL vfs_init_custom(connection_struct *conn)
134 int vfs_version = -1;
135 struct vfs_ops *ops, *(*init_fptr)(int *, struct vfs_ops *);
137 DEBUG(3, ("Initialising custom vfs hooks from %s\n", lp_vfsobj(SNUM(conn))));
139 /* Open object file */
141 if ((conn->dl_handle = sys_dlopen(lp_vfsobj(SNUM(conn)), RTLD_NOW | RTLD_GLOBAL)) == NULL) {
142 DEBUG(0, ("Error opening %s: %s\n", lp_vfsobj(SNUM(conn)), dlerror()));
146 /* Get handle on vfs_init() symbol */
148 init_fptr = (struct vfs_ops *(*)(int *, struct vfs_ops *))sys_dlsym(conn->dl_handle, "vfs_init");
150 if (init_fptr == NULL) {
151 DEBUG(0, ("No vfs_init() symbol found in %s\n", lp_vfsobj(SNUM(conn))));
155 /* Initialise vfs_ops structure */
157 conn->vfs_ops = default_vfs_ops;
159 if ((ops = init_fptr(&vfs_version, &default_vfs_ops)) == NULL) {
160 DEBUG(0, ("vfs_init function from %s failed\n", lp_vfsobj(SNUM(conn))));
164 if (vfs_version != SMB_VFS_INTERFACE_VERSION) {
165 DEBUG(0, ("vfs_init returned wrong interface version info (was %d, should be %d)\n",
166 vfs_version, SMB_VFS_INTERFACE_VERSION ));
170 if (ops != &conn->vfs_ops) {
171 memcpy(&conn->vfs_ops, ops, sizeof(struct vfs_ops));
177 /*****************************************************************
179 ******************************************************************/
181 BOOL smbd_vfs_init(connection_struct *conn)
183 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"));
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)
212 if (vfs_stat(conn,dname,st) != 0)
215 ret = S_ISDIR(st->st_mode);
222 /*******************************************************************
224 ********************************************************************/
225 char *vfs_getwd(connection_struct *conn, char *path)
227 return conn->vfs_ops.getwd(conn,path);
230 /*******************************************************************
232 ********************************************************************/
234 int vfs_mkdir(connection_struct *conn, const char *name, mode_t mode)
237 SMB_STRUCT_STAT sbuf;
239 if(!(ret=conn->vfs_ops.mkdir(conn,name,mode))) {
241 * Check if high bits should have been set,
242 * then (if bits are missing): add them.
243 * Consider bits automagically set by UNIX, i.e. SGID bit from parent dir.
245 if(mode & ~(S_IRWXU|S_IRWXG|S_IRWXO) &&
246 !vfs_stat(conn,name,&sbuf) && (mode & ~sbuf.st_mode))
247 vfs_chmod(conn,name,sbuf.st_mode | (mode & ~sbuf.st_mode));
252 /*******************************************************************
253 Check if an object exists in the vfs.
254 ********************************************************************/
256 BOOL vfs_object_exist(connection_struct *conn,const char *fname,SMB_STRUCT_STAT *sbuf)
265 if (vfs_stat(conn,fname,sbuf) == -1)
270 /*******************************************************************
271 Check if a file exists in the vfs.
272 ********************************************************************/
274 BOOL vfs_file_exist(connection_struct *conn, const char *fname,SMB_STRUCT_STAT *sbuf)
283 if (vfs_stat(conn,fname,sbuf) == -1)
285 return(S_ISREG(sbuf->st_mode));
288 /****************************************************************************
289 Read data from fsp on the vfs. (note: EINTR re-read differs from vfs_write_data)
290 ****************************************************************************/
292 ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count)
296 while (total < byte_count)
298 ssize_t ret = fsp->conn->vfs_ops.read(fsp, fsp->fd, buf + total,
301 if (ret == 0) return total;
310 return (ssize_t)total;
313 /****************************************************************************
314 Write data to a fd on the vfs.
315 ****************************************************************************/
317 ssize_t vfs_write_data(files_struct *fsp,const char *buffer,size_t N)
323 ret = fsp->conn->vfs_ops.write(fsp,fsp->fd,buffer + total,N - total);
332 return (ssize_t)total;
335 /****************************************************************************
336 An allocate file space call using the vfs interface.
337 Allocates space for a file from a filedescriptor.
338 Returns 0 on success, -1 on failure.
339 ****************************************************************************/
341 int vfs_allocate_file_space(files_struct *fsp, SMB_OFF_T len)
345 connection_struct *conn = fsp->conn;
346 struct vfs_ops *vfs_ops = &conn->vfs_ops;
347 SMB_OFF_T space_avail;
348 SMB_BIG_UINT bsize,dfree,dsize;
350 release_level_2_oplocks_on_change(fsp);
353 * Actually try and commit the space on disk....
356 DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", fsp->fsp_name, (double)len ));
358 ret = vfs_fstat(fsp,fsp->fd,&st);
362 if (len == st.st_size)
365 if (len < st.st_size) {
366 /* Shrink - use ftruncate. */
368 DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
369 fsp->fsp_name, (double)st.st_size ));
371 flush_write_cache(fsp, SIZECHANGE_FLUSH);
372 if ((ret = vfs_ops->ftruncate(fsp, fsp->fd, len)) != -1) {
373 set_filelen_write_cache(fsp, len);
378 /* Grow - we need to test if we have enough space. */
380 if (!lp_strict_allocate(SNUM(fsp->conn)))
384 len /= 1024; /* Len is now number of 1k blocks needed. */
385 space_avail = (SMB_OFF_T)conn->vfs_ops.disk_free(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize);
387 DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %lu, space avail = %lu\n",
388 fsp->fsp_name, (double)st.st_size, (unsigned long)len, (unsigned long)space_avail ));
390 if (len > space_avail) {
398 /****************************************************************************
399 A vfs set_filelen call.
400 set the length of a file from a filedescriptor.
401 Returns 0 on success, -1 on failure.
402 ****************************************************************************/
404 int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
408 release_level_2_oplocks_on_change(fsp);
409 DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len));
410 flush_write_cache(fsp, SIZECHANGE_FLUSH);
411 if ((ret = fsp->conn->vfs_ops.ftruncate(fsp, fsp->fd, len)) != -1)
412 set_filelen_write_cache(fsp, len);
417 /****************************************************************************
418 Transfer some data (n bytes) between two file_struct's.
419 ****************************************************************************/
421 static files_struct *in_fsp;
422 static files_struct *out_fsp;
424 static ssize_t read_fn(int fd, void *buf, size_t len)
426 return in_fsp->conn->vfs_ops.read(in_fsp, fd, buf, len);
429 static ssize_t write_fn(int fd, const void *buf, size_t len)
431 return out_fsp->conn->vfs_ops.write(out_fsp, fd, buf, len);
434 SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n)
439 return transfer_file_internal(in_fsp->fd, out_fsp->fd, n, read_fn, write_fn);
442 /*******************************************************************
443 A vfs_readdir wrapper which just returns the file name.
444 ********************************************************************/
446 char *vfs_readdirname(connection_struct *conn, void *p)
454 ptr = (struct dirent *)conn->vfs_ops.readdir(conn,p);
465 #ifdef HAVE_BROKEN_READDIR
466 /* using /usr/ucb/cc is BAD */
473 /* VFS options not quite working yet */
477 /***************************************************************************
478 handle the interpretation of the vfs option parameter
479 *************************************************************************/
480 static BOOL handle_vfs_option(char *pszParmValue, char **ptr)
482 struct vfs_options *new_option, **options = (struct vfs_options **)ptr;
485 /* Create new vfs option */
487 new_option = (struct vfs_options *)malloc(sizeof(*new_option));
488 if (new_option == NULL) {
492 ZERO_STRUCTP(new_option);
494 /* Get name and value */
496 new_option->name = strtok(pszParmValue, "=");
498 if (new_option->name == NULL) {
502 while(isspace(*new_option->name)) {
506 for (i = strlen(new_option->name); i > 0; i--) {
507 if (!isspace(new_option->name[i - 1])) break;
510 new_option->name[i] = '\0';
511 new_option->name = strdup(new_option->name);
513 new_option->value = strtok(NULL, "=");
515 if (new_option->value != NULL) {
517 while(isspace(*new_option->value)) {
521 for (i = strlen(new_option->value); i > 0; i--) {
522 if (!isspace(new_option->value[i - 1])) break;
525 new_option->value[i] = '\0';
526 new_option->value = strdup(new_option->value);
531 DLIST_ADD(*options, new_option);
539 /*******************************************************************
540 A wrapper for vfs_chdir().
541 ********************************************************************/
543 int vfs_ChDir(connection_struct *conn, char *path)
546 static pstring LastDir="";
548 if (strcsequal(path,"."))
551 if (*path == '/' && strcsequal(LastDir,path))
554 DEBUG(3,("vfs_ChDir to %s\n",path));
556 res = vfs_chdir(conn,path);
558 pstrcpy(LastDir,path);
562 /* number of list structures for a caching GetWd function. */
563 #define MAX_GETWDCACHE (50)
566 SMB_DEV_T dev; /* These *must* be compatible with the types returned in a stat() call. */
567 SMB_INO_T inode; /* These *must* be compatible with the types returned in a stat() call. */
568 char *dos_path; /* The pathname in DOS format. */
570 } ino_list[MAX_GETWDCACHE];
572 extern BOOL use_getwd_cache;
574 /****************************************************************************
575 Prompte a ptr (to make it recently used)
576 ****************************************************************************/
578 static void array_promote(char *array,int elsize,int element)
584 p = (char *)malloc(elsize);
587 DEBUG(5,("array_promote: malloc fail\n"));
591 memcpy(p,array + element * elsize, elsize);
592 memmove(array + elsize,array,elsize*element);
593 memcpy(array,p,elsize);
597 /*******************************************************************
598 Return the absolute current directory path - given a UNIX pathname.
599 Note that this path is returned in DOS format, not UNIX
600 format. Note this can be called with conn == NULL.
601 ********************************************************************/
603 char *vfs_GetWd(connection_struct *conn, char *path)
606 static BOOL getwd_cache_init = False;
607 SMB_STRUCT_STAT st, st2;
612 if (!use_getwd_cache)
613 return(vfs_getwd(conn,path));
616 if (!getwd_cache_init) {
617 getwd_cache_init = True;
618 for (i=0;i<MAX_GETWDCACHE;i++) {
619 string_set(&ino_list[i].dos_path,"");
620 ino_list[i].valid = False;
624 /* Get the inode of the current directory, if this doesn't work we're
627 if (vfs_stat(conn, ".",&st) == -1) {
628 DEBUG(0,("Very strange, couldn't stat \".\" path=%s\n", path));
629 return(vfs_getwd(conn,path));
633 for (i=0; i<MAX_GETWDCACHE; i++) {
634 if (ino_list[i].valid) {
636 /* If we have found an entry with a matching inode and dev number
637 then find the inode number for the directory in the cached string.
638 If this agrees with that returned by the stat for the current
639 directory then all is o.k. (but make sure it is a directory all
642 if (st.st_ino == ino_list[i].inode && st.st_dev == ino_list[i].dev) {
643 if (vfs_stat(conn,ino_list[i].dos_path,&st2) == 0) {
644 if (st.st_ino == st2.st_ino && st.st_dev == st2.st_dev &&
645 (st2.st_mode & S_IFMT) == S_IFDIR) {
646 pstrcpy (path, ino_list[i].dos_path);
648 /* promote it for future use */
649 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
652 /* If the inode is different then something's changed,
653 scrub the entry and start from scratch. */
654 ino_list[i].valid = False;
661 /* We don't have the information to hand so rely on traditional methods.
662 The very slow getcwd, which spawns a process on some systems, or the
663 not quite so bad getwd. */
665 if (!vfs_getwd(conn,s)) {
666 DEBUG(0,("vfs_GetWd: vfs_getwd call failed, errno %s\n",strerror(errno)));
672 DEBUG(5,("vfs_GetWd %s, inode %.0f, dev %.0f\n",s,(double)st.st_ino,(double)st.st_dev));
674 /* add it to the cache */
675 i = MAX_GETWDCACHE - 1;
676 string_set(&ino_list[i].dos_path,s);
677 ino_list[i].dev = st.st_dev;
678 ino_list[i].inode = st.st_ino;
679 ino_list[i].valid = True;
681 /* put it at the top of the list */
682 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
687 /*******************************************************************
688 Reduce a file name, removing .. elements and checking that
689 it is below dir in the heirachy. This uses vfs_GetWd() and so must be run
690 on the system that has the referenced file system.
691 Widelinks are allowed if widelinks is true.
692 ********************************************************************/
694 BOOL reduce_name(connection_struct *conn, char *s,char *dir,BOOL widelinks)
704 BOOL relative = (*s != '/');
706 *dir2 = *wd = *base_name = *newname = 0;
710 /* can't have a leading .. */
711 if (strncmp(s,"..",2) == 0 && (s[2]==0 || s[2]=='/')) {
712 DEBUG(3,("Illegal file name? (%s)\n",s));
722 DEBUG(3,("reduce_name [%s] [%s]\n",s,dir));
724 /* remove any double slashes */
725 all_string_sub(s,"//","/",0);
727 pstrcpy(base_name,s);
728 p = strrchr_m(base_name,'/');
733 if (!vfs_GetWd(conn,wd)) {
734 DEBUG(0,("couldn't vfs_GetWd for %s %s\n",s,dir));
738 if (vfs_ChDir(conn,dir) != 0) {
739 DEBUG(0,("couldn't vfs_ChDir to %s\n",dir));
743 if (!vfs_GetWd(conn,dir2)) {
744 DEBUG(0,("couldn't vfs_GetWd for %s\n",dir));
749 if (p && (p != base_name)) {
751 if (strcmp(p+1,".")==0)
753 if (strcmp(p+1,"..")==0)
757 if (vfs_ChDir(conn,base_name) != 0) {
759 DEBUG(3,("couldn't vfs_ChDir for %s %s basename=%s\n",s,dir,base_name));
763 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)) {
770 pstrcat(newname,"/");
771 pstrcat(newname,p+1);
775 size_t l = strlen(dir2);
776 if (dir2[l-1] == '/')
779 if (strncmp(newname,dir2,l) != 0) {
781 DEBUG(2,("Bad access attempt? s=%s dir=%s newname=%s l=%d\n",s,dir2,newname,(int)l));
786 if (newname[l] == '/')
787 pstrcpy(s,newname + l + 1);
789 pstrcpy(s,newname+l);
799 DEBUG(3,("reduced to %s\n",s));