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