Initial import
[samba] / source / 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    Copyright (C) Alexander Bokovoy 2002
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
22    This work was sponsored by Optifacio Software Services, Inc.
23 */
24
25 #include "includes.h"
26
27 #undef DBGC_CLASS
28 #define DBGC_CLASS DBGC_VFS
29
30 struct vfs_init_function_entry {
31         char *name;
32         vfs_op_tuple *vfs_op_tuples;
33         struct vfs_init_function_entry *prev, *next;
34 };
35
36 static struct vfs_init_function_entry *backends = NULL;
37
38 /* Some structures to help us initialise the vfs operations table */
39
40 struct vfs_syminfo {
41         char *name;
42         void *fptr;
43 };
44
45 /* Default vfs hooks.  WARNING: The order of these initialisers is
46    very important.  They must be in the same order as defined in
47    vfs.h.  Change at your own peril. */
48
49 static struct vfs_ops default_vfs = {
50
51         {
52                 /* Disk operations */
53         
54                 vfswrap_dummy_connect,
55                 vfswrap_dummy_disconnect,
56                 vfswrap_disk_free,
57                 vfswrap_get_quota,
58                 vfswrap_set_quota,
59                 vfswrap_get_shadow_copy_data,
60                 vfswrap_statvfs,
61         
62                 /* Directory operations */
63         
64                 vfswrap_opendir,
65                 vfswrap_readdir,
66                 vfswrap_seekdir,
67                 vfswrap_telldir,
68                 vfswrap_rewinddir,
69                 vfswrap_mkdir,
70                 vfswrap_rmdir,
71                 vfswrap_closedir,
72         
73                 /* File operations */
74         
75                 vfswrap_open,
76                 vfswrap_close,
77                 vfswrap_read,
78                 vfswrap_pread,
79                 vfswrap_write,
80                 vfswrap_pwrite,
81                 vfswrap_lseek,
82                 vfswrap_sendfile,
83                 vfswrap_rename,
84                 vfswrap_fsync,
85                 vfswrap_stat,
86                 vfswrap_fstat,
87                 vfswrap_lstat,
88                 vfswrap_unlink,
89                 vfswrap_chmod,
90                 vfswrap_fchmod,
91                 vfswrap_chown,
92                 vfswrap_fchown,
93                 vfswrap_chdir,
94                 vfswrap_getwd,
95                 vfswrap_utime,
96                 vfswrap_ftruncate,
97                 vfswrap_lock,
98                 vfswrap_symlink,
99                 vfswrap_readlink,
100                 vfswrap_link,
101                 vfswrap_mknod,
102                 vfswrap_realpath,
103         
104                 /* Windows ACL operations. */
105                 vfswrap_fget_nt_acl,
106                 vfswrap_get_nt_acl,
107                 vfswrap_fset_nt_acl,
108                 vfswrap_set_nt_acl,
109         
110                 /* POSIX ACL operations. */
111                 vfswrap_chmod_acl,
112                 vfswrap_fchmod_acl,
113
114                 vfswrap_sys_acl_get_entry,
115                 vfswrap_sys_acl_get_tag_type,
116                 vfswrap_sys_acl_get_permset,
117                 vfswrap_sys_acl_get_qualifier,
118                 vfswrap_sys_acl_get_file,
119                 vfswrap_sys_acl_get_fd,
120                 vfswrap_sys_acl_clear_perms,
121                 vfswrap_sys_acl_add_perm,
122                 vfswrap_sys_acl_to_text,
123                 vfswrap_sys_acl_init,
124                 vfswrap_sys_acl_create_entry,
125                 vfswrap_sys_acl_set_tag_type,
126                 vfswrap_sys_acl_set_qualifier,
127                 vfswrap_sys_acl_set_permset,
128                 vfswrap_sys_acl_valid,
129                 vfswrap_sys_acl_set_file,
130                 vfswrap_sys_acl_set_fd,
131                 vfswrap_sys_acl_delete_def_file,
132                 vfswrap_sys_acl_get_perm,
133                 vfswrap_sys_acl_free_text,
134                 vfswrap_sys_acl_free_acl,
135                 vfswrap_sys_acl_free_qualifier,
136
137                 /* EA operations. */
138                 vfswrap_getxattr,
139                 vfswrap_lgetxattr,
140                 vfswrap_fgetxattr,
141                 vfswrap_listxattr,
142                 vfswrap_llistxattr,
143                 vfswrap_flistxattr,
144                 vfswrap_removexattr,
145                 vfswrap_lremovexattr,
146                 vfswrap_fremovexattr,
147                 vfswrap_setxattr,
148                 vfswrap_lsetxattr,
149                 vfswrap_fsetxattr,
150
151                 /* AIO operations. */
152                 vfswrap_aio_read,
153                 vfswrap_aio_write,
154                 vfswrap_aio_return,
155                 vfswrap_aio_cancel,
156                 vfswrap_aio_error,
157                 vfswrap_aio_fsync,
158                 vfswrap_aio_suspend
159         }
160 };
161
162 /****************************************************************************
163     maintain the list of available backends
164 ****************************************************************************/
165
166 static struct vfs_init_function_entry *vfs_find_backend_entry(const char *name)
167 {
168         struct vfs_init_function_entry *entry = backends;
169  
170         while(entry) {
171                 if (strcmp(entry->name, name)==0) return entry;
172                 entry = entry->next;
173         }
174
175         return NULL;
176 }
177
178 NTSTATUS smb_register_vfs(int version, const char *name, vfs_op_tuple *vfs_op_tuples)
179 {
180         struct vfs_init_function_entry *entry = backends;
181
182         if ((version != SMB_VFS_INTERFACE_VERSION)) {
183                 DEBUG(0, ("Failed to register vfs module.\n"
184                           "The module was compiled against SMB_VFS_INTERFACE_VERSION %d,\n"
185                           "current SMB_VFS_INTERFACE_VERSION is %d.\n"
186                           "Please recompile against the current Samba Version!\n",  
187                           version, SMB_VFS_INTERFACE_VERSION));
188                 return NT_STATUS_OBJECT_TYPE_MISMATCH;
189         }
190
191         if (!name || !name[0] || !vfs_op_tuples) {
192                 DEBUG(0,("smb_register_vfs() called with NULL pointer or empty name!\n"));
193                 return NT_STATUS_INVALID_PARAMETER;
194         }
195
196         if (vfs_find_backend_entry(name)) {
197                 DEBUG(0,("VFS module %s already loaded!\n", name));
198                 return NT_STATUS_OBJECT_NAME_COLLISION;
199         }
200
201         entry = SMB_XMALLOC_P(struct vfs_init_function_entry);
202         entry->name = smb_xstrdup(name);
203         entry->vfs_op_tuples = vfs_op_tuples;
204
205         DLIST_ADD(backends, entry);
206         DEBUG(5, ("Successfully added vfs backend '%s'\n", name));
207         return NT_STATUS_OK;
208 }
209
210 /****************************************************************************
211   initialise default vfs hooks
212 ****************************************************************************/
213
214 static void vfs_init_default(connection_struct *conn)
215 {
216         DEBUG(3, ("Initialising default vfs hooks\n"));
217
218         memcpy(&conn->vfs.ops, &default_vfs.ops, sizeof(default_vfs.ops));
219         memcpy(&conn->vfs_opaque.ops, &default_vfs.ops, sizeof(default_vfs.ops));
220 }
221
222 /****************************************************************************
223   initialise custom vfs hooks
224  ****************************************************************************/
225
226 BOOL vfs_init_custom(connection_struct *conn, const char *vfs_object)
227 {
228         vfs_op_tuple *ops;
229         char *module_name = NULL;
230         char *module_param = NULL, *p;
231         int i;
232         vfs_handle_struct *handle;
233         struct vfs_init_function_entry *entry;
234         
235         if (!conn||!vfs_object||!vfs_object[0]) {
236                 DEBUG(0,("vfs_init_custon() called with NULL pointer or emtpy vfs_object!\n"));
237                 return False;
238         }
239
240         if(!backends) {
241                 static_init_vfs;
242         }
243
244         DEBUG(3, ("Initialising custom vfs hooks from [%s]\n", vfs_object));
245
246         module_name = smb_xstrdup(vfs_object);
247
248         p = strchr_m(module_name, ':');
249
250         if (p) {
251                 *p = 0;
252                 module_param = p+1;
253                 trim_char(module_param, ' ', ' ');
254         }
255
256         trim_char(module_name, ' ', ' ');
257
258         /* First, try to load the module with the new module system */
259         if((entry = vfs_find_backend_entry(module_name)) || 
260            (NT_STATUS_IS_OK(smb_probe_module("vfs", module_name)) && 
261                 (entry = vfs_find_backend_entry(module_name)))) {
262
263                 DEBUGADD(5,("Successfully loaded vfs module [%s] with the new modules system\n", vfs_object));
264                 
265                 if ((ops = entry->vfs_op_tuples) == NULL) {
266                         DEBUG(0, ("entry->vfs_op_tuples==NULL for [%s] failed\n", vfs_object));
267                         SAFE_FREE(module_name);
268                         return False;
269                 }
270         } else {
271                 DEBUG(0,("Can't find a vfs module [%s]\n",vfs_object));
272                 SAFE_FREE(module_name);
273                 return False;
274         }
275
276         handle = TALLOC_ZERO_P(conn->mem_ctx,vfs_handle_struct);
277         if (!handle) {
278                 DEBUG(0,("talloc_zero() failed!\n"));
279                 SAFE_FREE(module_name);
280                 return False;
281         }
282         memcpy(&handle->vfs_next, &conn->vfs, sizeof(struct vfs_ops));
283         handle->conn = conn;
284         if (module_param) {
285                 handle->param = talloc_strdup(conn->mem_ctx, module_param);
286         }
287         DLIST_ADD(conn->vfs_handles, handle);
288
289         for(i=0; ops[i].op != NULL; i++) {
290                 DEBUG(5, ("Checking operation #%d (type %d, layer %d)\n", i, ops[i].type, ops[i].layer));
291                 if(ops[i].layer == SMB_VFS_LAYER_OPAQUE) {
292                         /* Check whether this operation was already made opaque by different module */
293                         if(((void**)&conn->vfs_opaque.ops)[ops[i].type] == ((void**)&default_vfs.ops)[ops[i].type]) {
294                                 /* No, it isn't overloaded yet. Overload. */
295                                 DEBUGADD(5, ("Making operation type %d opaque [module %s]\n", ops[i].type, vfs_object));
296                                 ((void**)&conn->vfs_opaque.ops)[ops[i].type] = ops[i].op;
297                                 ((vfs_handle_struct **)&conn->vfs_opaque.handles)[ops[i].type] = handle;
298                         }
299                 }
300                 /* Change current VFS disposition*/
301                 DEBUGADD(5, ("Accepting operation type %d from module %s\n", ops[i].type, vfs_object));
302                 ((void**)&conn->vfs.ops)[ops[i].type] = ops[i].op;
303                 ((vfs_handle_struct **)&conn->vfs.handles)[ops[i].type] = handle;
304         }
305
306         SAFE_FREE(module_name);
307         return True;
308 }
309
310 /*****************************************************************
311  Generic VFS init.
312 ******************************************************************/
313
314 BOOL smbd_vfs_init(connection_struct *conn)
315 {
316         const char **vfs_objects;
317         unsigned int i = 0;
318         int j = 0;
319         
320         /* Normal share - initialise with disk access functions */
321         vfs_init_default(conn);
322         vfs_objects = lp_vfs_objects(SNUM(conn));
323
324         /* Override VFS functions if 'vfs object' was not specified*/
325         if (!vfs_objects || !vfs_objects[0])
326                 return True;
327         
328         for (i=0; vfs_objects[i] ;) {
329                 i++;
330         }
331
332         for (j=i-1; j >= 0; j--) {
333                 if (!vfs_init_custom(conn, vfs_objects[j])) {
334                         DEBUG(0, ("smbd_vfs_init: vfs_init_custom failed for %s\n", vfs_objects[j]));
335                         return False;
336                 }
337         }
338         return True;
339 }
340
341 /*******************************************************************
342  Check if directory exists.
343 ********************************************************************/
344
345 BOOL vfs_directory_exist(connection_struct *conn, const char *dname, SMB_STRUCT_STAT *st)
346 {
347         SMB_STRUCT_STAT st2;
348         BOOL ret;
349
350         if (!st)
351                 st = &st2;
352
353         if (SMB_VFS_STAT(conn,dname,st) != 0)
354                 return(False);
355
356         ret = S_ISDIR(st->st_mode);
357         if(!ret)
358                 errno = ENOTDIR;
359
360         return ret;
361 }
362
363 /*******************************************************************
364  vfs mkdir wrapper 
365 ********************************************************************/
366
367 int vfs_MkDir(connection_struct *conn, const char *name, mode_t mode)
368 {
369         int ret;
370         SMB_STRUCT_STAT sbuf;
371
372         if(!(ret=SMB_VFS_MKDIR(conn, name, mode))) {
373
374                 inherit_access_acl(conn, name, mode);
375
376                 /*
377                  * Check if high bits should have been set,
378                  * then (if bits are missing): add them.
379                  * Consider bits automagically set by UNIX, i.e. SGID bit from parent dir.
380                  */
381                 if(mode & ~(S_IRWXU|S_IRWXG|S_IRWXO) &&
382                                 !SMB_VFS_STAT(conn,name,&sbuf) && (mode & ~sbuf.st_mode))
383                         SMB_VFS_CHMOD(conn,name,sbuf.st_mode | (mode & ~sbuf.st_mode));
384         }
385         return ret;
386 }
387
388 /*******************************************************************
389  Check if an object exists in the vfs.
390 ********************************************************************/
391
392 BOOL vfs_object_exist(connection_struct *conn,const char *fname,SMB_STRUCT_STAT *sbuf)
393 {
394         SMB_STRUCT_STAT st;
395
396         if (!sbuf)
397                 sbuf = &st;
398
399         ZERO_STRUCTP(sbuf);
400
401         if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
402                 return(False);
403         return True;
404 }
405
406 /*******************************************************************
407  Check if a file exists in the vfs.
408 ********************************************************************/
409
410 BOOL vfs_file_exist(connection_struct *conn, const char *fname,SMB_STRUCT_STAT *sbuf)
411 {
412         SMB_STRUCT_STAT st;
413
414         if (!sbuf)
415                 sbuf = &st;
416
417         ZERO_STRUCTP(sbuf);
418
419         if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
420                 return False;
421         return(S_ISREG(sbuf->st_mode));
422 }
423
424 /****************************************************************************
425  Read data from fsp on the vfs. (note: EINTR re-read differs from vfs_write_data)
426 ****************************************************************************/
427
428 ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count)
429 {
430         size_t total=0;
431
432         while (total < byte_count)
433         {
434                 ssize_t ret = SMB_VFS_READ(fsp, fsp->fh->fd, buf + total,
435                                         byte_count - total);
436
437                 if (ret == 0) return total;
438                 if (ret == -1) {
439                         if (errno == EINTR)
440                                 continue;
441                         else
442                                 return -1;
443                 }
444                 total += ret;
445         }
446         return (ssize_t)total;
447 }
448
449 ssize_t vfs_pread_data(files_struct *fsp, char *buf,
450                 size_t byte_count, SMB_OFF_T offset)
451 {
452         size_t total=0;
453
454         while (total < byte_count)
455         {
456                 ssize_t ret = SMB_VFS_PREAD(fsp, fsp->fh->fd, buf + total,
457                                         byte_count - total, offset + total);
458
459                 if (ret == 0) return total;
460                 if (ret == -1) {
461                         if (errno == EINTR)
462                                 continue;
463                         else
464                                 return -1;
465                 }
466                 total += ret;
467         }
468         return (ssize_t)total;
469 }
470
471 /****************************************************************************
472  Write data to a fd on the vfs.
473 ****************************************************************************/
474
475 ssize_t vfs_write_data(files_struct *fsp,const char *buffer,size_t N)
476 {
477         size_t total=0;
478         ssize_t ret;
479
480         while (total < N) {
481                 ret = SMB_VFS_WRITE(fsp,fsp->fh->fd,buffer + total,N - total);
482
483                 if (ret == -1)
484                         return -1;
485                 if (ret == 0)
486                         return total;
487
488                 total += ret;
489         }
490         return (ssize_t)total;
491 }
492
493 ssize_t vfs_pwrite_data(files_struct *fsp,const char *buffer,
494                 size_t N, SMB_OFF_T offset)
495 {
496         size_t total=0;
497         ssize_t ret;
498
499         while (total < N) {
500                 ret = SMB_VFS_PWRITE(fsp, fsp->fh->fd, buffer + total,
501                                 N - total, offset + total);
502
503                 if (ret == -1)
504                         return -1;
505                 if (ret == 0)
506                         return total;
507
508                 total += ret;
509         }
510         return (ssize_t)total;
511 }
512 /****************************************************************************
513  An allocate file space call using the vfs interface.
514  Allocates space for a file from a filedescriptor.
515  Returns 0 on success, -1 on failure.
516 ****************************************************************************/
517
518 int vfs_allocate_file_space(files_struct *fsp, SMB_BIG_UINT len)
519 {
520         int ret;
521         SMB_STRUCT_STAT st;
522         connection_struct *conn = fsp->conn;
523         SMB_BIG_UINT space_avail;
524         SMB_BIG_UINT bsize,dfree,dsize;
525
526         release_level_2_oplocks_on_change(fsp);
527
528         /*
529          * Actually try and commit the space on disk....
530          */
531
532         DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", fsp->fsp_name, (double)len ));
533
534         if (((SMB_OFF_T)len) < 0) {
535                 DEBUG(0,("vfs_allocate_file_space: %s negative len requested.\n", fsp->fsp_name ));
536                 return -1;
537         }
538
539         ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st);
540         if (ret == -1)
541                 return ret;
542
543         if (len == (SMB_BIG_UINT)st.st_size)
544                 return 0;
545
546         if (len < (SMB_BIG_UINT)st.st_size) {
547                 /* Shrink - use ftruncate. */
548
549                 DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
550                                 fsp->fsp_name, (double)st.st_size ));
551
552                 flush_write_cache(fsp, SIZECHANGE_FLUSH);
553                 if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, (SMB_OFF_T)len)) != -1) {
554                         set_filelen_write_cache(fsp, len);
555                 }
556                 return ret;
557         }
558
559         /* Grow - we need to test if we have enough space. */
560
561         if (!lp_strict_allocate(SNUM(fsp->conn)))
562                 return 0;
563
564         len -= st.st_size;
565         len /= 1024; /* Len is now number of 1k blocks needed. */
566         space_avail = get_dfree_info(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize);
567         if (space_avail == (SMB_BIG_UINT)-1) {
568                 return -1;
569         }
570
571         DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %.0f, space avail = %.0f\n",
572                         fsp->fsp_name, (double)st.st_size, (double)len, (double)space_avail ));
573
574         if (len > space_avail) {
575                 errno = ENOSPC;
576                 return -1;
577         }
578
579         return 0;
580 }
581
582 /****************************************************************************
583  A vfs set_filelen call.
584  set the length of a file from a filedescriptor.
585  Returns 0 on success, -1 on failure.
586 ****************************************************************************/
587
588 int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
589 {
590         int ret;
591
592         release_level_2_oplocks_on_change(fsp);
593         DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len));
594         flush_write_cache(fsp, SIZECHANGE_FLUSH);
595         if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, len)) != -1)
596                 set_filelen_write_cache(fsp, len);
597
598         return ret;
599 }
600
601 /****************************************************************************
602  A vfs fill sparse call.
603  Writes zeros from the end of file to len, if len is greater than EOF.
604  Used only by strict_sync.
605  Returns 0 on success, -1 on failure.
606 ****************************************************************************/
607
608 static char *sparse_buf;
609 #define SPARSE_BUF_WRITE_SIZE (32*1024)
610
611 int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len)
612 {
613         int ret;
614         SMB_STRUCT_STAT st;
615         SMB_OFF_T offset;
616         size_t total;
617         size_t num_to_write;
618         ssize_t pwrite_ret;
619
620         release_level_2_oplocks_on_change(fsp);
621         ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st);
622         if (ret == -1) {
623                 return ret;
624         }
625
626         if (len <= st.st_size) {
627                 return 0;
628         }
629
630         DEBUG(10,("vfs_fill_sparse: write zeros in file %s from len %.0f to len %.0f (%.0f bytes)\n",
631                 fsp->fsp_name, (double)st.st_size, (double)len, (double)(len - st.st_size)));
632
633         flush_write_cache(fsp, SIZECHANGE_FLUSH);
634
635         if (!sparse_buf) {
636                 sparse_buf = SMB_CALLOC_ARRAY(char, SPARSE_BUF_WRITE_SIZE);
637                 if (!sparse_buf) {
638                         errno = ENOMEM;
639                         return -1;
640                 }
641         }
642
643         offset = st.st_size;
644         num_to_write = len - st.st_size;
645         total = 0;
646
647         while (total < num_to_write) {
648                 size_t curr_write_size = MIN(SPARSE_BUF_WRITE_SIZE, (num_to_write - total));
649
650                 pwrite_ret = SMB_VFS_PWRITE(fsp, fsp->fh->fd, sparse_buf, curr_write_size, offset + total);
651                 if (pwrite_ret == -1) {
652                         DEBUG(10,("vfs_fill_sparse: SMB_VFS_PWRITE for file %s failed with error %s\n",
653                                 fsp->fsp_name, strerror(errno) ));
654                         return -1;
655                 }
656                 if (pwrite_ret == 0) {
657                         return 0;
658                 }
659
660                 total += pwrite_ret;
661         }
662
663         set_filelen_write_cache(fsp, len);
664         return 0;
665 }
666
667 /****************************************************************************
668  Transfer some data (n bytes) between two file_struct's.
669 ****************************************************************************/
670
671 static files_struct *in_fsp;
672 static files_struct *out_fsp;
673
674 static ssize_t read_fn(int fd, void *buf, size_t len)
675 {
676         return SMB_VFS_READ(in_fsp, fd, buf, len);
677 }
678
679 static ssize_t write_fn(int fd, const void *buf, size_t len)
680 {
681         return SMB_VFS_WRITE(out_fsp, fd, buf, len);
682 }
683
684 SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n)
685 {
686         in_fsp = in;
687         out_fsp = out;
688
689         return transfer_file_internal(in_fsp->fh->fd, out_fsp->fh->fd, n, read_fn, write_fn);
690 }
691
692 /*******************************************************************
693  A vfs_readdir wrapper which just returns the file name.
694 ********************************************************************/
695
696 char *vfs_readdirname(connection_struct *conn, void *p)
697 {
698         SMB_STRUCT_DIRENT *ptr= NULL;
699         char *dname;
700
701         if (!p)
702                 return(NULL);
703
704         ptr = SMB_VFS_READDIR(conn,p);
705         if (!ptr)
706                 return(NULL);
707
708         dname = ptr->d_name;
709
710 #ifdef NEXT2
711         if (telldir(p) < 0)
712                 return(NULL);
713 #endif
714
715 #ifdef HAVE_BROKEN_READDIR
716         /* using /usr/ucb/cc is BAD */
717         dname = dname - 2;
718 #endif
719
720         return(dname);
721 }
722
723 /*******************************************************************
724  A wrapper for vfs_chdir().
725 ********************************************************************/
726
727 int vfs_ChDir(connection_struct *conn, const char *path)
728 {
729         int res;
730         static pstring LastDir="";
731
732         if (strcsequal(path,"."))
733                 return(0);
734
735         if (*path == '/' && strcsequal(LastDir,path))
736                 return(0);
737
738         DEBUG(4,("vfs_ChDir to %s\n",path));
739
740         res = SMB_VFS_CHDIR(conn,path);
741         if (!res)
742                 pstrcpy(LastDir,path);
743         return(res);
744 }
745
746 /* number of list structures for a caching GetWd function. */
747 #define MAX_GETWDCACHE (50)
748
749 static struct {
750         SMB_DEV_T dev; /* These *must* be compatible with the types returned in a stat() call. */
751         SMB_INO_T inode; /* These *must* be compatible with the types returned in a stat() call. */
752         char *dos_path; /* The pathname in DOS format. */
753         BOOL valid;
754 } ino_list[MAX_GETWDCACHE];
755
756 extern BOOL use_getwd_cache;
757
758 /****************************************************************************
759  Prompte a ptr (to make it recently used)
760 ****************************************************************************/
761
762 static void array_promote(char *array,int elsize,int element)
763 {
764         char *p;
765         if (element == 0)
766                 return;
767
768         p = (char *)SMB_MALLOC(elsize);
769
770         if (!p) {
771                 DEBUG(5,("array_promote: malloc fail\n"));
772                 return;
773         }
774
775         memcpy(p,array + element * elsize, elsize);
776         memmove(array + elsize,array,elsize*element);
777         memcpy(array,p,elsize);
778         SAFE_FREE(p);
779 }
780
781 /*******************************************************************
782  Return the absolute current directory path - given a UNIX pathname.
783  Note that this path is returned in DOS format, not UNIX
784  format. Note this can be called with conn == NULL.
785 ********************************************************************/
786
787 char *vfs_GetWd(connection_struct *conn, char *path)
788 {
789         pstring s;
790         static BOOL getwd_cache_init = False;
791         SMB_STRUCT_STAT st, st2;
792         int i;
793
794         *s = 0;
795
796         if (!use_getwd_cache)
797                 return(SMB_VFS_GETWD(conn,path));
798
799         /* init the cache */
800         if (!getwd_cache_init) {
801                 getwd_cache_init = True;
802                 for (i=0;i<MAX_GETWDCACHE;i++) {
803                         string_set(&ino_list[i].dos_path,"");
804                         ino_list[i].valid = False;
805                 }
806         }
807
808         /*  Get the inode of the current directory, if this doesn't work we're
809                 in trouble :-) */
810
811         if (SMB_VFS_STAT(conn, ".",&st) == -1) {
812                 /* Known to fail for root: the directory may be
813                  * NFS-mounted and exported with root_squash (so has no root access). */
814                 DEBUG(1,("vfs_GetWd: couldn't stat \".\" path=%s error %s (NFS problem ?)\n", path, strerror(errno) ));
815                 return(SMB_VFS_GETWD(conn,path));
816         }
817
818
819         for (i=0; i<MAX_GETWDCACHE; i++) {
820                 if (ino_list[i].valid) {
821
822                         /*  If we have found an entry with a matching inode and dev number
823                                 then find the inode number for the directory in the cached string.
824                                 If this agrees with that returned by the stat for the current
825                                 directory then all is o.k. (but make sure it is a directory all
826                                 the same...) */
827
828                         if (st.st_ino == ino_list[i].inode && st.st_dev == ino_list[i].dev) {
829                                 if (SMB_VFS_STAT(conn,ino_list[i].dos_path,&st2) == 0) {
830                                         if (st.st_ino == st2.st_ino && st.st_dev == st2.st_dev &&
831                                                         (st2.st_mode & S_IFMT) == S_IFDIR) {
832                                                 pstrcpy (path, ino_list[i].dos_path);
833
834                                                 /* promote it for future use */
835                                                 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
836                                                 return (path);
837                                         } else {
838                                                 /*  If the inode is different then something's changed,
839                                                         scrub the entry and start from scratch. */
840                                                 ino_list[i].valid = False;
841                                         }
842                                 }
843                         }
844                 }
845         }
846
847         /*  We don't have the information to hand so rely on traditional methods.
848                 The very slow getcwd, which spawns a process on some systems, or the
849                 not quite so bad getwd. */
850
851         if (!SMB_VFS_GETWD(conn,s)) {
852                 DEBUG(0,("vfs_GetWd: SMB_VFS_GETWD call failed, errno %s\n",strerror(errno)));
853                 return (NULL);
854         }
855
856         pstrcpy(path,s);
857
858         DEBUG(5,("vfs_GetWd %s, inode %.0f, dev %.0f\n",s,(double)st.st_ino,(double)st.st_dev));
859
860         /* add it to the cache */
861         i = MAX_GETWDCACHE - 1;
862         string_set(&ino_list[i].dos_path,s);
863         ino_list[i].dev = st.st_dev;
864         ino_list[i].inode = st.st_ino;
865         ino_list[i].valid = True;
866
867         /* put it at the top of the list */
868         array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
869
870         return (path);
871 }
872
873 BOOL canonicalize_path(connection_struct *conn, pstring path)
874 {
875 #ifdef REALPATH_TAKES_NULL
876         char *resolved_name = SMB_VFS_REALPATH(conn,path,NULL);
877         if (!resolved_name) {
878                 return False;
879         }
880         pstrcpy(path, resolved_name);
881         SAFE_FREE(resolved_name);
882         return True;
883 #else
884 #ifdef PATH_MAX
885         char resolved_name_buf[PATH_MAX+1];
886 #else
887         pstring resolved_name_buf;
888 #endif
889         char *resolved_name = SMB_VFS_REALPATH(conn,path,resolved_name_buf);
890         if (!resolved_name) {
891                 return False;
892         }
893         pstrcpy(path, resolved_name);
894         return True;
895 #endif /* REALPATH_TAKES_NULL */
896 }
897
898 /*******************************************************************
899  Reduce a file name, removing .. elements and checking that
900  it is below dir in the heirachy. This uses realpath.
901 ********************************************************************/
902
903 BOOL reduce_name(connection_struct *conn, const pstring fname)
904 {
905 #ifdef REALPATH_TAKES_NULL
906         BOOL free_resolved_name = True;
907 #else
908 #ifdef PATH_MAX
909         char resolved_name_buf[PATH_MAX+1];
910 #else
911         pstring resolved_name_buf;
912 #endif
913         BOOL free_resolved_name = False;
914 #endif
915         char *resolved_name = NULL;
916         size_t con_path_len = strlen(conn->connectpath);
917         char *p = NULL;
918         int saved_errno = errno;
919
920         DEBUG(3,("reduce_name [%s] [%s]\n", fname, conn->connectpath));
921
922 #ifdef REALPATH_TAKES_NULL
923         resolved_name = SMB_VFS_REALPATH(conn,fname,NULL);
924 #else
925         resolved_name = SMB_VFS_REALPATH(conn,fname,resolved_name_buf);
926 #endif
927
928         if (!resolved_name) {
929                 switch (errno) {
930                         case ENOTDIR:
931                                 DEBUG(3,("reduce_name: Component not a directory in getting realpath for %s\n", fname));
932                                 errno = saved_errno;
933                                 return False;
934                         case ENOENT:
935                         {
936                                 pstring tmp_fname;
937                                 fstring last_component;
938                                 /* Last component didn't exist. Remove it and try and canonicalise the directory. */
939
940                                 pstrcpy(tmp_fname, fname);
941                                 p = strrchr_m(tmp_fname, '/');
942                                 if (p) {
943                                         *p++ = '\0';
944                                         fstrcpy(last_component, p);
945                                 } else {
946                                         fstrcpy(last_component, tmp_fname);
947                                         pstrcpy(tmp_fname, ".");
948                                 }
949
950 #ifdef REALPATH_TAKES_NULL
951                                 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,NULL);
952 #else
953                                 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,resolved_name_buf);
954 #endif
955                                 if (!resolved_name) {
956                                         DEBUG(3,("reduce_name: couldn't get realpath for %s\n", fname));
957                                         errno = saved_errno;
958                                         return False;
959                                 }
960                                 pstrcpy(tmp_fname, resolved_name);
961                                 pstrcat(tmp_fname, "/");
962                                 pstrcat(tmp_fname, last_component);
963 #ifdef REALPATH_TAKES_NULL
964                                 SAFE_FREE(resolved_name);
965                                 resolved_name = SMB_STRDUP(tmp_fname);
966                                 if (!resolved_name) {
967                                         DEBUG(0,("reduce_name: malloc fail for %s\n", tmp_fname));
968                                         errno = saved_errno;
969                                         return False;
970                                 }
971 #else
972 #ifdef PATH_MAX
973                                 safe_strcpy(resolved_name_buf, tmp_fname, PATH_MAX);
974 #else
975                                 pstrcpy(resolved_name_buf, tmp_fname);
976 #endif
977                                 resolved_name = resolved_name_buf;
978 #endif
979                                 break;
980                         }
981                         default:
982                                 DEBUG(1,("reduce_name: couldn't get realpath for %s\n", fname));
983                                 /* Don't restore the saved errno. We need to return the error that
984                                    realpath caused here as it was not one of the cases we handle. JRA. */
985                                 return False;
986                 }
987         }
988
989         DEBUG(10,("reduce_name realpath [%s] -> [%s]\n", fname, resolved_name));
990
991         if (*resolved_name != '/') {
992                 DEBUG(0,("reduce_name: realpath doesn't return absolute paths !\n"));
993                 if (free_resolved_name)
994                         SAFE_FREE(resolved_name);
995                 errno = saved_errno;
996                 return False;
997         }
998
999         /* Check for widelinks allowed. */
1000         if (!lp_widelinks(SNUM(conn)) && (strncmp(conn->connectpath, resolved_name, con_path_len) != 0)) {
1001                 DEBUG(2, ("reduce_name: Bad access attempt: %s is a symlink outside the share path", fname));
1002                 if (free_resolved_name)
1003                         SAFE_FREE(resolved_name);
1004                 errno = EACCES;
1005                 return False;
1006         }
1007
1008         /* Check if we are allowing users to follow symlinks */
1009         /* Patch from David Clerc <David.Clerc@cui.unige.ch>
1010                 University of Geneva */
1011                                                                                                                                                     
1012 #ifdef S_ISLNK
1013         if (!lp_symlinks(SNUM(conn))) {
1014                 SMB_STRUCT_STAT statbuf;
1015                 if ( (SMB_VFS_LSTAT(conn,fname,&statbuf) != -1) &&
1016                                 (S_ISLNK(statbuf.st_mode)) ) {
1017                         if (free_resolved_name)
1018                                 SAFE_FREE(resolved_name);
1019                         DEBUG(3,("reduce_name: denied: file path name %s is a symlink\n",resolved_name));
1020                         errno = EACCES;
1021                         return False;
1022                 }
1023         }
1024 #endif
1025
1026         DEBUG(3,("reduce_name: %s reduced to %s\n", fname, resolved_name));
1027         if (free_resolved_name)
1028                 SAFE_FREE(resolved_name);
1029         errno = saved_errno;
1030         return(True);
1031 }