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