r20844: Somewhat radical change - this may break the build (I will
[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                 return -1;
458         }
459
460         ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st);
461         if (ret == -1)
462                 return ret;
463
464         if (len == (SMB_BIG_UINT)st.st_size)
465                 return 0;
466
467         if (len < (SMB_BIG_UINT)st.st_size) {
468                 /* Shrink - use ftruncate. */
469
470                 DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
471                                 fsp->fsp_name, (double)st.st_size ));
472
473                 flush_write_cache(fsp, SIZECHANGE_FLUSH);
474                 if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, (SMB_OFF_T)len)) != -1) {
475                         set_filelen_write_cache(fsp, len);
476                 }
477                 return ret;
478         }
479
480         /* Grow - we need to test if we have enough space. */
481
482         if (!lp_strict_allocate(SNUM(fsp->conn)))
483                 return 0;
484
485         len -= st.st_size;
486         len /= 1024; /* Len is now number of 1k blocks needed. */
487         space_avail = get_dfree_info(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize);
488         if (space_avail == (SMB_BIG_UINT)-1) {
489                 return -1;
490         }
491
492         DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %.0f, space avail = %.0f\n",
493                         fsp->fsp_name, (double)st.st_size, (double)len, (double)space_avail ));
494
495         if (len > space_avail) {
496                 errno = ENOSPC;
497                 return -1;
498         }
499
500         return 0;
501 }
502
503 /****************************************************************************
504  A vfs set_filelen call.
505  set the length of a file from a filedescriptor.
506  Returns 0 on success, -1 on failure.
507 ****************************************************************************/
508
509 int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
510 {
511         int ret;
512
513         release_level_2_oplocks_on_change(fsp);
514         DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len));
515         flush_write_cache(fsp, SIZECHANGE_FLUSH);
516         if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, len)) != -1)
517                 set_filelen_write_cache(fsp, len);
518
519         return ret;
520 }
521
522 /****************************************************************************
523  A vfs fill sparse call.
524  Writes zeros from the end of file to len, if len is greater than EOF.
525  Used only by strict_sync.
526  Returns 0 on success, -1 on failure.
527 ****************************************************************************/
528
529 static char *sparse_buf;
530 #define SPARSE_BUF_WRITE_SIZE (32*1024)
531
532 int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len)
533 {
534         int ret;
535         SMB_STRUCT_STAT st;
536         SMB_OFF_T offset;
537         size_t total;
538         size_t num_to_write;
539         ssize_t pwrite_ret;
540
541         release_level_2_oplocks_on_change(fsp);
542         ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st);
543         if (ret == -1) {
544                 return ret;
545         }
546
547         if (len <= st.st_size) {
548                 return 0;
549         }
550
551         DEBUG(10,("vfs_fill_sparse: write zeros in file %s from len %.0f to len %.0f (%.0f bytes)\n",
552                 fsp->fsp_name, (double)st.st_size, (double)len, (double)(len - st.st_size)));
553
554         flush_write_cache(fsp, SIZECHANGE_FLUSH);
555
556         if (!sparse_buf) {
557                 sparse_buf = SMB_CALLOC_ARRAY(char, SPARSE_BUF_WRITE_SIZE);
558                 if (!sparse_buf) {
559                         errno = ENOMEM;
560                         return -1;
561                 }
562         }
563
564         offset = st.st_size;
565         num_to_write = len - st.st_size;
566         total = 0;
567
568         while (total < num_to_write) {
569                 size_t curr_write_size = MIN(SPARSE_BUF_WRITE_SIZE, (num_to_write - total));
570
571                 pwrite_ret = SMB_VFS_PWRITE(fsp, fsp->fh->fd, sparse_buf, curr_write_size, offset + total);
572                 if (pwrite_ret == -1) {
573                         DEBUG(10,("vfs_fill_sparse: SMB_VFS_PWRITE for file %s failed with error %s\n",
574                                 fsp->fsp_name, strerror(errno) ));
575                         return -1;
576                 }
577                 if (pwrite_ret == 0) {
578                         return 0;
579                 }
580
581                 total += pwrite_ret;
582         }
583
584         set_filelen_write_cache(fsp, len);
585         return 0;
586 }
587
588 /****************************************************************************
589  Transfer some data (n bytes) between two file_struct's.
590 ****************************************************************************/
591
592 static files_struct *in_fsp;
593 static files_struct *out_fsp;
594
595 static ssize_t read_fn(int fd, void *buf, size_t len)
596 {
597         return SMB_VFS_READ(in_fsp, fd, buf, len);
598 }
599
600 static ssize_t write_fn(int fd, const void *buf, size_t len)
601 {
602         return SMB_VFS_WRITE(out_fsp, fd, buf, len);
603 }
604
605 SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n)
606 {
607         in_fsp = in;
608         out_fsp = out;
609
610         return transfer_file_internal(in_fsp->fh->fd, out_fsp->fh->fd, n, read_fn, write_fn);
611 }
612
613 /*******************************************************************
614  A vfs_readdir wrapper which just returns the file name.
615 ********************************************************************/
616
617 char *vfs_readdirname(connection_struct *conn, void *p)
618 {
619         SMB_STRUCT_DIRENT *ptr= NULL;
620         char *dname;
621
622         if (!p)
623                 return(NULL);
624
625         ptr = SMB_VFS_READDIR(conn, (DIR *)p);
626         if (!ptr)
627                 return(NULL);
628
629         dname = ptr->d_name;
630
631 #ifdef NEXT2
632         if (telldir(p) < 0)
633                 return(NULL);
634 #endif
635
636 #ifdef HAVE_BROKEN_READDIR_NAME
637         /* using /usr/ucb/cc is BAD */
638         dname = dname - 2;
639 #endif
640
641         return(dname);
642 }
643
644 /*******************************************************************
645  A wrapper for vfs_chdir().
646 ********************************************************************/
647
648 int vfs_ChDir(connection_struct *conn, const char *path)
649 {
650         int res;
651         static pstring LastDir="";
652
653         if (strcsequal(path,"."))
654                 return(0);
655
656         if (*path == '/' && strcsequal(LastDir,path))
657                 return(0);
658
659         DEBUG(4,("vfs_ChDir to %s\n",path));
660
661         res = SMB_VFS_CHDIR(conn,path);
662         if (!res)
663                 pstrcpy(LastDir,path);
664         return(res);
665 }
666
667 /* number of list structures for a caching GetWd function. */
668 #define MAX_GETWDCACHE (50)
669
670 static struct {
671         SMB_DEV_T dev; /* These *must* be compatible with the types returned in a stat() call. */
672         SMB_INO_T inode; /* These *must* be compatible with the types returned in a stat() call. */
673         char *dos_path; /* The pathname in DOS format. */
674         BOOL valid;
675 } ino_list[MAX_GETWDCACHE];
676
677 extern BOOL use_getwd_cache;
678
679 /****************************************************************************
680  Prompte a ptr (to make it recently used)
681 ****************************************************************************/
682
683 static void array_promote(char *array,int elsize,int element)
684 {
685         char *p;
686         if (element == 0)
687                 return;
688
689         p = (char *)SMB_MALLOC(elsize);
690
691         if (!p) {
692                 DEBUG(5,("array_promote: malloc fail\n"));
693                 return;
694         }
695
696         memcpy(p,array + element * elsize, elsize);
697         memmove(array + elsize,array,elsize*element);
698         memcpy(array,p,elsize);
699         SAFE_FREE(p);
700 }
701
702 /*******************************************************************
703  Return the absolute current directory path - given a UNIX pathname.
704  Note that this path is returned in DOS format, not UNIX
705  format. Note this can be called with conn == NULL.
706 ********************************************************************/
707
708 char *vfs_GetWd(connection_struct *conn, char *path)
709 {
710         pstring s;
711         static BOOL getwd_cache_init = False;
712         SMB_STRUCT_STAT st, st2;
713         int i;
714
715         *s = 0;
716
717         if (!use_getwd_cache)
718                 return(SMB_VFS_GETWD(conn,path));
719
720         /* init the cache */
721         if (!getwd_cache_init) {
722                 getwd_cache_init = True;
723                 for (i=0;i<MAX_GETWDCACHE;i++) {
724                         string_set(&ino_list[i].dos_path,"");
725                         ino_list[i].valid = False;
726                 }
727         }
728
729         /*  Get the inode of the current directory, if this doesn't work we're
730                 in trouble :-) */
731
732         if (SMB_VFS_STAT(conn, ".",&st) == -1) {
733                 /* Known to fail for root: the directory may be
734                  * NFS-mounted and exported with root_squash (so has no root access). */
735                 DEBUG(1,("vfs_GetWd: couldn't stat \".\" path=%s error %s (NFS problem ?)\n", path, strerror(errno) ));
736                 return(SMB_VFS_GETWD(conn,path));
737         }
738
739
740         for (i=0; i<MAX_GETWDCACHE; i++) {
741                 if (ino_list[i].valid) {
742
743                         /*  If we have found an entry with a matching inode and dev number
744                                 then find the inode number for the directory in the cached string.
745                                 If this agrees with that returned by the stat for the current
746                                 directory then all is o.k. (but make sure it is a directory all
747                                 the same...) */
748
749                         if (st.st_ino == ino_list[i].inode && st.st_dev == ino_list[i].dev) {
750                                 if (SMB_VFS_STAT(conn,ino_list[i].dos_path,&st2) == 0) {
751                                         if (st.st_ino == st2.st_ino && st.st_dev == st2.st_dev &&
752                                                         (st2.st_mode & S_IFMT) == S_IFDIR) {
753                                                 pstrcpy (path, ino_list[i].dos_path);
754
755                                                 /* promote it for future use */
756                                                 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
757                                                 return (path);
758                                         } else {
759                                                 /*  If the inode is different then something's changed,
760                                                         scrub the entry and start from scratch. */
761                                                 ino_list[i].valid = False;
762                                         }
763                                 }
764                         }
765                 }
766         }
767
768         /*  We don't have the information to hand so rely on traditional methods.
769                 The very slow getcwd, which spawns a process on some systems, or the
770                 not quite so bad getwd. */
771
772         if (!SMB_VFS_GETWD(conn,s)) {
773                 DEBUG(0,("vfs_GetWd: SMB_VFS_GETWD call failed, errno %s\n",strerror(errno)));
774                 return (NULL);
775         }
776
777         pstrcpy(path,s);
778
779         DEBUG(5,("vfs_GetWd %s, inode %.0f, dev %.0f\n",s,(double)st.st_ino,(double)st.st_dev));
780
781         /* add it to the cache */
782         i = MAX_GETWDCACHE - 1;
783         string_set(&ino_list[i].dos_path,s);
784         ino_list[i].dev = st.st_dev;
785         ino_list[i].inode = st.st_ino;
786         ino_list[i].valid = True;
787
788         /* put it at the top of the list */
789         array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
790
791         return (path);
792 }
793
794 BOOL canonicalize_path(connection_struct *conn, pstring path)
795 {
796 #ifdef REALPATH_TAKES_NULL
797         char *resolved_name = SMB_VFS_REALPATH(conn,path,NULL);
798         if (!resolved_name) {
799                 return False;
800         }
801         pstrcpy(path, resolved_name);
802         SAFE_FREE(resolved_name);
803         return 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         char *resolved_name = SMB_VFS_REALPATH(conn,path,resolved_name_buf);
811         if (!resolved_name) {
812                 return False;
813         }
814         pstrcpy(path, resolved_name);
815         return True;
816 #endif /* REALPATH_TAKES_NULL */
817 }
818
819 /*******************************************************************
820  Reduce a file name, removing .. elements and checking that
821  it is below dir in the heirachy. This uses realpath.
822 ********************************************************************/
823
824 NTSTATUS reduce_name(connection_struct *conn, const pstring fname)
825 {
826 #ifdef REALPATH_TAKES_NULL
827         BOOL free_resolved_name = True;
828 #else
829 #ifdef PATH_MAX
830         char resolved_name_buf[PATH_MAX+1];
831 #else
832         pstring resolved_name_buf;
833 #endif
834         BOOL free_resolved_name = False;
835 #endif
836         char *resolved_name = NULL;
837         size_t con_path_len = strlen(conn->connectpath);
838         char *p = NULL;
839
840         DEBUG(3,("reduce_name [%s] [%s]\n", fname, conn->connectpath));
841
842 #ifdef REALPATH_TAKES_NULL
843         resolved_name = SMB_VFS_REALPATH(conn,fname,NULL);
844 #else
845         resolved_name = SMB_VFS_REALPATH(conn,fname,resolved_name_buf);
846 #endif
847
848         if (!resolved_name) {
849                 switch (errno) {
850                         case ENOTDIR:
851                                 DEBUG(3,("reduce_name: Component not a directory in getting realpath for %s\n", fname));
852                                 return map_nt_error_from_unix(errno);
853                         case ENOENT:
854                         {
855                                 pstring tmp_fname;
856                                 fstring last_component;
857                                 /* Last component didn't exist. Remove it and try and canonicalise the directory. */
858
859                                 pstrcpy(tmp_fname, fname);
860                                 p = strrchr_m(tmp_fname, '/');
861                                 if (p) {
862                                         *p++ = '\0';
863                                         fstrcpy(last_component, p);
864                                 } else {
865                                         fstrcpy(last_component, tmp_fname);
866                                         pstrcpy(tmp_fname, ".");
867                                 }
868
869 #ifdef REALPATH_TAKES_NULL
870                                 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,NULL);
871 #else
872                                 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,resolved_name_buf);
873 #endif
874                                 if (!resolved_name) {
875                                         DEBUG(3,("reduce_name: couldn't get realpath for %s\n", fname));
876                                         return map_nt_error_from_unix(errno);
877                                 }
878                                 pstrcpy(tmp_fname, resolved_name);
879                                 pstrcat(tmp_fname, "/");
880                                 pstrcat(tmp_fname, last_component);
881 #ifdef REALPATH_TAKES_NULL
882                                 SAFE_FREE(resolved_name);
883                                 resolved_name = SMB_STRDUP(tmp_fname);
884                                 if (!resolved_name) {
885                                         DEBUG(0,("reduce_name: malloc fail for %s\n", tmp_fname));
886                                         return NT_STATUS_NO_MEMORY;
887                                 }
888 #else
889 #ifdef PATH_MAX
890                                 safe_strcpy(resolved_name_buf, tmp_fname, PATH_MAX);
891 #else
892                                 pstrcpy(resolved_name_buf, tmp_fname);
893 #endif
894                                 resolved_name = resolved_name_buf;
895 #endif
896                                 break;
897                         }
898                         default:
899                                 DEBUG(1,("reduce_name: couldn't get realpath for %s\n", fname));
900                                 return map_nt_error_from_unix(errno);
901                 }
902         }
903
904         DEBUG(10,("reduce_name realpath [%s] -> [%s]\n", fname, resolved_name));
905
906         if (*resolved_name != '/') {
907                 DEBUG(0,("reduce_name: realpath doesn't return absolute paths !\n"));
908                 if (free_resolved_name) {
909                         SAFE_FREE(resolved_name);
910                 }
911                 return NT_STATUS_OBJECT_NAME_INVALID;
912         }
913
914         /* Check for widelinks allowed. */
915         if (!lp_widelinks(SNUM(conn)) && (strncmp(conn->connectpath, resolved_name, con_path_len) != 0)) {
916                 DEBUG(2, ("reduce_name: Bad access attempt: %s is a symlink outside the share path", fname));
917                 if (free_resolved_name) {
918                         SAFE_FREE(resolved_name);
919                 }
920                 return NT_STATUS_ACCESS_DENIED;
921         }
922
923         /* Check if we are allowing users to follow symlinks */
924         /* Patch from David Clerc <David.Clerc@cui.unige.ch>
925                 University of Geneva */
926                                                                                                                                                     
927 #ifdef S_ISLNK
928         if (!lp_symlinks(SNUM(conn))) {
929                 SMB_STRUCT_STAT statbuf;
930                 if ( (SMB_VFS_LSTAT(conn,fname,&statbuf) != -1) &&
931                                 (S_ISLNK(statbuf.st_mode)) ) {
932                         if (free_resolved_name) {
933                                 SAFE_FREE(resolved_name);
934                         }
935                         DEBUG(3,("reduce_name: denied: file path name %s is a symlink\n",resolved_name));
936                         return NT_STATUS_ACCESS_DENIED;
937                 }
938         }
939 #endif
940
941         DEBUG(3,("reduce_name: %s reduced to %s\n", fname, resolved_name));
942         if (free_resolved_name) {
943                 SAFE_FREE(resolved_name);
944         }
945         return NT_STATUS_OK;
946 }