Renamed vfs_init() to smbd_vfs_init() to allow vfs modules to compile.
[samba.git] / source3 / smbd / vfs.c
1 /*
2    Unix SMB/Netbios implementation.
3    Version 3.0
4    VFS initialisation and support functions
5    Copyright (C) Tim Potter 1999
6
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.
11
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.
16
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.
20 */
21
22 #include "includes.h"
23
24 /* Some structures to help us initialise the vfs operations table */
25
26 struct vfs_syminfo {
27         char *name;
28         void *fptr;
29 };
30
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. */
34
35 struct vfs_ops default_vfs_ops = {
36
37         /* Disk operations */
38
39         vfswrap_dummy_connect,
40         vfswrap_dummy_disconnect,
41         vfswrap_disk_free,
42
43         /* Directory operations */
44
45         vfswrap_opendir,
46         vfswrap_readdir,
47         vfswrap_mkdir,
48         vfswrap_rmdir,
49         vfswrap_closedir,
50
51         /* File operations */
52
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,
75
76         vfswrap_fget_nt_acl,
77         vfswrap_get_nt_acl,
78         vfswrap_fset_nt_acl,
79         vfswrap_set_nt_acl,
80
81 #if defined(HAVE_NO_ACLS)
82         NULL,
83         NULL
84 #else
85         vfswrap_chmod_acl,
86         vfswrap_fchmod_acl
87 #endif
88 };
89
90 /****************************************************************************
91   initialise default vfs hooks
92 ****************************************************************************/
93
94 static BOOL vfs_init_default(connection_struct *conn)
95 {
96     DEBUG(3, ("Initialising default vfs hooks\n"));
97
98     memcpy(&conn->vfs_ops, &default_vfs_ops, sizeof(struct vfs_ops));
99     return True;
100 }
101
102 /****************************************************************************
103   initialise custom vfs hooks
104 ****************************************************************************/
105
106 #ifdef HAVE_LIBDL
107 static BOOL vfs_init_custom(connection_struct *conn)
108 {
109         int vfs_version = -1;
110         struct vfs_ops *ops, *(*init_fptr)(int *, struct vfs_ops *);
111
112         DEBUG(3, ("Initialising custom vfs hooks from %s\n",
113                   lp_vfsobj(SNUM(conn))));
114
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;
120         }
121
122         /* Get handle on vfs_init() symbol */
123         init_fptr = (struct vfs_ops *(*)(int *, struct vfs_ops *))sys_dlsym(conn->dl_handle, "vfs_init");
124
125         if (init_fptr == NULL) {
126                 DEBUG(0, ("No vfs_init() symbol found in %s\n",
127                           lp_vfsobj(SNUM(conn))));
128                 return False;
129         }
130
131         /* Initialise vfs_ops structure */
132         conn->vfs_ops = default_vfs_ops;
133
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;
137         }
138         
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;
143         }
144         
145         if (ops != &conn->vfs_ops) {
146                 memcpy(&conn->vfs_ops, ops, sizeof(struct vfs_ops));
147         }
148
149         return True;
150 }
151 #endif
152
153 /*****************************************************************
154  Generic VFS init.
155 ******************************************************************/
156
157 BOOL smbd_vfs_init(connection_struct *conn)
158 {
159         if (*lp_vfsobj(SNUM(conn))) {
160 #ifdef HAVE_LIBDL
161  
162                 /* Loadable object file */
163  
164                 if (!vfs_init_custom(conn)) {
165                         DEBUG(0, ("smbd_vfs_init: vfs_init_custom failed\n"));
166                         return False;
167                 }
168
169                 return True;
170 #else
171                 DEBUG(0, ("smbd_vfs_init: No libdl present - cannot use VFS objects\n"));
172                 return False;
173 #endif
174         }
175  
176         /* Normal share - initialise with disk access functions */
177  
178         return vfs_init_default(conn);
179 }
180
181 /*******************************************************************
182  Check if directory exists.
183 ********************************************************************/
184
185 BOOL vfs_directory_exist(connection_struct *conn, const char *dname, SMB_STRUCT_STAT *st)
186 {
187         SMB_STRUCT_STAT st2;
188         BOOL ret;
189
190         if (!st)
191                 st = &st2;
192
193         if (vfs_stat(conn,dname,st) != 0)
194                 return(False);
195
196         ret = S_ISDIR(st->st_mode);
197         if(!ret)
198                 errno = ENOTDIR;
199
200         return ret;
201 }
202
203 /*******************************************************************
204  vfs getwd wrapper 
205 ********************************************************************/
206 char *vfs_getwd(connection_struct *conn, char *path)
207 {
208         return conn->vfs_ops.getwd(conn,path);
209 }
210
211 /*******************************************************************
212  vfs mkdir wrapper 
213 ********************************************************************/
214
215 int vfs_mkdir(connection_struct *conn, const char *name, mode_t mode)
216 {
217         int ret;
218         SMB_STRUCT_STAT sbuf;
219
220         if(!(ret=conn->vfs_ops.mkdir(conn,name,mode))) {
221                 /*
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.
225                  */
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));
229         }
230         return ret;
231 }
232
233 /*******************************************************************
234  Check if a vfs file exists.
235 ********************************************************************/
236
237 BOOL vfs_file_exist(connection_struct *conn,const char *fname,SMB_STRUCT_STAT *sbuf)
238 {
239         SMB_STRUCT_STAT st;
240
241         if (!sbuf)
242                 sbuf = &st;
243
244         ZERO_STRUCTP(sbuf);
245
246         if (vfs_stat(conn,fname,sbuf) != 0)
247                 return(False);
248
249         return(S_ISREG(sbuf->st_mode));
250 }
251
252 /****************************************************************************
253  Read data from fsp on the vfs. (note: EINTR re-read differs from vfs_write_data)
254 ****************************************************************************/
255
256 ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count)
257 {
258         size_t total=0;
259
260         while (total < byte_count)
261         {
262                 ssize_t ret = fsp->conn->vfs_ops.read(fsp, fsp->fd, buf + total,
263                                                                                           byte_count - total);
264
265                 if (ret == 0) return total;
266                 if (ret == -1) {
267                         if (errno == EINTR)
268                                 continue;
269                         else
270                                 return -1;
271                 }
272                 total += ret;
273         }
274         return (ssize_t)total;
275 }
276
277 /****************************************************************************
278  Write data to a fd on the vfs.
279 ****************************************************************************/
280
281 ssize_t vfs_write_data(files_struct *fsp,const char *buffer,size_t N)
282 {
283   size_t total=0;
284   ssize_t ret;
285
286   while (total < N)
287   {
288     ret = fsp->conn->vfs_ops.write(fsp,fsp->fd,buffer + total,N - total);
289
290     if (ret == -1) return -1;
291     if (ret == 0) return total;
292
293     total += ret;
294   }
295   return (ssize_t)total;
296 }
297
298 /****************************************************************************
299  An allocate file space call using the vfs interface.
300  Allocates space for a file from a filedescriptor.
301  Returns 0 on success, -1 on failure.
302 ****************************************************************************/
303
304 int vfs_allocate_file_space(files_struct *fsp, SMB_OFF_T len)
305 {
306         int ret;
307         SMB_STRUCT_STAT st;
308         struct vfs_ops *vfs_ops = &fsp->conn->vfs_ops;
309
310         if (!lp_strict_allocate(SNUM(fsp->conn)))
311                 return vfs_set_filelen(fsp, len);
312                 
313         release_level_2_oplocks_on_change(fsp);
314
315         /*
316          * Actually try and commit the space on disk....
317          */
318
319         DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", fsp->fsp_name, (double)len ));
320
321         ret = vfs_fstat(fsp,fsp->fd,&st);
322         if (ret == -1)
323                 return ret;
324
325         if (len == st.st_size)
326                 return 0;
327
328         if (len < st.st_size) {
329                 /* Shrink - use ftruncate. */
330
331                 DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
332                                 fsp->fsp_name, (double)st.st_size ));
333
334                 if ((ret = vfs_ops->ftruncate(fsp, fsp->fd, len)) != -1) {
335                         set_filelen_write_cache(fsp, len);
336                 }
337                 return ret;
338         }
339
340         /* Grow - we need to write out the space.... */
341         {
342                 static unsigned char zero_space[65536];
343
344                 SMB_OFF_T start_pos = st.st_size;
345                 SMB_OFF_T len_to_write = len - st.st_size;
346                 SMB_OFF_T retlen;
347
348                 DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f\n",
349                                 fsp->fsp_name, (double)st.st_size ));
350
351                 if ((retlen = vfs_ops->lseek(fsp, fsp->fd, start_pos, SEEK_SET)) != start_pos)
352                         return -1;
353
354                 while ( len_to_write > 0) {
355                         SMB_OFF_T current_len_to_write = MIN(sizeof(zero_space),len_to_write);
356
357                         retlen = vfs_ops->write(fsp,fsp->fd,(const char *)zero_space,current_len_to_write);
358                         if (retlen <= 0) {
359                                 /* Write fail - return to original size. */
360                                 int save_errno = errno;
361                                 fsp->conn->vfs_ops.ftruncate(fsp, fsp->fd, st.st_size);
362                                 errno = save_errno;
363                                 DEBUG(10,("vfs_allocate_file_space: file %s, grow. write fail %s\n",
364                                         fsp->fsp_name, strerror(errno) ));
365                                 return -1;
366                         }
367
368                         DEBUG(10,("vfs_allocate_file_space: file %s, grow. wrote %.0f\n",
369                                         fsp->fsp_name, (double)retlen ));
370
371                         len_to_write -= retlen;
372                 }
373                 set_filelen_write_cache(fsp, len);
374         }
375         return 0;
376 }
377
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 ****************************************************************************/
383
384 int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
385 {
386         int ret;
387
388         release_level_2_oplocks_on_change(fsp);
389         if ((ret = fsp->conn->vfs_ops.ftruncate(fsp, fsp->fd, len)) != -1)
390                 set_filelen_write_cache(fsp, len);
391
392         return ret;
393 }
394
395 /****************************************************************************
396  Transfer some data (n bytes) between two file_struct's.
397 ****************************************************************************/
398
399 static files_struct *in_fsp;
400 static files_struct *out_fsp;
401
402 static ssize_t read_fn(int fd, void *buf, size_t len)
403 {
404         return in_fsp->conn->vfs_ops.read(in_fsp, fd, buf, len);
405 }
406
407 static ssize_t write_fn(int fd, const void *buf, size_t len)
408 {
409         return out_fsp->conn->vfs_ops.write(out_fsp, fd, buf, len);
410 }
411
412 SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n)
413 {
414         in_fsp = in;
415         out_fsp = out;
416
417         return transfer_file_internal(in_fsp->fd, out_fsp->fd, n, read_fn, write_fn);
418 }
419
420 /*******************************************************************
421  A vfs_readdir wrapper which just returns the file name.
422 ********************************************************************/
423
424 char *vfs_readdirname(connection_struct *conn, void *p)
425 {
426         struct dirent *ptr;
427         char *dname;
428
429         if (!p)
430                 return(NULL);
431
432         ptr = (struct dirent *)conn->vfs_ops.readdir(conn,p);
433         if (!ptr)
434                 return(NULL);
435
436         dname = ptr->d_name;
437
438 #ifdef NEXT2
439         if (telldir(p) < 0)
440                 return(NULL);
441 #endif
442
443 #ifdef HAVE_BROKEN_READDIR
444         /* using /usr/ucb/cc is BAD */
445         dname = dname - 2;
446 #endif
447
448         return(dname);
449 }
450
451 /* VFS options not quite working yet */
452
453 #if 0
454
455 /***************************************************************************
456   handle the interpretation of the vfs option parameter
457  *************************************************************************/
458 static BOOL handle_vfs_option(char *pszParmValue, char **ptr)
459 {
460     struct vfs_options *new_option, **options = (struct vfs_options **)ptr;
461     int i;
462
463     /* Create new vfs option */
464
465     new_option = (struct vfs_options *)malloc(sizeof(*new_option));
466     if (new_option == NULL) {
467         return False;
468     }
469
470     ZERO_STRUCTP(new_option);
471
472     /* Get name and value */
473
474     new_option->name = strtok(pszParmValue, "=");
475
476     if (new_option->name == NULL) {
477         return False;
478     }
479
480     while(isspace(*new_option->name)) {
481         new_option->name++;
482     }
483
484     for (i = strlen(new_option->name); i > 0; i--) {
485         if (!isspace(new_option->name[i - 1])) break;
486     }
487
488     new_option->name[i] = '\0';
489     new_option->name = strdup(new_option->name);
490
491     new_option->value = strtok(NULL, "=");
492
493     if (new_option->value != NULL) {
494
495         while(isspace(*new_option->value)) {
496             new_option->value++;
497         }
498         
499         for (i = strlen(new_option->value); i > 0; i--) {
500             if (!isspace(new_option->value[i - 1])) break;
501         }
502         
503         new_option->value[i] = '\0';
504         new_option->value = strdup(new_option->value);
505     }
506
507     /* Add to list */
508
509     DLIST_ADD(*options, new_option);
510
511     return True;
512 }
513
514 #endif
515
516
517 /*******************************************************************
518  A wrapper for vfs_chdir().
519 ********************************************************************/
520
521 int vfs_ChDir(connection_struct *conn, char *path)
522 {
523         int res;
524         static pstring LastDir="";
525
526         if (strcsequal(path,"."))
527                 return(0);
528
529         if (*path == '/' && strcsequal(LastDir,path))
530                 return(0);
531
532         DEBUG(3,("vfs_ChDir to %s\n",path));
533
534         res = vfs_chdir(conn,path);
535         if (!res)
536                 pstrcpy(LastDir,path);
537         return(res);
538 }
539
540 /* number of list structures for a caching GetWd function. */
541 #define MAX_GETWDCACHE (50)
542
543 struct
544 {
545   SMB_DEV_T dev; /* These *must* be compatible with the types returned in a stat() call. */
546   SMB_INO_T inode; /* These *must* be compatible with the types returned in a stat() call. */
547   char *dos_path; /* The pathname in DOS format. */
548   BOOL valid;
549 } ino_list[MAX_GETWDCACHE];
550
551 extern BOOL use_getwd_cache;
552
553 /****************************************************************************
554  Prompte a ptr (to make it recently used)
555 ****************************************************************************/
556
557 static void array_promote(char *array,int elsize,int element)
558 {
559         char *p;
560         if (element == 0)
561                 return;
562
563         p = (char *)malloc(elsize);
564
565         if (!p) {
566                 DEBUG(5,("array_promote: malloc fail\n"));
567                 return;
568         }
569
570         memcpy(p,array + element * elsize, elsize);
571         memmove(array + elsize,array,elsize*element);
572         memcpy(array,p,elsize);
573         SAFE_FREE(p);
574 }
575
576 /*******************************************************************
577  Return the absolute current directory path - given a UNIX pathname.
578  Note that this path is returned in DOS format, not UNIX
579  format. Note this can be called with conn == NULL.
580 ********************************************************************/
581
582 char *vfs_GetWd(connection_struct *conn, char *path)
583 {
584   pstring s;
585   static BOOL getwd_cache_init = False;
586   SMB_STRUCT_STAT st, st2;
587   int i;
588
589   *s = 0;
590
591   if (!use_getwd_cache)
592     return(vfs_getwd(conn,path));
593
594   /* init the cache */
595   if (!getwd_cache_init)
596   {
597     getwd_cache_init = True;
598     for (i=0;i<MAX_GETWDCACHE;i++)
599     {
600       string_set(&ino_list[i].dos_path,"");
601       ino_list[i].valid = False;
602     }
603   }
604
605   /*  Get the inode of the current directory, if this doesn't work we're
606       in trouble :-) */
607
608   if (vfs_stat(conn, ".",&st) == -1)
609   {
610     DEBUG(0,("Very strange, couldn't stat \".\" path=%s\n", path));
611     return(vfs_getwd(conn,path));
612   }
613
614
615   for (i=0; i<MAX_GETWDCACHE; i++)
616     if (ino_list[i].valid)
617     {
618
619       /*  If we have found an entry with a matching inode and dev number
620           then find the inode number for the directory in the cached string.
621           If this agrees with that returned by the stat for the current
622           directory then all is o.k. (but make sure it is a directory all
623           the same...) */
624
625       if (st.st_ino == ino_list[i].inode &&
626           st.st_dev == ino_list[i].dev)
627       {
628         if (vfs_stat(conn,ino_list[i].dos_path,&st2) == 0)
629         {
630           if (st.st_ino == st2.st_ino &&
631               st.st_dev == st2.st_dev &&
632               (st2.st_mode & S_IFMT) == S_IFDIR)
633           {
634             pstrcpy (path, ino_list[i].dos_path);
635
636             /* promote it for future use */
637             array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
638             return (path);
639           }
640           else
641           {
642             /*  If the inode is different then something's changed,
643                 scrub the entry and start from scratch. */
644             ino_list[i].valid = False;
645           }
646         }
647       }
648     }
649
650
651   /*  We don't have the information to hand so rely on traditional methods.
652       The very slow getcwd, which spawns a process on some systems, or the
653       not quite so bad getwd. */
654
655   if (!vfs_getwd(conn,s))
656   {
657     DEBUG(0,("vfs_GetWd: vfs_getwd call failed, errno %s\n",strerror(errno)));
658     return (NULL);
659   }
660
661   pstrcpy(path,s);
662
663   DEBUG(5,("vfs_GetWd %s, inode %.0f, dev %.0f\n",s,(double)st.st_ino,(double)st.st_dev));
664
665   /* add it to the cache */
666   i = MAX_GETWDCACHE - 1;
667   string_set(&ino_list[i].dos_path,s);
668   ino_list[i].dev = st.st_dev;
669   ino_list[i].inode = st.st_ino;
670   ino_list[i].valid = True;
671
672   /* put it at the top of the list */
673   array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
674
675   return (path);
676 }
677
678 /*******************************************************************
679  Reduce a file name, removing .. elements and checking that
680  it is below dir in the heirachy. This uses vfs_GetWd() and so must be run
681  on the system that has the referenced file system.
682  Widelinks are allowed if widelinks is true.
683 ********************************************************************/
684
685 BOOL reduce_name(connection_struct *conn, char *s,char *dir,BOOL widelinks)
686 {
687 #ifndef REDUCE_PATHS
688   return True;
689 #else
690   pstring dir2;
691   pstring wd;
692   pstring base_name;
693   pstring newname;
694   char *p=NULL;
695   BOOL relative = (*s != '/');
696
697   *dir2 = *wd = *base_name = *newname = 0;
698
699   if (widelinks)
700   {
701     unix_clean_name(s);
702     /* can't have a leading .. */
703     if (strncmp(s,"..",2) == 0 && (s[2]==0 || s[2]=='/'))
704     {
705       DEBUG(3,("Illegal file name? (%s)\n",s));
706       return(False);
707     }
708
709     if (strlen(s) == 0)
710       pstrcpy(s,"./");
711
712     return(True);
713   }
714
715   DEBUG(3,("reduce_name [%s] [%s]\n",s,dir));
716
717   /* remove any double slashes */
718   all_string_sub(s,"//","/",0);
719
720   pstrcpy(base_name,s);
721   p = strrchr_m(base_name,'/');
722
723   if (!p)
724     return(True);
725
726   if (!vfs_GetWd(conn,wd))
727   {
728     DEBUG(0,("couldn't vfs_GetWd for %s %s\n",s,dir));
729     return(False);
730   }
731
732   if (vfs_ChDir(conn,dir) != 0)
733   {
734     DEBUG(0,("couldn't vfs_ChDir to %s\n",dir));
735     return(False);
736   }
737
738   if (!vfs_GetWd(conn,dir2))
739   {
740     DEBUG(0,("couldn't vfs_GetWd for %s\n",dir));
741     vfs_ChDir(conn,wd);
742     return(False);
743   }
744
745   if (p && (p != base_name))
746   {
747     *p = 0;
748     if (strcmp(p+1,".")==0)
749       p[1]=0;
750     if (strcmp(p+1,"..")==0)
751       *p = '/';
752   }
753
754   if (vfs_ChDir(conn,base_name) != 0)
755   {
756     vfs_ChDir(conn,wd);
757     DEBUG(3,("couldn't vfs_ChDir for %s %s basename=%s\n",s,dir,base_name));
758     return(False);
759   }
760
761   if (!vfs_GetWd(conn,newname))
762   {
763     vfs_ChDir(conn,wd);
764     DEBUG(2,("couldn't get vfs_GetWd for %s %s\n",s,dir2));
765     return(False);
766   }
767
768   if (p && (p != base_name))
769   {
770     pstrcat(newname,"/");
771     pstrcat(newname,p+1);
772   }
773
774   {
775     size_t l = strlen(dir2);
776     if (dir2[l-1] == '/')
777       l--;
778
779     if (strncmp(newname,dir2,l) != 0)
780     {
781       vfs_ChDir(conn,wd);
782       DEBUG(2,("Bad access attempt? s=%s dir=%s newname=%s l=%d\n",s,dir2,newname,(int)l));
783       return(False);
784     }
785
786     if (relative)
787     {
788       if (newname[l] == '/')
789         pstrcpy(s,newname + l + 1);
790       else
791         pstrcpy(s,newname+l);
792     }
793     else
794       pstrcpy(s,newname);
795   }
796
797   vfs_ChDir(conn,wd);
798
799   if (strlen(s) == 0)
800     pstrcpy(s,"./");
801
802   DEBUG(3,("reduced to %s\n",s));
803   return(True);
804 #endif
805 }