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