preparing for release of 3.0-alpha11
[Samba/ekacnet.git] / source / smbd / vfs.c
blob6d8e9cc76c2758519c60de3bbf49ee1fb5f7c618
1 /*
2 Unix SMB/Netbios implementation.
3 Version 3.0
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 static 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_rename,
59 vfswrap_fsync,
60 vfswrap_stat,
61 vfswrap_fstat,
62 vfswrap_lstat,
63 vfswrap_unlink,
64 vfswrap_chmod,
65 vfswrap_fchmod,
66 vfswrap_chown,
67 vfswrap_fchown,
68 vfswrap_chdir,
69 vfswrap_getwd,
70 vfswrap_utime,
71 vfswrap_ftruncate,
72 vfswrap_lock,
73 vfswrap_symlink,
74 vfswrap_readlink,
76 vfswrap_fget_nt_acl,
77 vfswrap_get_nt_acl,
78 vfswrap_fset_nt_acl,
79 vfswrap_set_nt_acl,
81 #if defined(HAVE_NO_ACLS)
82 NULL,
83 NULL
84 #else
85 vfswrap_chmod_acl,
86 vfswrap_fchmod_acl
87 #endif
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));
99 return True;
102 /****************************************************************************
103 initialise custom vfs hooks
104 ****************************************************************************/
106 #ifdef HAVE_LIBDL
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()));
119 return False;
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))));
128 return False;
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))));
136 return False;
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 ));
142 return False;
145 if (ops != &conn->vfs_ops) {
146 memcpy(&conn->vfs_ops, ops, sizeof(struct vfs_ops));
149 return True;
151 #endif
153 /*****************************************************************
154 Generic VFS init.
155 ******************************************************************/
157 BOOL smbd_vfs_init(connection_struct *conn)
159 if (*lp_vfsobj(SNUM(conn))) {
160 #ifdef HAVE_LIBDL
162 /* Loadable object file */
164 if (!vfs_init_custom(conn)) {
165 DEBUG(0, ("smbd_vfs_init: vfs_init_custom failed\n"));
166 return False;
169 return True;
170 #else
171 DEBUG(0, ("smbd_vfs_init: No libdl present - cannot use VFS objects\n"));
172 return False;
173 #endif
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)
187 SMB_STRUCT_STAT st2;
188 BOOL ret;
190 if (!st)
191 st = &st2;
193 if (vfs_stat(conn,dname,st) != 0)
194 return(False);
196 ret = S_ISDIR(st->st_mode);
197 if(!ret)
198 errno = ENOTDIR;
200 return ret;
203 /*******************************************************************
204 vfs getwd wrapper
205 ********************************************************************/
206 char *vfs_getwd(connection_struct *conn, char *path)
208 return conn->vfs_ops.getwd(conn,path);
211 /*******************************************************************
212 vfs mkdir wrapper
213 ********************************************************************/
215 int vfs_mkdir(connection_struct *conn, const char *name, mode_t mode)
217 int ret;
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));
230 return ret;
233 /*******************************************************************
234 Check if a vfs file exists.
235 ********************************************************************/
237 BOOL vfs_file_exist(connection_struct *conn,const char *fname,SMB_STRUCT_STAT *sbuf)
239 SMB_STRUCT_STAT st;
241 if (!sbuf)
242 sbuf = &st;
244 ZERO_STRUCTP(sbuf);
246 if (vfs_stat(conn,fname,sbuf) != 0)
247 return(False);
249 return(S_ISREG(sbuf->st_mode));
252 /****************************************************************************
253 Read data from fsp on the vfs. (note: EINTR re-read differs from vfs_write_data)
254 ****************************************************************************/
256 ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count)
258 size_t total=0;
260 while (total < byte_count)
262 ssize_t ret = fsp->conn->vfs_ops.read(fsp, fsp->fd, buf + total,
263 byte_count - total);
265 if (ret == 0) return total;
266 if (ret == -1) {
267 if (errno == EINTR)
268 continue;
269 else
270 return -1;
272 total += ret;
274 return (ssize_t)total;
277 /****************************************************************************
278 Write data to a fd on the vfs.
279 ****************************************************************************/
281 ssize_t vfs_write_data(files_struct *fsp,const char *buffer,size_t N)
283 size_t total=0;
284 ssize_t ret;
286 while (total < N) {
287 ret = fsp->conn->vfs_ops.write(fsp,fsp->fd,buffer + total,N - total);
289 if (ret == -1)
290 return -1;
291 if (ret == 0)
292 return total;
294 total += ret;
296 return (ssize_t)total;
299 /****************************************************************************
300 An allocate file space call using the vfs interface.
301 Allocates space for a file from a filedescriptor.
302 Returns 0 on success, -1 on failure.
303 ****************************************************************************/
305 int vfs_allocate_file_space(files_struct *fsp, SMB_OFF_T len)
307 int ret;
308 SMB_STRUCT_STAT st;
309 connection_struct *conn = fsp->conn;
310 struct vfs_ops *vfs_ops = &conn->vfs_ops;
311 SMB_OFF_T space_avail;
312 SMB_BIG_UINT bsize,dfree,dsize;
314 release_level_2_oplocks_on_change(fsp);
317 * Actually try and commit the space on disk....
320 DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", fsp->fsp_name, (double)len ));
322 ret = vfs_fstat(fsp,fsp->fd,&st);
323 if (ret == -1)
324 return ret;
326 if (len == st.st_size)
327 return 0;
329 if (len < st.st_size) {
330 /* Shrink - use ftruncate. */
332 DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
333 fsp->fsp_name, (double)st.st_size ));
335 if ((ret = vfs_ops->ftruncate(fsp, fsp->fd, len)) != -1) {
336 set_filelen_write_cache(fsp, len);
338 return ret;
341 /* Grow - we need to test if we have enough space. */
343 if (!lp_strict_allocate(SNUM(fsp->conn)))
344 return 0;
346 len -= st.st_size;
347 len /= 1024; /* Len is now number of 1k blocks needed. */
348 space_avail = (SMB_OFF_T)conn->vfs_ops.disk_free(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize);
350 DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %lu, space avail = %lu\n",
351 fsp->fsp_name, (double)st.st_size, (unsigned long)len, (unsigned long)space_avail ));
353 if (len > space_avail) {
354 errno = ENOSPC;
355 return -1;
358 return 0;
361 /****************************************************************************
362 A vfs set_filelen call.
363 set the length of a file from a filedescriptor.
364 Returns 0 on success, -1 on failure.
365 ****************************************************************************/
367 int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
369 int ret;
371 release_level_2_oplocks_on_change(fsp);
372 DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len));
373 if ((ret = fsp->conn->vfs_ops.ftruncate(fsp, fsp->fd, len)) != -1)
374 set_filelen_write_cache(fsp, len);
376 return ret;
379 /****************************************************************************
380 Transfer some data (n bytes) between two file_struct's.
381 ****************************************************************************/
383 static files_struct *in_fsp;
384 static files_struct *out_fsp;
386 static ssize_t read_fn(int fd, void *buf, size_t len)
388 return in_fsp->conn->vfs_ops.read(in_fsp, fd, buf, len);
391 static ssize_t write_fn(int fd, const void *buf, size_t len)
393 return out_fsp->conn->vfs_ops.write(out_fsp, fd, buf, len);
396 SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n)
398 in_fsp = in;
399 out_fsp = out;
401 return transfer_file_internal(in_fsp->fd, out_fsp->fd, n, read_fn, write_fn);
404 /*******************************************************************
405 A vfs_readdir wrapper which just returns the file name.
406 ********************************************************************/
408 char *vfs_readdirname(connection_struct *conn, void *p)
410 struct dirent *ptr;
411 char *dname;
413 if (!p)
414 return(NULL);
416 ptr = (struct dirent *)conn->vfs_ops.readdir(conn,p);
417 if (!ptr)
418 return(NULL);
420 dname = ptr->d_name;
422 #ifdef NEXT2
423 if (telldir(p) < 0)
424 return(NULL);
425 #endif
427 #ifdef HAVE_BROKEN_READDIR
428 /* using /usr/ucb/cc is BAD */
429 dname = dname - 2;
430 #endif
432 return(dname);
435 /* VFS options not quite working yet */
437 #if 0
439 /***************************************************************************
440 handle the interpretation of the vfs option parameter
441 *************************************************************************/
442 static BOOL handle_vfs_option(char *pszParmValue, char **ptr)
444 struct vfs_options *new_option, **options = (struct vfs_options **)ptr;
445 int i;
447 /* Create new vfs option */
449 new_option = (struct vfs_options *)malloc(sizeof(*new_option));
450 if (new_option == NULL) {
451 return False;
454 ZERO_STRUCTP(new_option);
456 /* Get name and value */
458 new_option->name = strtok(pszParmValue, "=");
460 if (new_option->name == NULL) {
461 return False;
464 while(isspace(*new_option->name)) {
465 new_option->name++;
468 for (i = strlen(new_option->name); i > 0; i--) {
469 if (!isspace(new_option->name[i - 1])) break;
472 new_option->name[i] = '\0';
473 new_option->name = strdup(new_option->name);
475 new_option->value = strtok(NULL, "=");
477 if (new_option->value != NULL) {
479 while(isspace(*new_option->value)) {
480 new_option->value++;
483 for (i = strlen(new_option->value); i > 0; i--) {
484 if (!isspace(new_option->value[i - 1])) break;
487 new_option->value[i] = '\0';
488 new_option->value = strdup(new_option->value);
491 /* Add to list */
493 DLIST_ADD(*options, new_option);
495 return True;
498 #endif
501 /*******************************************************************
502 A wrapper for vfs_chdir().
503 ********************************************************************/
505 int vfs_ChDir(connection_struct *conn, char *path)
507 int res;
508 static pstring LastDir="";
510 if (strcsequal(path,"."))
511 return(0);
513 if (*path == '/' && strcsequal(LastDir,path))
514 return(0);
516 DEBUG(3,("vfs_ChDir to %s\n",path));
518 res = vfs_chdir(conn,path);
519 if (!res)
520 pstrcpy(LastDir,path);
521 return(res);
524 /* number of list structures for a caching GetWd function. */
525 #define MAX_GETWDCACHE (50)
527 struct
529 SMB_DEV_T dev; /* These *must* be compatible with the types returned in a stat() call. */
530 SMB_INO_T inode; /* These *must* be compatible with the types returned in a stat() call. */
531 char *dos_path; /* The pathname in DOS format. */
532 BOOL valid;
533 } ino_list[MAX_GETWDCACHE];
535 extern BOOL use_getwd_cache;
537 /****************************************************************************
538 Prompte a ptr (to make it recently used)
539 ****************************************************************************/
541 static void array_promote(char *array,int elsize,int element)
543 char *p;
544 if (element == 0)
545 return;
547 p = (char *)malloc(elsize);
549 if (!p) {
550 DEBUG(5,("array_promote: malloc fail\n"));
551 return;
554 memcpy(p,array + element * elsize, elsize);
555 memmove(array + elsize,array,elsize*element);
556 memcpy(array,p,elsize);
557 SAFE_FREE(p);
560 /*******************************************************************
561 Return the absolute current directory path - given a UNIX pathname.
562 Note that this path is returned in DOS format, not UNIX
563 format. Note this can be called with conn == NULL.
564 ********************************************************************/
566 char *vfs_GetWd(connection_struct *conn, char *path)
568 pstring s;
569 static BOOL getwd_cache_init = False;
570 SMB_STRUCT_STAT st, st2;
571 int i;
573 *s = 0;
575 if (!use_getwd_cache)
576 return(vfs_getwd(conn,path));
578 /* init the cache */
579 if (!getwd_cache_init)
581 getwd_cache_init = True;
582 for (i=0;i<MAX_GETWDCACHE;i++)
584 string_set(&ino_list[i].dos_path,"");
585 ino_list[i].valid = False;
589 /* Get the inode of the current directory, if this doesn't work we're
590 in trouble :-) */
592 if (vfs_stat(conn, ".",&st) == -1)
594 DEBUG(0,("Very strange, couldn't stat \".\" path=%s\n", path));
595 return(vfs_getwd(conn,path));
599 for (i=0; i<MAX_GETWDCACHE; i++)
600 if (ino_list[i].valid)
603 /* If we have found an entry with a matching inode and dev number
604 then find the inode number for the directory in the cached string.
605 If this agrees with that returned by the stat for the current
606 directory then all is o.k. (but make sure it is a directory all
607 the same...) */
609 if (st.st_ino == ino_list[i].inode &&
610 st.st_dev == ino_list[i].dev)
612 if (vfs_stat(conn,ino_list[i].dos_path,&st2) == 0)
614 if (st.st_ino == st2.st_ino &&
615 st.st_dev == st2.st_dev &&
616 (st2.st_mode & S_IFMT) == S_IFDIR)
618 pstrcpy (path, ino_list[i].dos_path);
620 /* promote it for future use */
621 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
622 return (path);
624 else
626 /* If the inode is different then something's changed,
627 scrub the entry and start from scratch. */
628 ino_list[i].valid = False;
635 /* We don't have the information to hand so rely on traditional methods.
636 The very slow getcwd, which spawns a process on some systems, or the
637 not quite so bad getwd. */
639 if (!vfs_getwd(conn,s))
641 DEBUG(0,("vfs_GetWd: vfs_getwd call failed, errno %s\n",strerror(errno)));
642 return (NULL);
645 pstrcpy(path,s);
647 DEBUG(5,("vfs_GetWd %s, inode %.0f, dev %.0f\n",s,(double)st.st_ino,(double)st.st_dev));
649 /* add it to the cache */
650 i = MAX_GETWDCACHE - 1;
651 string_set(&ino_list[i].dos_path,s);
652 ino_list[i].dev = st.st_dev;
653 ino_list[i].inode = st.st_ino;
654 ino_list[i].valid = True;
656 /* put it at the top of the list */
657 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
659 return (path);
662 /*******************************************************************
663 Reduce a file name, removing .. elements and checking that
664 it is below dir in the heirachy. This uses vfs_GetWd() and so must be run
665 on the system that has the referenced file system.
666 Widelinks are allowed if widelinks is true.
667 ********************************************************************/
669 BOOL reduce_name(connection_struct *conn, char *s,char *dir,BOOL widelinks)
671 #ifndef REDUCE_PATHS
672 return True;
673 #else
674 pstring dir2;
675 pstring wd;
676 pstring base_name;
677 pstring newname;
678 char *p=NULL;
679 BOOL relative = (*s != '/');
681 *dir2 = *wd = *base_name = *newname = 0;
683 if (widelinks)
685 unix_clean_name(s);
686 /* can't have a leading .. */
687 if (strncmp(s,"..",2) == 0 && (s[2]==0 || s[2]=='/'))
689 DEBUG(3,("Illegal file name? (%s)\n",s));
690 return(False);
693 if (strlen(s) == 0)
694 pstrcpy(s,"./");
696 return(True);
699 DEBUG(3,("reduce_name [%s] [%s]\n",s,dir));
701 /* remove any double slashes */
702 all_string_sub(s,"//","/",0);
704 pstrcpy(base_name,s);
705 p = strrchr_m(base_name,'/');
707 if (!p)
708 return(True);
710 if (!vfs_GetWd(conn,wd))
712 DEBUG(0,("couldn't vfs_GetWd for %s %s\n",s,dir));
713 return(False);
716 if (vfs_ChDir(conn,dir) != 0)
718 DEBUG(0,("couldn't vfs_ChDir to %s\n",dir));
719 return(False);
722 if (!vfs_GetWd(conn,dir2))
724 DEBUG(0,("couldn't vfs_GetWd for %s\n",dir));
725 vfs_ChDir(conn,wd);
726 return(False);
729 if (p && (p != base_name))
731 *p = 0;
732 if (strcmp(p+1,".")==0)
733 p[1]=0;
734 if (strcmp(p+1,"..")==0)
735 *p = '/';
738 if (vfs_ChDir(conn,base_name) != 0)
740 vfs_ChDir(conn,wd);
741 DEBUG(3,("couldn't vfs_ChDir for %s %s basename=%s\n",s,dir,base_name));
742 return(False);
745 if (!vfs_GetWd(conn,newname))
747 vfs_ChDir(conn,wd);
748 DEBUG(2,("couldn't get vfs_GetWd for %s %s\n",s,dir2));
749 return(False);
752 if (p && (p != base_name))
754 pstrcat(newname,"/");
755 pstrcat(newname,p+1);
759 size_t l = strlen(dir2);
760 if (dir2[l-1] == '/')
761 l--;
763 if (strncmp(newname,dir2,l) != 0)
765 vfs_ChDir(conn,wd);
766 DEBUG(2,("Bad access attempt? s=%s dir=%s newname=%s l=%d\n",s,dir2,newname,(int)l));
767 return(False);
770 if (relative)
772 if (newname[l] == '/')
773 pstrcpy(s,newname + l + 1);
774 else
775 pstrcpy(s,newname+l);
777 else
778 pstrcpy(s,newname);
781 vfs_ChDir(conn,wd);
783 if (strlen(s) == 0)
784 pstrcpy(s,"./");
786 DEBUG(3,("reduced to %s\n",s));
787 return(True);
788 #endif