r21082: Make canonicalize_path static to service.c -- we do have conn->connectpath
[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    Copyright (C) James Peach 2006
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22
23    This work was sponsored by Optifacio Software Services, Inc.
24 */
25
26 #include "includes.h"
27
28 #undef DBGC_CLASS
29 #define DBGC_CLASS DBGC_VFS
30
31 static_decl_vfs;
32
33 struct vfs_init_function_entry {
34         char *name;
35         vfs_op_tuple *vfs_op_tuples;
36         struct vfs_init_function_entry *prev, *next;
37 };
38
39 static struct vfs_init_function_entry *backends = NULL;
40
41 /****************************************************************************
42     maintain the list of available backends
43 ****************************************************************************/
44
45 static struct vfs_init_function_entry *vfs_find_backend_entry(const char *name)
46 {
47         struct vfs_init_function_entry *entry = backends;
48  
49         while(entry) {
50                 if (strcmp(entry->name, name)==0) return entry;
51                 entry = entry->next;
52         }
53
54         return NULL;
55 }
56
57 NTSTATUS smb_register_vfs(int version, const char *name, vfs_op_tuple *vfs_op_tuples)
58 {
59         struct vfs_init_function_entry *entry = backends;
60
61         if ((version != SMB_VFS_INTERFACE_VERSION)) {
62                 DEBUG(0, ("Failed to register vfs module.\n"
63                           "The module was compiled against SMB_VFS_INTERFACE_VERSION %d,\n"
64                           "current SMB_VFS_INTERFACE_VERSION is %d.\n"
65                           "Please recompile against the current Samba Version!\n",  
66                           version, SMB_VFS_INTERFACE_VERSION));
67                 return NT_STATUS_OBJECT_TYPE_MISMATCH;
68         }
69
70         if (!name || !name[0] || !vfs_op_tuples) {
71                 DEBUG(0,("smb_register_vfs() called with NULL pointer or empty name!\n"));
72                 return NT_STATUS_INVALID_PARAMETER;
73         }
74
75         if (vfs_find_backend_entry(name)) {
76                 DEBUG(0,("VFS module %s already loaded!\n", name));
77                 return NT_STATUS_OBJECT_NAME_COLLISION;
78         }
79
80         entry = SMB_XMALLOC_P(struct vfs_init_function_entry);
81         entry->name = smb_xstrdup(name);
82         entry->vfs_op_tuples = vfs_op_tuples;
83
84         DLIST_ADD(backends, entry);
85         DEBUG(5, ("Successfully added vfs backend '%s'\n", name));
86         return NT_STATUS_OK;
87 }
88
89 /****************************************************************************
90   initialise default vfs hooks
91 ****************************************************************************/
92
93 static void vfs_init_default(connection_struct *conn)
94 {
95         DEBUG(3, ("Initialising default vfs hooks\n"));
96         vfs_init_custom(conn, DEFAULT_VFS_MODULE_NAME);
97 }
98
99 /****************************************************************************
100   initialise custom vfs hooks
101  ****************************************************************************/
102
103 static inline void vfs_set_operation(struct vfs_ops * vfs, vfs_op_type which,
104                                 struct vfs_handle_struct * handle, void * op)
105 {
106         ((struct vfs_handle_struct **)&vfs->handles)[which] = handle;
107         ((void **)(void *)&vfs->ops)[which] = op;
108 }
109
110 BOOL vfs_init_custom(connection_struct *conn, const char *vfs_object)
111 {
112         vfs_op_tuple *ops;
113         char *module_name = NULL;
114         char *module_param = NULL, *p;
115         int i;
116         vfs_handle_struct *handle;
117         struct vfs_init_function_entry *entry;
118         
119         if (!conn||!vfs_object||!vfs_object[0]) {
120                 DEBUG(0,("vfs_init_custon() called with NULL pointer or emtpy vfs_object!\n"));
121                 return False;
122         }
123
124         if(!backends) {
125                 static_init_vfs;
126         }
127
128         DEBUG(3, ("Initialising custom vfs hooks from [%s]\n", vfs_object));
129
130         module_name = smb_xstrdup(vfs_object);
131
132         p = strchr_m(module_name, ':');
133
134         if (p) {
135                 *p = 0;
136                 module_param = p+1;
137                 trim_char(module_param, ' ', ' ');
138         }
139
140         trim_char(module_name, ' ', ' ');
141
142         /* First, try to load the module with the new module system */
143         if((entry = vfs_find_backend_entry(module_name)) || 
144            (NT_STATUS_IS_OK(smb_probe_module("vfs", module_name)) && 
145                 (entry = vfs_find_backend_entry(module_name)))) {
146
147                 DEBUGADD(5,("Successfully loaded vfs module [%s] with the new modules system\n", vfs_object));
148                 
149                 if ((ops = entry->vfs_op_tuples) == NULL) {
150                         DEBUG(0, ("entry->vfs_op_tuples==NULL for [%s] failed\n", vfs_object));
151                         SAFE_FREE(module_name);
152                         return False;
153                 }
154         } else {
155                 DEBUG(0,("Can't find a vfs module [%s]\n",vfs_object));
156                 SAFE_FREE(module_name);
157                 return False;
158         }
159
160         handle = TALLOC_ZERO_P(conn->mem_ctx,vfs_handle_struct);
161         if (!handle) {
162                 DEBUG(0,("talloc_zero() failed!\n"));
163                 SAFE_FREE(module_name);
164                 return False;
165         }
166         memcpy(&handle->vfs_next, &conn->vfs, sizeof(struct vfs_ops));
167         handle->conn = conn;
168         if (module_param) {
169                 handle->param = talloc_strdup(conn->mem_ctx, module_param);
170         }
171         DLIST_ADD(conn->vfs_handles, handle);
172
173         for(i=0; ops[i].op != NULL; i++) {
174                 DEBUG(5, ("Checking operation #%d (type %d, layer %d)\n", i, ops[i].type, ops[i].layer));
175                 if(ops[i].layer == SMB_VFS_LAYER_OPAQUE) {
176                         /* If this operation was already made opaque by different module, it
177                          * will be overridded here.
178                          */
179                         DEBUGADD(5, ("Making operation type %d opaque [module %s]\n", ops[i].type, vfs_object));
180                         vfs_set_operation(&conn->vfs_opaque, ops[i].type, handle, ops[i].op);
181                 }
182                 /* Change current VFS disposition*/
183                 DEBUGADD(5, ("Accepting operation type %d from module %s\n", ops[i].type, vfs_object));
184                 vfs_set_operation(&conn->vfs, ops[i].type, handle, ops[i].op);
185         }
186
187         SAFE_FREE(module_name);
188         return True;
189 }
190
191 /*****************************************************************
192  Allow VFS modules to extend files_struct with VFS-specific state.
193  This will be ok for small numbers of extensions, but might need to
194  be refactored if it becomes more widely used.
195 ******************************************************************/
196
197 #define EXT_DATA_AREA(e) ((uint8 *)(e) + sizeof(struct vfs_fsp_data))
198
199 void *vfs_add_fsp_extension_notype(vfs_handle_struct *handle, files_struct *fsp, size_t ext_size)
200 {
201         struct vfs_fsp_data *ext;
202         void * ext_data;
203
204         /* Prevent VFS modules adding multiple extensions. */
205         if ((ext_data = vfs_fetch_fsp_extension(handle, fsp))) {
206                 return ext_data;
207         }
208
209         ext = (struct vfs_fsp_data *)TALLOC_ZERO(
210                 handle->conn->mem_ctx, sizeof(struct vfs_fsp_data) + ext_size);
211         if (ext == NULL) {
212                 return NULL;
213         }
214
215         ext->owner = handle;
216         ext->next = fsp->vfs_extension;
217         fsp->vfs_extension = ext;
218         return EXT_DATA_AREA(ext);
219 }
220
221 void vfs_remove_fsp_extension(vfs_handle_struct *handle, files_struct *fsp)
222 {
223         struct vfs_fsp_data *curr;
224         struct vfs_fsp_data *prev;
225
226         for (curr = fsp->vfs_extension, prev = NULL;
227              curr;
228              prev = curr, curr = curr->next) {
229                 if (curr->owner == handle) {
230                     if (prev) {
231                             prev->next = curr->next;
232                     } else {
233                             fsp->vfs_extension = curr->next;
234                     }
235                     TALLOC_FREE(curr);
236                     return;
237                 }
238         }
239 }
240
241 void *vfs_fetch_fsp_extension(vfs_handle_struct *handle, files_struct *fsp)
242 {
243         struct vfs_fsp_data *head;
244
245         for (head = fsp->vfs_extension; head; head = head->next) {
246                 if (head->owner == handle) {
247                         return EXT_DATA_AREA(head);
248                 }
249         }
250
251         return NULL;
252 }
253
254 #undef EXT_DATA_AREA
255
256 /*****************************************************************
257  Generic VFS init.
258 ******************************************************************/
259
260 BOOL smbd_vfs_init(connection_struct *conn)
261 {
262         const char **vfs_objects;
263         unsigned int i = 0;
264         int j = 0;
265         
266         /* Normal share - initialise with disk access functions */
267         vfs_init_default(conn);
268         vfs_objects = lp_vfs_objects(SNUM(conn));
269
270         /* Override VFS functions if 'vfs object' was not specified*/
271         if (!vfs_objects || !vfs_objects[0])
272                 return True;
273         
274         for (i=0; vfs_objects[i] ;) {
275                 i++;
276         }
277
278         for (j=i-1; j >= 0; j--) {
279                 if (!vfs_init_custom(conn, vfs_objects[j])) {
280                         DEBUG(0, ("smbd_vfs_init: vfs_init_custom failed for %s\n", vfs_objects[j]));
281                         return False;
282                 }
283         }
284         return True;
285 }
286
287 /*******************************************************************
288  Check if directory exists.
289 ********************************************************************/
290
291 BOOL vfs_directory_exist(connection_struct *conn, const char *dname, SMB_STRUCT_STAT *st)
292 {
293         SMB_STRUCT_STAT st2;
294         BOOL ret;
295
296         if (!st)
297                 st = &st2;
298
299         if (SMB_VFS_STAT(conn,dname,st) != 0)
300                 return(False);
301
302         ret = S_ISDIR(st->st_mode);
303         if(!ret)
304                 errno = ENOTDIR;
305
306         return ret;
307 }
308
309 /*******************************************************************
310  Check if an object exists in the vfs.
311 ********************************************************************/
312
313 BOOL vfs_object_exist(connection_struct *conn,const char *fname,SMB_STRUCT_STAT *sbuf)
314 {
315         SMB_STRUCT_STAT st;
316
317         if (!sbuf)
318                 sbuf = &st;
319
320         ZERO_STRUCTP(sbuf);
321
322         if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
323                 return(False);
324         return True;
325 }
326
327 /*******************************************************************
328  Check if a file exists in the vfs.
329 ********************************************************************/
330
331 BOOL vfs_file_exist(connection_struct *conn, const char *fname,SMB_STRUCT_STAT *sbuf)
332 {
333         SMB_STRUCT_STAT st;
334
335         if (!sbuf)
336                 sbuf = &st;
337
338         ZERO_STRUCTP(sbuf);
339
340         if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
341                 return False;
342         return(S_ISREG(sbuf->st_mode));
343 }
344
345 /****************************************************************************
346  Read data from fsp on the vfs. (note: EINTR re-read differs from vfs_write_data)
347 ****************************************************************************/
348
349 ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count)
350 {
351         size_t total=0;
352
353         while (total < byte_count)
354         {
355                 ssize_t ret = SMB_VFS_READ(fsp, fsp->fh->fd, buf + total,
356                                         byte_count - total);
357
358                 if (ret == 0) return total;
359                 if (ret == -1) {
360                         if (errno == EINTR)
361                                 continue;
362                         else
363                                 return -1;
364                 }
365                 total += ret;
366         }
367         return (ssize_t)total;
368 }
369
370 ssize_t vfs_pread_data(files_struct *fsp, char *buf,
371                 size_t byte_count, SMB_OFF_T offset)
372 {
373         size_t total=0;
374
375         while (total < byte_count)
376         {
377                 ssize_t ret = SMB_VFS_PREAD(fsp, fsp->fh->fd, buf + total,
378                                         byte_count - total, offset + total);
379
380                 if (ret == 0) return total;
381                 if (ret == -1) {
382                         if (errno == EINTR)
383                                 continue;
384                         else
385                                 return -1;
386                 }
387                 total += ret;
388         }
389         return (ssize_t)total;
390 }
391
392 /****************************************************************************
393  Write data to a fd on the vfs.
394 ****************************************************************************/
395
396 ssize_t vfs_write_data(files_struct *fsp,const char *buffer,size_t N)
397 {
398         size_t total=0;
399         ssize_t ret;
400
401         while (total < N) {
402                 ret = SMB_VFS_WRITE(fsp,fsp->fh->fd,buffer + total,N - total);
403
404                 if (ret == -1)
405                         return -1;
406                 if (ret == 0)
407                         return total;
408
409                 total += ret;
410         }
411         return (ssize_t)total;
412 }
413
414 ssize_t vfs_pwrite_data(files_struct *fsp,const char *buffer,
415                 size_t N, SMB_OFF_T offset)
416 {
417         size_t total=0;
418         ssize_t ret;
419
420         while (total < N) {
421                 ret = SMB_VFS_PWRITE(fsp, fsp->fh->fd, buffer + total,
422                                 N - total, offset + total);
423
424                 if (ret == -1)
425                         return -1;
426                 if (ret == 0)
427                         return total;
428
429                 total += ret;
430         }
431         return (ssize_t)total;
432 }
433 /****************************************************************************
434  An allocate file space call using the vfs interface.
435  Allocates space for a file from a filedescriptor.
436  Returns 0 on success, -1 on failure.
437 ****************************************************************************/
438
439 int vfs_allocate_file_space(files_struct *fsp, SMB_BIG_UINT len)
440 {
441         int ret;
442         SMB_STRUCT_STAT st;
443         connection_struct *conn = fsp->conn;
444         SMB_BIG_UINT space_avail;
445         SMB_BIG_UINT bsize,dfree,dsize;
446
447         release_level_2_oplocks_on_change(fsp);
448
449         /*
450          * Actually try and commit the space on disk....
451          */
452
453         DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", fsp->fsp_name, (double)len ));
454
455         if (((SMB_OFF_T)len) < 0) {
456                 DEBUG(0,("vfs_allocate_file_space: %s negative len requested.\n", fsp->fsp_name ));
457                 errno = EINVAL;
458                 return -1;
459         }
460
461         ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st);
462         if (ret == -1)
463                 return ret;
464
465         if (len == (SMB_BIG_UINT)st.st_size)
466                 return 0;
467
468         if (len < (SMB_BIG_UINT)st.st_size) {
469                 /* Shrink - use ftruncate. */
470
471                 DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
472                                 fsp->fsp_name, (double)st.st_size ));
473
474                 flush_write_cache(fsp, SIZECHANGE_FLUSH);
475                 if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, (SMB_OFF_T)len)) != -1) {
476                         set_filelen_write_cache(fsp, len);
477                 }
478                 return ret;
479         }
480
481         /* Grow - we need to test if we have enough space. */
482
483         if (!lp_strict_allocate(SNUM(fsp->conn)))
484                 return 0;
485
486         len -= st.st_size;
487         len /= 1024; /* Len is now number of 1k blocks needed. */
488         space_avail = get_dfree_info(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize);
489         if (space_avail == (SMB_BIG_UINT)-1) {
490                 return -1;
491         }
492
493         DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %.0f, space avail = %.0f\n",
494                         fsp->fsp_name, (double)st.st_size, (double)len, (double)space_avail ));
495
496         if (len > space_avail) {
497                 errno = ENOSPC;
498                 return -1;
499         }
500
501         return 0;
502 }
503
504 /****************************************************************************
505  A vfs set_filelen call.
506  set the length of a file from a filedescriptor.
507  Returns 0 on success, -1 on failure.
508 ****************************************************************************/
509
510 int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
511 {
512         int ret;
513
514         release_level_2_oplocks_on_change(fsp);
515         DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len));
516         flush_write_cache(fsp, SIZECHANGE_FLUSH);
517         if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, len)) != -1)
518                 set_filelen_write_cache(fsp, len);
519
520         return ret;
521 }
522
523 /****************************************************************************
524  A vfs fill sparse call.
525  Writes zeros from the end of file to len, if len is greater than EOF.
526  Used only by strict_sync.
527  Returns 0 on success, -1 on failure.
528 ****************************************************************************/
529
530 static char *sparse_buf;
531 #define SPARSE_BUF_WRITE_SIZE (32*1024)
532
533 int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len)
534 {
535         int ret;
536         SMB_STRUCT_STAT st;
537         SMB_OFF_T offset;
538         size_t total;
539         size_t num_to_write;
540         ssize_t pwrite_ret;
541
542         release_level_2_oplocks_on_change(fsp);
543         ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st);
544         if (ret == -1) {
545                 return ret;
546         }
547
548         if (len <= st.st_size) {
549                 return 0;
550         }
551
552         DEBUG(10,("vfs_fill_sparse: write zeros in file %s from len %.0f to len %.0f (%.0f bytes)\n",
553                 fsp->fsp_name, (double)st.st_size, (double)len, (double)(len - st.st_size)));
554
555         flush_write_cache(fsp, SIZECHANGE_FLUSH);
556
557         if (!sparse_buf) {
558                 sparse_buf = SMB_CALLOC_ARRAY(char, SPARSE_BUF_WRITE_SIZE);
559                 if (!sparse_buf) {
560                         errno = ENOMEM;
561                         return -1;
562                 }
563         }
564
565         offset = st.st_size;
566         num_to_write = len - st.st_size;
567         total = 0;
568
569         while (total < num_to_write) {
570                 size_t curr_write_size = MIN(SPARSE_BUF_WRITE_SIZE, (num_to_write - total));
571
572                 pwrite_ret = SMB_VFS_PWRITE(fsp, fsp->fh->fd, sparse_buf, curr_write_size, offset + total);
573                 if (pwrite_ret == -1) {
574                         DEBUG(10,("vfs_fill_sparse: SMB_VFS_PWRITE for file %s failed with error %s\n",
575                                 fsp->fsp_name, strerror(errno) ));
576                         return -1;
577                 }
578                 if (pwrite_ret == 0) {
579                         return 0;
580                 }
581
582                 total += pwrite_ret;
583         }
584
585         set_filelen_write_cache(fsp, len);
586         return 0;
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->fh->fd, out_fsp->fh->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, (DIR *)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_NAME
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 /*******************************************************************
796  Reduce a file name, removing .. elements and checking that
797  it is below dir in the heirachy. This uses realpath.
798 ********************************************************************/
799
800 NTSTATUS reduce_name(connection_struct *conn, const pstring fname)
801 {
802 #ifdef REALPATH_TAKES_NULL
803         BOOL free_resolved_name = True;
804 #else
805 #ifdef PATH_MAX
806         char resolved_name_buf[PATH_MAX+1];
807 #else
808         pstring resolved_name_buf;
809 #endif
810         BOOL free_resolved_name = False;
811 #endif
812         char *resolved_name = NULL;
813         size_t con_path_len = strlen(conn->connectpath);
814         char *p = NULL;
815
816         DEBUG(3,("reduce_name [%s] [%s]\n", fname, conn->connectpath));
817
818 #ifdef REALPATH_TAKES_NULL
819         resolved_name = SMB_VFS_REALPATH(conn,fname,NULL);
820 #else
821         resolved_name = SMB_VFS_REALPATH(conn,fname,resolved_name_buf);
822 #endif
823
824         if (!resolved_name) {
825                 switch (errno) {
826                         case ENOTDIR:
827                                 DEBUG(3,("reduce_name: Component not a directory in getting realpath for %s\n", fname));
828                                 return map_nt_error_from_unix(errno);
829                         case ENOENT:
830                         {
831                                 pstring tmp_fname;
832                                 fstring last_component;
833                                 /* Last component didn't exist. Remove it and try and canonicalise the directory. */
834
835                                 pstrcpy(tmp_fname, fname);
836                                 p = strrchr_m(tmp_fname, '/');
837                                 if (p) {
838                                         *p++ = '\0';
839                                         fstrcpy(last_component, p);
840                                 } else {
841                                         fstrcpy(last_component, tmp_fname);
842                                         pstrcpy(tmp_fname, ".");
843                                 }
844
845 #ifdef REALPATH_TAKES_NULL
846                                 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,NULL);
847 #else
848                                 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,resolved_name_buf);
849 #endif
850                                 if (!resolved_name) {
851                                         DEBUG(3,("reduce_name: couldn't get realpath for %s\n", fname));
852                                         return map_nt_error_from_unix(errno);
853                                 }
854                                 pstrcpy(tmp_fname, resolved_name);
855                                 pstrcat(tmp_fname, "/");
856                                 pstrcat(tmp_fname, last_component);
857 #ifdef REALPATH_TAKES_NULL
858                                 SAFE_FREE(resolved_name);
859                                 resolved_name = SMB_STRDUP(tmp_fname);
860                                 if (!resolved_name) {
861                                         DEBUG(0,("reduce_name: malloc fail for %s\n", tmp_fname));
862                                         return NT_STATUS_NO_MEMORY;
863                                 }
864 #else
865 #ifdef PATH_MAX
866                                 safe_strcpy(resolved_name_buf, tmp_fname, PATH_MAX);
867 #else
868                                 pstrcpy(resolved_name_buf, tmp_fname);
869 #endif
870                                 resolved_name = resolved_name_buf;
871 #endif
872                                 break;
873                         }
874                         default:
875                                 DEBUG(1,("reduce_name: couldn't get realpath for %s\n", fname));
876                                 return map_nt_error_from_unix(errno);
877                 }
878         }
879
880         DEBUG(10,("reduce_name realpath [%s] -> [%s]\n", fname, resolved_name));
881
882         if (*resolved_name != '/') {
883                 DEBUG(0,("reduce_name: realpath doesn't return absolute paths !\n"));
884                 if (free_resolved_name) {
885                         SAFE_FREE(resolved_name);
886                 }
887                 return NT_STATUS_OBJECT_NAME_INVALID;
888         }
889
890         /* Check for widelinks allowed. */
891         if (!lp_widelinks(SNUM(conn)) && (strncmp(conn->connectpath, resolved_name, con_path_len) != 0)) {
892                 DEBUG(2, ("reduce_name: Bad access attempt: %s is a symlink outside the share path", fname));
893                 if (free_resolved_name) {
894                         SAFE_FREE(resolved_name);
895                 }
896                 return NT_STATUS_ACCESS_DENIED;
897         }
898
899         /* Check if we are allowing users to follow symlinks */
900         /* Patch from David Clerc <David.Clerc@cui.unige.ch>
901                 University of Geneva */
902                                                                                                                                                     
903 #ifdef S_ISLNK
904         if (!lp_symlinks(SNUM(conn))) {
905                 SMB_STRUCT_STAT statbuf;
906                 if ( (SMB_VFS_LSTAT(conn,fname,&statbuf) != -1) &&
907                                 (S_ISLNK(statbuf.st_mode)) ) {
908                         if (free_resolved_name) {
909                                 SAFE_FREE(resolved_name);
910                         }
911                         DEBUG(3,("reduce_name: denied: file path name %s is a symlink\n",resolved_name));
912                         return NT_STATUS_ACCESS_DENIED;
913                 }
914         }
915 #endif
916
917         DEBUG(3,("reduce_name: %s reduced to %s\n", fname, resolved_name));
918         if (free_resolved_name) {
919                 SAFE_FREE(resolved_name);
920         }
921         return NT_STATUS_OK;
922 }