r6633: Added "check_path_syntax_posix()" in preparation for handling
[nivanova/samba-autobuild/.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_P(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) {
231                 static_init_vfs;
232         }
233
234         DEBUG(3, ("Initialising custom vfs hooks from [%s]\n", vfs_object));
235
236         module_name = smb_xstrdup(vfs_object);
237
238         p = strchr_m(module_name, ':');
239
240         if (p) {
241                 *p = 0;
242                 module_param = p+1;
243                 trim_char(module_param, ' ', ' ');
244         }
245
246         trim_char(module_name, ' ', ' ');
247
248         /* First, try to load the module with the new module system */
249         if((entry = vfs_find_backend_entry(module_name)) || 
250            (NT_STATUS_IS_OK(smb_probe_module("vfs", module_name)) && 
251                 (entry = vfs_find_backend_entry(module_name)))) {
252
253                 DEBUGADD(5,("Successfully loaded vfs module [%s] with the new modules system\n", vfs_object));
254                 
255                 if ((ops = entry->vfs_op_tuples) == NULL) {
256                         DEBUG(0, ("entry->vfs_op_tuples==NULL for [%s] failed\n", vfs_object));
257                         SAFE_FREE(module_name);
258                         return False;
259                 }
260         } else {
261                 DEBUG(0,("Can't find a vfs module [%s]\n",vfs_object));
262                 SAFE_FREE(module_name);
263                 return False;
264         }
265
266         handle = TALLOC_ZERO_P(conn->mem_ctx,vfs_handle_struct);
267         if (!handle) {
268                 DEBUG(0,("talloc_zero() failed!\n"));
269                 SAFE_FREE(module_name);
270                 return False;
271         }
272         memcpy(&handle->vfs_next, &conn->vfs, sizeof(struct vfs_ops));
273         handle->conn = conn;
274         if (module_param) {
275                 handle->param = talloc_strdup(conn->mem_ctx, module_param);
276         }
277         DLIST_ADD(conn->vfs_handles, handle);
278
279         for(i=0; ops[i].op != NULL; i++) {
280           DEBUG(5, ("Checking operation #%d (type %d, layer %d)\n", i, ops[i].type, ops[i].layer));
281           if(ops[i].layer == SMB_VFS_LAYER_OPAQUE) {
282             /* Check whether this operation was already made opaque by different module */
283             if(((void**)&conn->vfs_opaque.ops)[ops[i].type] == ((void**)&default_vfs.ops)[ops[i].type]) {
284               /* No, it isn't overloaded yet. Overload. */
285               DEBUGADD(5, ("Making operation type %d opaque [module %s]\n", ops[i].type, vfs_object));
286               ((void**)&conn->vfs_opaque.ops)[ops[i].type] = ops[i].op;
287               ((vfs_handle_struct **)&conn->vfs_opaque.handles)[ops[i].type] = handle;
288             }
289           }
290           /* Change current VFS disposition*/
291           DEBUGADD(5, ("Accepting operation type %d from module %s\n", ops[i].type, vfs_object));
292           ((void**)&conn->vfs.ops)[ops[i].type] = ops[i].op;
293           ((vfs_handle_struct **)&conn->vfs.handles)[ops[i].type] = handle;
294         }
295
296         SAFE_FREE(module_name);
297         return True;
298 }
299
300 /*****************************************************************
301  Generic VFS init.
302 ******************************************************************/
303
304 BOOL smbd_vfs_init(connection_struct *conn)
305 {
306         const char **vfs_objects;
307         unsigned int i = 0;
308         int j = 0;
309         
310         /* Normal share - initialise with disk access functions */
311         vfs_init_default(conn);
312         vfs_objects = lp_vfs_objects(SNUM(conn));
313
314         /* Override VFS functions if 'vfs object' was not specified*/
315         if (!vfs_objects || !vfs_objects[0])
316                 return True;
317         
318         for (i=0; vfs_objects[i] ;) {
319                 i++;
320         }
321
322         for (j=i-1; j >= 0; j--) {
323                 if (!vfs_init_custom(conn, vfs_objects[j])) {
324                         DEBUG(0, ("smbd_vfs_init: vfs_init_custom failed for %s\n", vfs_objects[j]));
325                         return False;
326                 }
327         }
328         return True;
329 }
330
331 /*******************************************************************
332  Check if directory exists.
333 ********************************************************************/
334
335 BOOL vfs_directory_exist(connection_struct *conn, const char *dname, SMB_STRUCT_STAT *st)
336 {
337         SMB_STRUCT_STAT st2;
338         BOOL ret;
339
340         if (!st)
341                 st = &st2;
342
343         if (SMB_VFS_STAT(conn,dname,st) != 0)
344                 return(False);
345
346         ret = S_ISDIR(st->st_mode);
347         if(!ret)
348                 errno = ENOTDIR;
349
350         return ret;
351 }
352
353 /*******************************************************************
354  vfs mkdir wrapper 
355 ********************************************************************/
356
357 int vfs_MkDir(connection_struct *conn, const char *name, mode_t mode)
358 {
359         int ret;
360         SMB_STRUCT_STAT sbuf;
361
362         if(!(ret=SMB_VFS_MKDIR(conn, name, mode))) {
363
364                 inherit_access_acl(conn, name, mode);
365
366                 /*
367                  * Check if high bits should have been set,
368                  * then (if bits are missing): add them.
369                  * Consider bits automagically set by UNIX, i.e. SGID bit from parent dir.
370                  */
371                 if(mode & ~(S_IRWXU|S_IRWXG|S_IRWXO) &&
372                                 !SMB_VFS_STAT(conn,name,&sbuf) && (mode & ~sbuf.st_mode))
373                         SMB_VFS_CHMOD(conn,name,sbuf.st_mode | (mode & ~sbuf.st_mode));
374         }
375         return ret;
376 }
377
378 /*******************************************************************
379  Check if an object exists in the vfs.
380 ********************************************************************/
381
382 BOOL vfs_object_exist(connection_struct *conn,const char *fname,SMB_STRUCT_STAT *sbuf)
383 {
384         SMB_STRUCT_STAT st;
385
386         if (!sbuf)
387                 sbuf = &st;
388
389         ZERO_STRUCTP(sbuf);
390
391         if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
392                 return(False);
393         return True;
394 }
395
396 /*******************************************************************
397  Check if a file exists in the vfs.
398 ********************************************************************/
399
400 BOOL vfs_file_exist(connection_struct *conn, const char *fname,SMB_STRUCT_STAT *sbuf)
401 {
402         SMB_STRUCT_STAT st;
403
404         if (!sbuf)
405                 sbuf = &st;
406
407         ZERO_STRUCTP(sbuf);
408
409         if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
410                 return False;
411         return(S_ISREG(sbuf->st_mode));
412 }
413
414 /****************************************************************************
415  Read data from fsp on the vfs. (note: EINTR re-read differs from vfs_write_data)
416 ****************************************************************************/
417
418 ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count)
419 {
420         size_t total=0;
421
422         while (total < byte_count)
423         {
424                 ssize_t ret = SMB_VFS_READ(fsp, fsp->fd, buf + total,
425                                         byte_count - total);
426
427                 if (ret == 0) return total;
428                 if (ret == -1) {
429                         if (errno == EINTR)
430                                 continue;
431                         else
432                                 return -1;
433                 }
434                 total += ret;
435         }
436         return (ssize_t)total;
437 }
438
439 ssize_t vfs_pread_data(files_struct *fsp, char *buf,
440                 size_t byte_count, SMB_OFF_T offset)
441 {
442         size_t total=0;
443
444         while (total < byte_count)
445         {
446                 ssize_t ret = SMB_VFS_PREAD(fsp, fsp->fd, buf + total,
447                                         byte_count - total, offset + total);
448
449                 if (ret == 0) return total;
450                 if (ret == -1) {
451                         if (errno == EINTR)
452                                 continue;
453                         else
454                                 return -1;
455                 }
456                 total += ret;
457         }
458         return (ssize_t)total;
459 }
460
461 /****************************************************************************
462  Write data to a fd on the vfs.
463 ****************************************************************************/
464
465 ssize_t vfs_write_data(files_struct *fsp,const char *buffer,size_t N)
466 {
467         size_t total=0;
468         ssize_t ret;
469
470         while (total < N) {
471                 ret = SMB_VFS_WRITE(fsp,fsp->fd,buffer + total,N - total);
472
473                 if (ret == -1)
474                         return -1;
475                 if (ret == 0)
476                         return total;
477
478                 total += ret;
479         }
480         return (ssize_t)total;
481 }
482
483 ssize_t vfs_pwrite_data(files_struct *fsp,const char *buffer,
484                 size_t N, SMB_OFF_T offset)
485 {
486         size_t total=0;
487         ssize_t ret;
488
489         while (total < N) {
490                 ret = SMB_VFS_PWRITE(fsp, fsp->fd, buffer + total,
491                                 N - total, offset + total);
492
493                 if (ret == -1)
494                         return -1;
495                 if (ret == 0)
496                         return total;
497
498                 total += ret;
499         }
500         return (ssize_t)total;
501 }
502 /****************************************************************************
503  An allocate file space call using the vfs interface.
504  Allocates space for a file from a filedescriptor.
505  Returns 0 on success, -1 on failure.
506 ****************************************************************************/
507
508 int vfs_allocate_file_space(files_struct *fsp, SMB_BIG_UINT len)
509 {
510         int ret;
511         SMB_STRUCT_STAT st;
512         connection_struct *conn = fsp->conn;
513         SMB_BIG_UINT space_avail;
514         SMB_BIG_UINT bsize,dfree,dsize;
515
516         release_level_2_oplocks_on_change(fsp);
517
518         /*
519          * Actually try and commit the space on disk....
520          */
521
522         DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", fsp->fsp_name, (double)len ));
523
524         if (((SMB_OFF_T)len) < 0) {
525                 DEBUG(0,("vfs_allocate_file_space: %s negative len requested.\n", fsp->fsp_name ));
526                 return -1;
527         }
528
529         ret = SMB_VFS_FSTAT(fsp,fsp->fd,&st);
530         if (ret == -1)
531                 return ret;
532
533         if (len == (SMB_BIG_UINT)st.st_size)
534                 return 0;
535
536         if (len < (SMB_BIG_UINT)st.st_size) {
537                 /* Shrink - use ftruncate. */
538
539                 DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
540                                 fsp->fsp_name, (double)st.st_size ));
541
542                 flush_write_cache(fsp, SIZECHANGE_FLUSH);
543                 if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fd, (SMB_OFF_T)len)) != -1) {
544                         set_filelen_write_cache(fsp, len);
545                 }
546                 return ret;
547         }
548
549         /* Grow - we need to test if we have enough space. */
550
551         if (!lp_strict_allocate(SNUM(fsp->conn)))
552                 return 0;
553
554         len -= st.st_size;
555         len /= 1024; /* Len is now number of 1k blocks needed. */
556         space_avail = SMB_VFS_DISK_FREE(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize);
557         if (space_avail == (SMB_BIG_UINT)-1) {
558                 return -1;
559         }
560
561         DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %.0f, space avail = %.0f\n",
562                         fsp->fsp_name, (double)st.st_size, (double)len, (double)space_avail ));
563
564         if (len > space_avail) {
565                 errno = ENOSPC;
566                 return -1;
567         }
568
569         return 0;
570 }
571
572 /****************************************************************************
573  A vfs set_filelen call.
574  set the length of a file from a filedescriptor.
575  Returns 0 on success, -1 on failure.
576 ****************************************************************************/
577
578 int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
579 {
580         int ret;
581
582         release_level_2_oplocks_on_change(fsp);
583         DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len));
584         flush_write_cache(fsp, SIZECHANGE_FLUSH);
585         if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fd, len)) != -1)
586                 set_filelen_write_cache(fsp, len);
587
588         return ret;
589 }
590
591 /****************************************************************************
592  Transfer some data (n bytes) between two file_struct's.
593 ****************************************************************************/
594
595 static files_struct *in_fsp;
596 static files_struct *out_fsp;
597
598 static ssize_t read_fn(int fd, void *buf, size_t len)
599 {
600         return SMB_VFS_READ(in_fsp, fd, buf, len);
601 }
602
603 static ssize_t write_fn(int fd, const void *buf, size_t len)
604 {
605         return SMB_VFS_WRITE(out_fsp, fd, buf, len);
606 }
607
608 SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n)
609 {
610         in_fsp = in;
611         out_fsp = out;
612
613         return transfer_file_internal(in_fsp->fd, out_fsp->fd, n, read_fn, write_fn);
614 }
615
616 /*******************************************************************
617  A vfs_readdir wrapper which just returns the file name.
618 ********************************************************************/
619
620 char *vfs_readdirname(connection_struct *conn, void *p)
621 {
622         SMB_STRUCT_DIRENT *ptr= NULL;
623         char *dname;
624
625         if (!p)
626                 return(NULL);
627
628         ptr = SMB_VFS_READDIR(conn,p);
629         if (!ptr)
630                 return(NULL);
631
632         dname = ptr->d_name;
633
634 #ifdef NEXT2
635         if (telldir(p) < 0)
636                 return(NULL);
637 #endif
638
639 #ifdef HAVE_BROKEN_READDIR
640         /* using /usr/ucb/cc is BAD */
641         dname = dname - 2;
642 #endif
643
644         return(dname);
645 }
646
647 /*******************************************************************
648  A wrapper for vfs_chdir().
649 ********************************************************************/
650
651 int vfs_ChDir(connection_struct *conn, const char *path)
652 {
653         int res;
654         static pstring LastDir="";
655
656         if (strcsequal(path,"."))
657                 return(0);
658
659         if (*path == '/' && strcsequal(LastDir,path))
660                 return(0);
661
662         DEBUG(4,("vfs_ChDir to %s\n",path));
663
664         res = SMB_VFS_CHDIR(conn,path);
665         if (!res)
666                 pstrcpy(LastDir,path);
667         return(res);
668 }
669
670 /* number of list structures for a caching GetWd function. */
671 #define MAX_GETWDCACHE (50)
672
673 static struct {
674         SMB_DEV_T dev; /* These *must* be compatible with the types returned in a stat() call. */
675         SMB_INO_T inode; /* These *must* be compatible with the types returned in a stat() call. */
676         char *dos_path; /* The pathname in DOS format. */
677         BOOL valid;
678 } ino_list[MAX_GETWDCACHE];
679
680 extern BOOL use_getwd_cache;
681
682 /****************************************************************************
683  Prompte a ptr (to make it recently used)
684 ****************************************************************************/
685
686 static void array_promote(char *array,int elsize,int element)
687 {
688         char *p;
689         if (element == 0)
690                 return;
691
692         p = (char *)SMB_MALLOC(elsize);
693
694         if (!p) {
695                 DEBUG(5,("array_promote: malloc fail\n"));
696                 return;
697         }
698
699         memcpy(p,array + element * elsize, elsize);
700         memmove(array + elsize,array,elsize*element);
701         memcpy(array,p,elsize);
702         SAFE_FREE(p);
703 }
704
705 /*******************************************************************
706  Return the absolute current directory path - given a UNIX pathname.
707  Note that this path is returned in DOS format, not UNIX
708  format. Note this can be called with conn == NULL.
709 ********************************************************************/
710
711 char *vfs_GetWd(connection_struct *conn, char *path)
712 {
713         pstring s;
714         static BOOL getwd_cache_init = False;
715         SMB_STRUCT_STAT st, st2;
716         int i;
717
718         *s = 0;
719
720         if (!use_getwd_cache)
721                 return(SMB_VFS_GETWD(conn,path));
722
723         /* init the cache */
724         if (!getwd_cache_init) {
725                 getwd_cache_init = True;
726                 for (i=0;i<MAX_GETWDCACHE;i++) {
727                         string_set(&ino_list[i].dos_path,"");
728                         ino_list[i].valid = False;
729                 }
730         }
731
732         /*  Get the inode of the current directory, if this doesn't work we're
733                 in trouble :-) */
734
735         if (SMB_VFS_STAT(conn, ".",&st) == -1) {
736                 /* Known to fail for root: the directory may be
737                  * NFS-mounted and exported with root_squash (so has no root access). */
738                 DEBUG(1,("vfs_GetWd: couldn't stat \".\" path=%s error %s (NFS problem ?)\n", path, strerror(errno) ));
739                 return(SMB_VFS_GETWD(conn,path));
740         }
741
742
743         for (i=0; i<MAX_GETWDCACHE; i++) {
744                 if (ino_list[i].valid) {
745
746                         /*  If we have found an entry with a matching inode and dev number
747                                 then find the inode number for the directory in the cached string.
748                                 If this agrees with that returned by the stat for the current
749                                 directory then all is o.k. (but make sure it is a directory all
750                                 the same...) */
751
752                         if (st.st_ino == ino_list[i].inode && st.st_dev == ino_list[i].dev) {
753                                 if (SMB_VFS_STAT(conn,ino_list[i].dos_path,&st2) == 0) {
754                                         if (st.st_ino == st2.st_ino && st.st_dev == st2.st_dev &&
755                                                         (st2.st_mode & S_IFMT) == S_IFDIR) {
756                                                 pstrcpy (path, ino_list[i].dos_path);
757
758                                                 /* promote it for future use */
759                                                 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
760                                                 return (path);
761                                         } else {
762                                                 /*  If the inode is different then something's changed,
763                                                         scrub the entry and start from scratch. */
764                                                 ino_list[i].valid = False;
765                                         }
766                                 }
767                         }
768                 }
769         }
770
771         /*  We don't have the information to hand so rely on traditional methods.
772                 The very slow getcwd, which spawns a process on some systems, or the
773                 not quite so bad getwd. */
774
775         if (!SMB_VFS_GETWD(conn,s)) {
776                 DEBUG(0,("vfs_GetWd: SMB_VFS_GETWD call failed, errno %s\n",strerror(errno)));
777                 return (NULL);
778         }
779
780         pstrcpy(path,s);
781
782         DEBUG(5,("vfs_GetWd %s, inode %.0f, dev %.0f\n",s,(double)st.st_ino,(double)st.st_dev));
783
784         /* add it to the cache */
785         i = MAX_GETWDCACHE - 1;
786         string_set(&ino_list[i].dos_path,s);
787         ino_list[i].dev = st.st_dev;
788         ino_list[i].inode = st.st_ino;
789         ino_list[i].valid = True;
790
791         /* put it at the top of the list */
792         array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
793
794         return (path);
795 }
796
797 BOOL canonicalize_path(connection_struct *conn, pstring path)
798 {
799 #ifdef REALPATH_TAKES_NULL
800         char *resolved_name = SMB_VFS_REALPATH(conn,path,NULL);
801         if (!resolved_name) {
802                 return False;
803         }
804         pstrcpy(path, resolved_name);
805         SAFE_FREE(resolved_name);
806         return True;
807 #else
808 #ifdef PATH_MAX
809         char resolved_name_buf[PATH_MAX+1];
810 #else
811         pstring resolved_name_buf;
812 #endif
813         char *resolved_name = SMB_VFS_REALPATH(conn,path,resolved_name_buf);
814         if (!resolved_name) {
815                 return False;
816         }
817         pstrcpy(path, resolved_name);
818         return True;
819 #endif /* REALPATH_TAKES_NULL */
820 }
821
822 /*******************************************************************
823  Reduce a file name, removing .. elements and checking that
824  it is below dir in the heirachy. This uses realpath.
825 ********************************************************************/
826
827 BOOL reduce_name(connection_struct *conn, const pstring fname)
828 {
829 #ifdef REALPATH_TAKES_NULL
830         BOOL free_resolved_name = True;
831 #else
832 #ifdef PATH_MAX
833         char resolved_name_buf[PATH_MAX+1];
834 #else
835         pstring resolved_name_buf;
836 #endif
837         BOOL free_resolved_name = False;
838 #endif
839         char *resolved_name = NULL;
840         size_t con_path_len = strlen(conn->connectpath);
841         char *p = NULL;
842         int saved_errno = errno;
843
844         DEBUG(3,("reduce_name [%s] [%s]\n", fname, conn->connectpath));
845
846 #ifdef REALPATH_TAKES_NULL
847         resolved_name = SMB_VFS_REALPATH(conn,fname,NULL);
848 #else
849         resolved_name = SMB_VFS_REALPATH(conn,fname,resolved_name_buf);
850 #endif
851
852         if (!resolved_name) {
853                 switch (errno) {
854                         case ENOTDIR:
855                                 DEBUG(3,("reduce_name: Component not a directory in getting realpath for %s\n", fname));
856                                 errno = saved_errno;
857                                 return False;
858                         case ENOENT:
859                         {
860                                 pstring tmp_fname;
861                                 fstring last_component;
862                                 /* Last component didn't exist. Remove it and try and canonicalise the directory. */
863
864                                 pstrcpy(tmp_fname, fname);
865                                 p = strrchr_m(tmp_fname, '/');
866                                 if (p) {
867                                         *p++ = '\0';
868                                         fstrcpy(last_component, p);
869                                 } else {
870                                         fstrcpy(last_component, tmp_fname);
871                                         pstrcpy(tmp_fname, ".");
872                                 }
873
874 #ifdef REALPATH_TAKES_NULL
875                                 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,NULL);
876 #else
877                                 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,resolved_name_buf);
878 #endif
879                                 if (!resolved_name) {
880                                         DEBUG(3,("reduce_name: couldn't get realpath for %s\n", fname));
881                                         errno = saved_errno;
882                                         return False;
883                                 }
884                                 pstrcpy(tmp_fname, resolved_name);
885                                 pstrcat(tmp_fname, "/");
886                                 pstrcat(tmp_fname, last_component);
887 #ifdef REALPATH_TAKES_NULL
888                                 SAFE_FREE(resolved_name);
889                                 resolved_name = SMB_STRDUP(tmp_fname);
890                                 if (!resolved_name) {
891                                         DEBUG(0,("reduce_name: malloc fail for %s\n", tmp_fname));
892                                         errno = saved_errno;
893                                         return False;
894                                 }
895 #else
896 #ifdef PATH_MAX
897                                 safe_strcpy(resolved_name_buf, tmp_fname, PATH_MAX);
898 #else
899                                 pstrcpy(resolved_name_buf, tmp_fname);
900 #endif
901                                 resolved_name = resolved_name_buf;
902 #endif
903                                 break;
904                         }
905                         default:
906                                 DEBUG(1,("reduce_name: couldn't get realpath for %s\n", fname));
907                                 /* Don't restore the saved errno. We need to return the error that
908                                    realpath caused here as it was not one of the cases we handle. JRA. */
909                                 return False;
910                 }
911         }
912
913         DEBUG(10,("reduce_name realpath [%s] -> [%s]\n", fname, resolved_name));
914
915         if (*resolved_name != '/') {
916                 DEBUG(0,("reduce_name: realpath doesn't return absolute paths !\n"));
917                 if (free_resolved_name)
918                         SAFE_FREE(resolved_name);
919                 errno = saved_errno;
920                 return False;
921         }
922
923         /* Check for widelinks allowed. */
924         if (!lp_widelinks(SNUM(conn)) && (strncmp(conn->connectpath, resolved_name, con_path_len) != 0)) {
925                 DEBUG(2, ("reduce_name: Bad access attempt: %s is a symlink outside the share path", fname));
926                 if (free_resolved_name)
927                         SAFE_FREE(resolved_name);
928                 errno = EACCES;
929                 return False;
930         }
931
932         /* Check if we are allowing users to follow symlinks */
933         /* Patch from David Clerc <David.Clerc@cui.unige.ch>
934                 University of Geneva */
935                                                                                                                                                     
936 #ifdef S_ISLNK
937         if (!lp_symlinks(SNUM(conn))) {
938                 SMB_STRUCT_STAT statbuf;
939                 if ( (SMB_VFS_LSTAT(conn,fname,&statbuf) != -1) &&
940                                 (S_ISLNK(statbuf.st_mode)) ) {
941                         if (free_resolved_name)
942                                 SAFE_FREE(resolved_name);
943                         DEBUG(3,("reduce_name: denied: file path name %s is a symlink\n",resolved_name));
944                         errno = EACCES;
945                         return False;
946                 }
947         }
948 #endif
949
950         DEBUG(3,("reduce_name: %s reduced to %s\n", fname, resolved_name));
951         if (free_resolved_name)
952                 SAFE_FREE(resolved_name);
953         errno = saved_errno;
954         return(True);
955 }