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