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