r6408: Fix compile error lurking where PATH_MAX is not defined. Bugzilla #2560.
[jra/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_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) 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 = TALLOC_ZERO_P(conn->mem_ctx,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         if (space_avail == (SMB_BIG_UINT)-1) {
556                 return -1;
557         }
558
559         DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %.0f, space avail = %.0f\n",
560                         fsp->fsp_name, (double)st.st_size, (double)len, (double)space_avail ));
561
562         if (len > space_avail) {
563                 errno = ENOSPC;
564                 return -1;
565         }
566
567         return 0;
568 }
569
570 /****************************************************************************
571  A vfs set_filelen call.
572  set the length of a file from a filedescriptor.
573  Returns 0 on success, -1 on failure.
574 ****************************************************************************/
575
576 int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
577 {
578         int ret;
579
580         release_level_2_oplocks_on_change(fsp);
581         DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len));
582         flush_write_cache(fsp, SIZECHANGE_FLUSH);
583         if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fd, len)) != -1)
584                 set_filelen_write_cache(fsp, len);
585
586         return ret;
587 }
588
589 /****************************************************************************
590  Transfer some data (n bytes) between two file_struct's.
591 ****************************************************************************/
592
593 static files_struct *in_fsp;
594 static files_struct *out_fsp;
595
596 static ssize_t read_fn(int fd, void *buf, size_t len)
597 {
598         return SMB_VFS_READ(in_fsp, fd, buf, len);
599 }
600
601 static ssize_t write_fn(int fd, const void *buf, size_t len)
602 {
603         return SMB_VFS_WRITE(out_fsp, fd, buf, len);
604 }
605
606 SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n)
607 {
608         in_fsp = in;
609         out_fsp = out;
610
611         return transfer_file_internal(in_fsp->fd, out_fsp->fd, n, read_fn, write_fn);
612 }
613
614 /*******************************************************************
615  A vfs_readdir wrapper which just returns the file name.
616 ********************************************************************/
617
618 char *vfs_readdirname(connection_struct *conn, void *p)
619 {
620         SMB_STRUCT_DIRENT *ptr= NULL;
621         char *dname;
622
623         if (!p)
624                 return(NULL);
625
626         ptr = SMB_VFS_READDIR(conn,p);
627         if (!ptr)
628                 return(NULL);
629
630         dname = ptr->d_name;
631
632 #ifdef NEXT2
633         if (telldir(p) < 0)
634                 return(NULL);
635 #endif
636
637 #ifdef HAVE_BROKEN_READDIR
638         /* using /usr/ucb/cc is BAD */
639         dname = dname - 2;
640 #endif
641
642         return(dname);
643 }
644
645 /*******************************************************************
646  A wrapper for vfs_chdir().
647 ********************************************************************/
648
649 int vfs_ChDir(connection_struct *conn, const char *path)
650 {
651         int res;
652         static pstring LastDir="";
653
654         if (strcsequal(path,"."))
655                 return(0);
656
657         if (*path == '/' && strcsequal(LastDir,path))
658                 return(0);
659
660         DEBUG(4,("vfs_ChDir to %s\n",path));
661
662         res = SMB_VFS_CHDIR(conn,path);
663         if (!res)
664                 pstrcpy(LastDir,path);
665         return(res);
666 }
667
668 /* number of list structures for a caching GetWd function. */
669 #define MAX_GETWDCACHE (50)
670
671 static struct {
672         SMB_DEV_T dev; /* These *must* be compatible with the types returned in a stat() call. */
673         SMB_INO_T inode; /* These *must* be compatible with the types returned in a stat() call. */
674         char *dos_path; /* The pathname in DOS format. */
675         BOOL valid;
676 } ino_list[MAX_GETWDCACHE];
677
678 extern BOOL use_getwd_cache;
679
680 /****************************************************************************
681  Prompte a ptr (to make it recently used)
682 ****************************************************************************/
683
684 static void array_promote(char *array,int elsize,int element)
685 {
686         char *p;
687         if (element == 0)
688                 return;
689
690         p = (char *)SMB_MALLOC(elsize);
691
692         if (!p) {
693                 DEBUG(5,("array_promote: malloc fail\n"));
694                 return;
695         }
696
697         memcpy(p,array + element * elsize, elsize);
698         memmove(array + elsize,array,elsize*element);
699         memcpy(array,p,elsize);
700         SAFE_FREE(p);
701 }
702
703 /*******************************************************************
704  Return the absolute current directory path - given a UNIX pathname.
705  Note that this path is returned in DOS format, not UNIX
706  format. Note this can be called with conn == NULL.
707 ********************************************************************/
708
709 char *vfs_GetWd(connection_struct *conn, char *path)
710 {
711         pstring s;
712         static BOOL getwd_cache_init = False;
713         SMB_STRUCT_STAT st, st2;
714         int i;
715
716         *s = 0;
717
718         if (!use_getwd_cache)
719                 return(SMB_VFS_GETWD(conn,path));
720
721         /* init the cache */
722         if (!getwd_cache_init) {
723                 getwd_cache_init = True;
724                 for (i=0;i<MAX_GETWDCACHE;i++) {
725                         string_set(&ino_list[i].dos_path,"");
726                         ino_list[i].valid = False;
727                 }
728         }
729
730         /*  Get the inode of the current directory, if this doesn't work we're
731                 in trouble :-) */
732
733         if (SMB_VFS_STAT(conn, ".",&st) == -1) {
734                 /* Known to fail for root: the directory may be
735                  * NFS-mounted and exported with root_squash (so has no root access). */
736                 DEBUG(1,("vfs_GetWd: couldn't stat \".\" path=%s error %s (NFS problem ?)\n", path, strerror(errno) ));
737                 return(SMB_VFS_GETWD(conn,path));
738         }
739
740
741         for (i=0; i<MAX_GETWDCACHE; i++) {
742                 if (ino_list[i].valid) {
743
744                         /*  If we have found an entry with a matching inode and dev number
745                                 then find the inode number for the directory in the cached string.
746                                 If this agrees with that returned by the stat for the current
747                                 directory then all is o.k. (but make sure it is a directory all
748                                 the same...) */
749
750                         if (st.st_ino == ino_list[i].inode && st.st_dev == ino_list[i].dev) {
751                                 if (SMB_VFS_STAT(conn,ino_list[i].dos_path,&st2) == 0) {
752                                         if (st.st_ino == st2.st_ino && st.st_dev == st2.st_dev &&
753                                                         (st2.st_mode & S_IFMT) == S_IFDIR) {
754                                                 pstrcpy (path, ino_list[i].dos_path);
755
756                                                 /* promote it for future use */
757                                                 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
758                                                 return (path);
759                                         } else {
760                                                 /*  If the inode is different then something's changed,
761                                                         scrub the entry and start from scratch. */
762                                                 ino_list[i].valid = False;
763                                         }
764                                 }
765                         }
766                 }
767         }
768
769         /*  We don't have the information to hand so rely on traditional methods.
770                 The very slow getcwd, which spawns a process on some systems, or the
771                 not quite so bad getwd. */
772
773         if (!SMB_VFS_GETWD(conn,s)) {
774                 DEBUG(0,("vfs_GetWd: SMB_VFS_GETWD call failed, errno %s\n",strerror(errno)));
775                 return (NULL);
776         }
777
778         pstrcpy(path,s);
779
780         DEBUG(5,("vfs_GetWd %s, inode %.0f, dev %.0f\n",s,(double)st.st_ino,(double)st.st_dev));
781
782         /* add it to the cache */
783         i = MAX_GETWDCACHE - 1;
784         string_set(&ino_list[i].dos_path,s);
785         ino_list[i].dev = st.st_dev;
786         ino_list[i].inode = st.st_ino;
787         ino_list[i].valid = True;
788
789         /* put it at the top of the list */
790         array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
791
792         return (path);
793 }
794
795 BOOL canonicalize_path(connection_struct *conn, pstring path)
796 {
797 #ifdef REALPATH_TAKES_NULL
798         char *resolved_name = SMB_VFS_REALPATH(conn,path,NULL);
799         if (!resolved_name) {
800                 return False;
801         }
802         pstrcpy(path, resolved_name);
803         SAFE_FREE(resolved_name);
804         return True;
805 #else
806 #ifdef PATH_MAX
807         char resolved_name_buf[PATH_MAX+1];
808 #else
809         pstring resolved_name_buf;
810 #endif
811         char *resolved_name = SMB_VFS_REALPATH(conn,path,resolved_name_buf);
812         if (!resolved_name) {
813                 return False;
814         }
815         pstrcpy(path, resolved_name);
816         return True;
817 #endif /* REALPATH_TAKES_NULL */
818 }
819
820 /*******************************************************************
821  Reduce a file name, removing .. elements and checking that
822  it is below dir in the heirachy. This uses realpath.
823 ********************************************************************/
824
825 BOOL reduce_name(connection_struct *conn, const pstring fname)
826 {
827 #ifdef REALPATH_TAKES_NULL
828         BOOL free_resolved_name = True;
829 #else
830 #ifdef PATH_MAX
831         char resolved_name_buf[PATH_MAX+1];
832 #else
833         pstring resolved_name_buf;
834 #endif
835         BOOL free_resolved_name = False;
836 #endif
837         char *resolved_name = NULL;
838         size_t con_path_len = strlen(conn->connectpath);
839         char *p = NULL;
840         int saved_errno = errno;
841
842         DEBUG(3,("reduce_name [%s] [%s]\n", fname, conn->connectpath));
843
844 #ifdef REALPATH_TAKES_NULL
845         resolved_name = SMB_VFS_REALPATH(conn,fname,NULL);
846 #else
847         resolved_name = SMB_VFS_REALPATH(conn,fname,resolved_name_buf);
848 #endif
849
850         if (!resolved_name) {
851                 switch (errno) {
852                         case ENOTDIR:
853                                 DEBUG(3,("reduce_name: Component not a directory in getting realpath for %s\n", fname));
854                                 errno = saved_errno;
855                                 return False;
856                         case ENOENT:
857                         {
858                                 pstring tmp_fname;
859                                 fstring last_component;
860                                 /* Last component didn't exist. Remove it and try and canonicalise the directory. */
861
862                                 pstrcpy(tmp_fname, fname);
863                                 p = strrchr_m(tmp_fname, '/');
864                                 if (p) {
865                                         *p++ = '\0';
866                                         fstrcpy(last_component, p);
867                                 } else {
868                                         fstrcpy(last_component, tmp_fname);
869                                         pstrcpy(tmp_fname, ".");
870                                 }
871
872 #ifdef REALPATH_TAKES_NULL
873                                 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,NULL);
874 #else
875                                 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,resolved_name_buf);
876 #endif
877                                 if (!resolved_name) {
878                                         DEBUG(3,("reduce_name: couldn't get realpath for %s\n", fname));
879                                         errno = saved_errno;
880                                         return False;
881                                 }
882                                 pstrcpy(tmp_fname, resolved_name);
883                                 pstrcat(tmp_fname, "/");
884                                 pstrcat(tmp_fname, last_component);
885 #ifdef REALPATH_TAKES_NULL
886                                 SAFE_FREE(resolved_name);
887                                 resolved_name = SMB_STRDUP(tmp_fname);
888                                 if (!resolved_name) {
889                                         DEBUG(0,("reduce_name: malloc fail for %s\n", tmp_fname));
890                                         errno = saved_errno;
891                                         return False;
892                                 }
893 #else
894 #ifdef PATH_MAX
895                                 safe_strcpy(resolved_name_buf, tmp_fname, PATH_MAX);
896 #else
897                                 pstrcpy(resolved_name_buf, tmp_fname);
898 #endif
899                                 resolved_name = resolved_name_buf;
900 #endif
901                                 break;
902                         }
903                         default:
904                                 DEBUG(1,("reduce_name: couldn't get realpath for %s\n", fname));
905                                 /* Don't restore the saved errno. We need to return the error that
906                                    realpath caused here as it was not one of the cases we handle. JRA. */
907                                 return False;
908                 }
909         }
910
911         DEBUG(10,("reduce_name realpath [%s] -> [%s]\n", fname, resolved_name));
912
913         if (*resolved_name != '/') {
914                 DEBUG(0,("reduce_name: realpath doesn't return absolute paths !\n"));
915                 if (free_resolved_name)
916                         SAFE_FREE(resolved_name);
917                 errno = saved_errno;
918                 return False;
919         }
920
921         /* Check for widelinks allowed. */
922         if (!lp_widelinks(SNUM(conn)) && (strncmp(conn->connectpath, resolved_name, con_path_len) != 0)) {
923                 DEBUG(2, ("reduce_name: Bad access attempt: %s is a symlink outside the share path", fname));
924                 if (free_resolved_name)
925                         SAFE_FREE(resolved_name);
926                 errno = EACCES;
927                 return False;
928         }
929
930         /* Check if we are allowing users to follow symlinks */
931         /* Patch from David Clerc <David.Clerc@cui.unige.ch>
932                 University of Geneva */
933                                                                                                                                                     
934 #ifdef S_ISLNK
935         if (!lp_symlinks(SNUM(conn))) {
936                 SMB_STRUCT_STAT statbuf;
937                 if ( (SMB_VFS_LSTAT(conn,fname,&statbuf) != -1) &&
938                                 (S_ISLNK(statbuf.st_mode)) ) {
939                         if (free_resolved_name)
940                                 SAFE_FREE(resolved_name);
941                         DEBUG(3,("reduce_name: denied: file path name %s is a symlink\n",resolved_name));
942                         errno = EACCES;
943                         return False;
944                 }
945         }
946 #endif
947
948         DEBUG(3,("reduce_name: %s reduced to %s\n", fname, resolved_name));
949         if (free_resolved_name)
950                 SAFE_FREE(resolved_name);
951         errno = saved_errno;
952         return(True);
953 }