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