Disable VFS routines if no libdl available.
[samba.git] / source3 / smbd / vfs.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    vfs initialisation and support functions
5    Copyright (C) Tim Potter 1992-1998
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 #ifdef HAVE_LIBDL
24 #include <dlfcn.h>
25 #endif
26
27 extern int DEBUGLEVEL;
28
29 /* Some structures to help us initialise the vfs operations table */
30
31 struct vfs_syminfo {
32     char *name;
33     void *fptr;
34 };
35
36 struct vfs_ops dl_ops;
37
38 struct vfs_syminfo vfs_syminfo[] = {
39
40     /* Global operations */
41
42     {"vfs_init",       &dl_ops.init},
43
44     /* Disk operations */
45
46     {"vfs_connect",    &dl_ops.connect},
47     {"vfs_disconnect", &dl_ops.disconnect},
48     {"vfs_disk_free",  &dl_ops.disk_free},
49
50     /* Directory operations */
51
52     {"vfs_opendir",    &dl_ops.opendir},
53     {"vfs_readdir",    &dl_ops.readdir},
54     {"vfs_mkdir",      &dl_ops.mkdir},
55     {"vfs_rmdir",      &dl_ops.rmdir},
56
57     /* File operations */
58
59     {"vfs_open",       &dl_ops.open},
60     {"vfs_close",      &dl_ops.close},
61     {"vfs_read",       &dl_ops.read},
62     {"vfs_write",      &dl_ops.write},
63     {"vfs_lseek",      &dl_ops.lseek},
64     {"vfs_rename",     &dl_ops.rename},
65     {"vfs_sync",       &dl_ops.sync},
66     {"vfs_stat",       &dl_ops.stat},
67     {"vfs_fstat",      &dl_ops.fstat},
68     {"vfs_lstat",      &dl_ops.lstat},
69     {"vfs_lock",       &dl_ops.lock},
70     {"vfs_unlink",     &dl_ops.unlink},
71     {"vfs_chmod",      &dl_ops.chmod},
72     {"vfs_utime",      &dl_ops.utime},
73     
74     {NULL, 0}
75 };
76
77 /* Default vfs hooks.  WARNING: The order of these initialisers is
78    very important.  Change at your own peril. */
79
80 struct vfs_ops default_vfs_ops = {
81
82     /* Global operations */
83
84     NULL,                         /* init */
85
86     /* Disk operations */        
87
88     NULL,                         /* connect */
89     NULL,                         /* disconnect */
90     vfswrap_disk_free,
91
92     /* Directory operations */
93
94     vfswrap_opendir,
95     vfswrap_readdir,
96     vfswrap_mkdir,
97     vfswrap_rmdir,
98
99     /* File operations */
100
101     vfswrap_open,
102     vfswrap_close,
103     vfswrap_read,
104     vfswrap_write,
105     vfswrap_lseek,
106     vfswrap_rename,
107     vfswrap_sync_file,
108     vfswrap_stat,
109     vfswrap_fstat,
110     vfswrap_lstat,
111     vfswrap_fcntl_lock,
112     vfswrap_unlink,
113     vfswrap_chmod,
114     vfswrap_utime
115 };
116
117 /****************************************************************************
118   call vfs_init function of loadable module
119 ****************************************************************************/
120 #ifdef HAVE_LIBDL
121 BOOL do_vfs_init(char *vfs_object)
122 {
123     void *handle, (*fptr)(void);
124
125     DEBUG(3, ("Calling vfs_init for module %s\n", vfs_object));
126
127     handle = dlopen(vfs_object, RTLD_NOW);
128     if (!handle) {
129         DEBUG(0, ("Error opening %s: %s\n", vfs_object, dlerror()));
130         return False;
131     }
132
133     fptr = dlsym(handle, "vfs_init");
134
135     /* Call initialisation function */
136
137     if (fptr != NULL) {
138         fptr();
139     }
140
141     dlclose(handle);
142
143     return True;
144 }
145 #endif
146
147 /****************************************************************************
148   initialise default vfs hooks
149 ****************************************************************************/
150 int vfs_init_default(connection_struct *conn)
151 {
152     DEBUG(3, ("Initialising default vfs hooks\n"));
153
154     bcopy(&default_vfs_ops, &conn->vfs_ops, sizeof(conn->vfs_ops));
155     return 0;
156 }
157
158 /****************************************************************************
159   initialise custom vfs hooks
160 ****************************************************************************/
161 #ifdef HAVE_LIBDL
162 int vfs_init_custom(connection_struct *conn)
163 {
164     void *handle, *fptr;
165     int index;
166
167     DEBUG(3, ("Initialising custom vfs hooks from %s\n",
168               lp_vfsobj(SNUM(conn))));
169
170     /* Open object file */
171
172     handle = dlopen(lp_vfsobj(SNUM(conn)), RTLD_NOW);
173     if (!handle) {
174         DEBUG(0, ("Error opening %s: %s\n", lp_vfsobj(SNUM(conn)),
175                   dlerror()));
176         return -1;
177     }
178
179     /* Read list of symbols */
180
181     for(index = 0; vfs_syminfo[index].name; index++) {
182         fptr = dlsym(handle, vfs_syminfo[index].name);
183         if (fptr == NULL) {
184             DEBUG(0, ("Symbol %s not found in %s\n", vfs_syminfo[index].name,
185                       lp_vfsobj(SNUM(conn))));
186             return -1;
187         }
188
189         *((void **)vfs_syminfo[index].fptr) = fptr;
190     }
191
192     /* Copy loaded symbols into connection struct */
193
194     bcopy(&dl_ops, &conn->vfs_ops, sizeof(dl_ops));
195     dlclose(handle);
196
197     do_vfs_init(lp_vfsobj(SNUM(conn)));
198
199     return 0;
200 }
201 #endif
202
203 /*******************************************************************
204   check if a vfs file exists
205 ********************************************************************/
206 BOOL vfs_file_exist(connection_struct *conn,char *fname,SMB_STRUCT_STAT *sbuf)
207 {
208   SMB_STRUCT_STAT st;
209   if (!sbuf) sbuf = &st;
210   
211   if (conn->vfs_ops.stat(fname,sbuf) != 0) 
212     return(False);
213
214   return(S_ISREG(sbuf->st_mode));
215 }
216
217 /****************************************************************************
218   read data from the client vfs, reading exactly N bytes. 
219 ****************************************************************************/
220 ssize_t vfs_read_data(files_struct *fsp,char *buffer,size_t N)
221 {
222   ssize_t  ret;
223   size_t total=0;  
224   int fd = fsp->fd_ptr->fd;
225   extern int smb_read_error;
226  
227   smb_read_error = 0;
228
229   while (total < N)
230   {
231 #ifdef WITH_SSL
232       DEBUG(0, ("WARNING: read_data() called with SSL enabled\n"));
233     if(fd == sslFd){
234       ret = SSL_read(ssl, buffer + total, N - total);
235     }else{
236       ret = read(fd,buffer + total,N - total);
237     }
238 #else /* WITH_SSL */
239     ret = fsp->conn->vfs_ops.read(fd,buffer + total,N - total);
240 #endif /* WITH_SSL */
241
242     if (ret == 0)
243     {
244       smb_read_error = READ_EOF;
245       return 0;
246     }
247     if (ret == -1)
248     {
249       smb_read_error = READ_ERROR;
250       return -1;
251     }
252     total += ret;
253   }
254   return (ssize_t)total;
255 }
256
257 /****************************************************************************
258   write data to a fd on the vfs
259 ****************************************************************************/
260 ssize_t vfs_write_data(files_struct *fsp,char *buffer,size_t N)
261 {
262   size_t total=0;
263   ssize_t ret;
264   int fd = fsp->fd_ptr->fd;
265
266   while (total < N)
267   {
268 #ifdef WITH_SSL
269       DEBUG(0, ("WARNING: write_data called with SSL enabled\n"));
270     if(fd == sslFd){
271       ret = SSL_write(ssl,buffer + total,N - total);
272     }else{
273       ret = write(fd,buffer + total,N - total);
274     }
275 #else /* WITH_SSL */
276     ret = fsp->conn->vfs_ops.write(fd,buffer + total,N - total);
277 #endif /* WITH_SSL */
278
279     if (ret == -1) return -1;
280     if (ret == 0) return total;
281
282     total += ret;
283   }
284   return (ssize_t)total;
285 }
286
287 /****************************************************************************
288 transfer some data between two file_struct's
289 ****************************************************************************/
290 SMB_OFF_T vfs_transfer_file(int in_fd, files_struct *in_fsp, 
291                             int out_fd, files_struct *out_fsp,
292                             SMB_OFF_T n, char *header, int headlen, int align)
293 {
294   static char *buf=NULL;  
295   static int size=0;
296   char *buf1,*abuf;
297   SMB_OFF_T total = 0;
298
299   DEBUG(4,("vfs_transfer_file n=%.0f  (head=%d) called\n",(double)n,headlen));
300
301   /* Check we have at least somewhere to read from */
302
303   SMB_ASSERT((in_fd != -1) || (in_fsp != NULL));
304
305   if (size == 0) {
306     size = lp_readsize();
307     size = MAX(size,1024);
308   }
309
310   while (!buf && size>0) {
311     buf = (char *)Realloc(buf,size+8);
312     if (!buf) size /= 2;
313   }
314
315   if (!buf) {
316     DEBUG(0,("Can't allocate transfer buffer!\n"));
317     exit(1);
318   }
319
320   abuf = buf + (align%8);
321
322   if (header)
323     n += headlen;
324
325   while (n > 0)
326   {
327     int s = (int)MIN(n,(SMB_OFF_T)size);
328     int ret,ret2=0;
329
330     ret = 0;
331
332     if (header && (headlen >= MIN(s,1024))) {
333       buf1 = header;
334       s = headlen;
335       ret = headlen;
336       headlen = 0;
337       header = NULL;
338     } else {
339       buf1 = abuf;
340     }
341
342     if (header && headlen > 0)
343     {
344       ret = MIN(headlen,size);
345       memcpy(buf1,header,ret);
346       headlen -= ret;
347       header += ret;
348       if (headlen <= 0) header = NULL;
349     }
350
351     if (s > ret) {
352       ret += in_fsp ? 
353           in_fsp->conn->vfs_ops.read(in_fsp->fd_ptr->fd,buf1+ret,s-ret) : read(in_fd,buf1+ret,s-ret);
354     }
355
356     if (ret > 0)
357     {
358         if (out_fsp) {
359             ret2 = out_fsp->conn->vfs_ops.write(out_fsp->fd_ptr->fd,buf1,ret);
360         } else {
361             ret2= (out_fd != -1) ? write_data(out_fd,buf1,ret) : ret;
362         }
363     }
364
365       if (ret2 > 0) total += ret2;
366       /* if we can't write then dump excess data */
367       if (ret2 != ret)
368         vfs_transfer_file(in_fd, in_fsp, -1,NULL,n-(ret+headlen),NULL,0,0);
369
370     if (ret <= 0 || ret2 != ret)
371       return(total);
372     n -= ret;
373   }
374   return(total);
375 }
376
377 /*******************************************************************
378 a vfs_readdir wrapper which just returns the file name
379 ********************************************************************/
380 char *vfs_readdirname(connection_struct *conn, void *p)
381 {
382         struct dirent *ptr;
383         char *dname;
384
385         if (!p) return(NULL);
386   
387         ptr = (struct dirent *)conn->vfs_ops.readdir(p);
388         if (!ptr) return(NULL);
389
390         dname = ptr->d_name;
391
392 #ifdef NEXT2
393         if (telldir(p) < 0) return(NULL);
394 #endif
395
396 #ifdef HAVE_BROKEN_READDIR
397         /* using /usr/ucb/cc is BAD */
398         dname = dname - 2;
399 #endif
400
401         {
402                 static pstring buf;
403                 memcpy(buf, dname, NAMLEN(ptr)+1);
404                 unix_to_dos(buf, True);
405                 dname = buf;
406         }
407
408         unix_to_dos(dname, True);
409         return(dname);
410 }