first pass at updating head branch to be to be the same as the SAMBA_2_0 branch
[kai/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 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 #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 /* Default vfs hooks.  WARNING: The order of these initialisers is
37    very important.  They must be in the same order as defined in
38    vfs.h.  Change at your own peril. */
39
40 struct vfs_ops default_vfs_ops = {
41
42     /* Disk operations */        
43
44     vfswrap_dummy_connect,
45     vfswrap_dummy_disconnect,
46     vfswrap_disk_free,
47
48     /* Directory operations */
49
50     vfswrap_opendir,
51     vfswrap_readdir,
52     vfswrap_mkdir,
53     vfswrap_rmdir,
54     vfswrap_closedir,
55
56     /* File operations */
57
58     vfswrap_open,
59     vfswrap_close,
60     vfswrap_read,
61     vfswrap_write,
62     vfswrap_lseek,
63     vfswrap_rename,
64     vfswrap_sync_file,
65     vfswrap_stat,
66     vfswrap_fstat,
67     vfswrap_lstat,
68     vfswrap_fcntl_lock,
69     vfswrap_unlink,
70     vfswrap_chmod,
71     vfswrap_utime
72 };
73
74 /****************************************************************************
75   initialise default vfs hooks
76 ****************************************************************************/
77 int vfs_init_default(connection_struct *conn)
78 {
79     DEBUG(3, ("Initialising default vfs hooks\n"));
80
81     memcpy(&conn->vfs_ops, &default_vfs_ops, sizeof(conn->vfs_ops));
82     return True;
83 }
84
85 /****************************************************************************
86   initialise custom vfs hooks
87 ****************************************************************************/
88 #ifdef HAVE_LIBDL
89 BOOL vfs_init_custom(connection_struct *conn)
90 {
91     void *handle;
92     struct vfs_ops *ops, *(*fptr)(struct vfs_options *options);
93
94     DEBUG(3, ("Initialising custom vfs hooks from %s\n",
95               lp_vfsobj(SNUM(conn))));
96
97     /* Open object file */
98
99     handle = dlopen(lp_vfsobj(SNUM(conn)), RTLD_NOW);
100     if (!handle) {
101         DEBUG(0, ("Error opening %s: %s\n", lp_vfsobj(SNUM(conn)),
102                   dlerror()));
103         return False;
104     }
105
106     /* Get handle on vfs_init() symbol */
107
108     fptr = dlsym(handle, "vfs_init");
109     if (fptr == NULL) {
110         DEBUG(0, ("No vfs_init() symbol found in %s\n", 
111                   lp_vfsobj(SNUM(conn))));
112         return False;
113     }
114
115     dlclose(handle);
116
117     /* Initialise vfs_ops structure */
118
119     if ((ops = fptr(lp_vfsoptions(SNUM(conn)))) == NULL) {
120         return False;
121     }
122
123     /* Fill in unused operations with default (disk based) ones.
124        There's probably a neater way to do this then a whole bunch of
125        if statements. */ 
126
127     memcpy(&conn->vfs_ops, ops, sizeof(conn->vfs_ops));
128     
129     if (conn->vfs_ops.connect == NULL) {
130         conn->vfs_ops.connect = default_vfs_ops.connect;
131     }
132
133     if (conn->vfs_ops.disconnect == NULL) {
134         conn->vfs_ops.disconnect = default_vfs_ops.disconnect;
135     }
136
137     if (conn->vfs_ops.disk_free == NULL) {
138         conn->vfs_ops.disk_free = default_vfs_ops.disk_free;
139     }
140
141     if (conn->vfs_ops.opendir == NULL) {
142         conn->vfs_ops.opendir = default_vfs_ops.opendir;
143     }
144
145     if (conn->vfs_ops.readdir == NULL) {
146         conn->vfs_ops.readdir = default_vfs_ops.readdir;
147     }
148
149     if (conn->vfs_ops.mkdir == NULL) {
150         conn->vfs_ops.mkdir = default_vfs_ops.mkdir;
151     }
152
153     if (conn->vfs_ops.rmdir == NULL) {
154         conn->vfs_ops.rmdir = default_vfs_ops.rmdir;
155     }
156
157     if (conn->vfs_ops.closedir == NULL) {
158         conn->vfs_ops.closedir = default_vfs_ops.closedir;
159     }
160
161     if (conn->vfs_ops.open == NULL) {
162         conn->vfs_ops.open = default_vfs_ops.open;
163     }
164
165     if (conn->vfs_ops.close == NULL) {
166         conn->vfs_ops.close = default_vfs_ops.close;
167     }
168
169     if (conn->vfs_ops.read == NULL) {
170         conn->vfs_ops.read = default_vfs_ops.read;
171     }
172     
173     if (conn->vfs_ops.write == NULL) {
174         conn->vfs_ops.write = default_vfs_ops.write;
175     }
176     
177     if (conn->vfs_ops.lseek == NULL) {
178         conn->vfs_ops.lseek = default_vfs_ops.lseek;
179     }
180     
181     if (conn->vfs_ops.rename == NULL) {
182         conn->vfs_ops.rename = default_vfs_ops.rename;
183     }
184     
185     if (conn->vfs_ops.sync == NULL) {
186         conn->vfs_ops.sync = default_vfs_ops.sync;
187     }
188     
189     if (conn->vfs_ops.stat == NULL) {
190         conn->vfs_ops.stat = default_vfs_ops.stat;
191     }
192     
193     if (conn->vfs_ops.fstat == NULL) {
194         conn->vfs_ops.fstat = default_vfs_ops.fstat;
195     }
196     
197     if (conn->vfs_ops.lstat == NULL) {
198         conn->vfs_ops.lstat = default_vfs_ops.lstat;
199     }
200     
201     if (conn->vfs_ops.lock == NULL) {
202         conn->vfs_ops.lock = default_vfs_ops.lock;
203     }
204     
205     if (conn->vfs_ops.unlink == NULL) {
206         conn->vfs_ops.unlink = default_vfs_ops.unlink;
207     }
208     
209     if (conn->vfs_ops.chmod == NULL) {
210         conn->vfs_ops.chmod = default_vfs_ops.chmod;
211     }
212     
213     if (conn->vfs_ops.utime == NULL) {
214         conn->vfs_ops.utime = default_vfs_ops.utime;
215     }
216     
217     return True;
218 }
219 #endif
220
221 /*******************************************************************
222   check if a vfs file exists
223 ********************************************************************/
224 BOOL vfs_file_exist(connection_struct *conn,char *fname,SMB_STRUCT_STAT *sbuf)
225 {
226   SMB_STRUCT_STAT st;
227   if (!sbuf) sbuf = &st;
228   
229   if (conn->vfs_ops.stat(fname,sbuf) != 0) 
230     return(False);
231
232   return(S_ISREG(sbuf->st_mode));
233 }
234
235 /****************************************************************************
236   write data to a fd on the vfs
237 ****************************************************************************/
238 ssize_t vfs_write_data(files_struct *fsp,char *buffer,size_t N)
239 {
240   size_t total=0;
241   ssize_t ret;
242   int fd = fsp->fd_ptr->fd;
243
244   while (total < N)
245   {
246     ret = fsp->conn->vfs_ops.write(fd,buffer + total,N - total);
247
248     if (ret == -1) return -1;
249     if (ret == 0) return total;
250
251     total += ret;
252   }
253   return (ssize_t)total;
254 }
255
256 /****************************************************************************
257 transfer some data between two file_struct's
258 ****************************************************************************/
259 SMB_OFF_T vfs_transfer_file(int in_fd, files_struct *in_fsp, 
260                             int out_fd, files_struct *out_fsp,
261                             SMB_OFF_T n, char *header, int headlen, int align)
262 {
263   static char *buf=NULL;  
264   static int size=0;
265   char *buf1,*abuf;
266   SMB_OFF_T total = 0;
267
268   DEBUG(4,("vfs_transfer_file n=%.0f  (head=%d) called\n",(double)n,headlen));
269
270   /* Check we have at least somewhere to read from */
271
272   SMB_ASSERT((in_fd != -1) || (in_fsp != NULL));
273
274   if (size == 0) {
275     size = lp_readsize();
276     size = MAX(size,1024);
277   }
278
279   while (!buf && size>0) {
280     buf = (char *)Realloc(buf,size+8);
281     if (!buf) size /= 2;
282   }
283
284   if (!buf) {
285     DEBUG(0,("Can't allocate transfer buffer!\n"));
286     exit(1);
287   }
288
289   abuf = buf + (align%8);
290
291   if (header)
292     n += headlen;
293
294   while (n > 0)
295   {
296     int s = (int)MIN(n,(SMB_OFF_T)size);
297     int ret,ret2=0;
298
299     ret = 0;
300
301     if (header && (headlen >= MIN(s,1024))) {
302       buf1 = header;
303       s = headlen;
304       ret = headlen;
305       headlen = 0;
306       header = NULL;
307     } else {
308       buf1 = abuf;
309     }
310
311     if (header && headlen > 0)
312     {
313       ret = MIN(headlen,size);
314       memcpy(buf1,header,ret);
315       headlen -= ret;
316       header += ret;
317       if (headlen <= 0) header = NULL;
318     }
319
320     if (s > ret) {
321       ret += in_fsp ? 
322           in_fsp->conn->vfs_ops.read(in_fsp->fd_ptr->fd,buf1+ret,s-ret) : read(in_fd,buf1+ret,s-ret);
323     }
324
325     if (ret > 0)
326     {
327         if (out_fsp) {
328             ret2 = out_fsp->conn->vfs_ops.write(out_fsp->fd_ptr->fd,buf1,ret);
329         } else {
330             ret2= (out_fd != -1) ? write_data(out_fd,buf1,ret) : ret;
331         }
332     }
333
334       if (ret2 > 0) total += ret2;
335       /* if we can't write then dump excess data */
336       if (ret2 != ret)
337         vfs_transfer_file(in_fd, in_fsp, -1,NULL,n-(ret+headlen),NULL,0,0);
338
339     if (ret <= 0 || ret2 != ret)
340       return(total);
341     n -= ret;
342   }
343   return(total);
344 }
345
346 /*******************************************************************
347 a vfs_readdir wrapper which just returns the file name
348 ********************************************************************/
349 char *vfs_readdirname(connection_struct *conn, void *p)
350 {
351         struct dirent *ptr;
352         char *dname;
353
354         if (!p) return(NULL);
355   
356         ptr = (struct dirent *)conn->vfs_ops.readdir(p);
357         if (!ptr) return(NULL);
358
359         dname = ptr->d_name;
360
361 #ifdef NEXT2
362         if (telldir(p) < 0) return(NULL);
363 #endif
364
365 #ifdef HAVE_BROKEN_READDIR
366         /* using /usr/ucb/cc is BAD */
367         dname = dname - 2;
368 #endif
369
370         {
371                 static pstring buf;
372                 memcpy(buf, dname, NAMLEN(ptr)+1);
373                 unix_to_dos(buf, True);
374                 dname = buf;
375         }
376
377         unix_to_dos(dname, True);
378         return(dname);
379 }