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