Enable vfs objects = /full/path/to/object.so
[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 3 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, see <http://www.gnu.org/licenses/>.
21
22    This work was sponsored by Optifacio Software Services, Inc.
23 */
24
25 #include "includes.h"
26
27 #undef DBGC_CLASS
28 #define DBGC_CLASS DBGC_VFS
29
30 static_decl_vfs;
31
32 struct vfs_init_function_entry {
33         char *name;
34         vfs_op_tuple *vfs_op_tuples;
35         struct vfs_init_function_entry *prev, *next;
36 };
37
38 static struct vfs_init_function_entry *backends = NULL;
39
40 /****************************************************************************
41     maintain the list of available backends
42 ****************************************************************************/
43
44 static struct vfs_init_function_entry *vfs_find_backend_entry(const char *name)
45 {
46         struct vfs_init_function_entry *entry = backends;
47
48         DEBUG(10, ("vfs_find_backend_entry called for %s\n", name));
49  
50         while(entry) {
51                 if (strcmp(entry->name, name)==0) return entry;
52                 entry = entry->next;
53         }
54
55         return NULL;
56 }
57
58 NTSTATUS smb_register_vfs(int version, const char *name, vfs_op_tuple *vfs_op_tuples)
59 {
60         struct vfs_init_function_entry *entry = backends;
61
62         if ((version != SMB_VFS_INTERFACE_VERSION)) {
63                 DEBUG(0, ("Failed to register vfs module.\n"
64                           "The module was compiled against SMB_VFS_INTERFACE_VERSION %d,\n"
65                           "current SMB_VFS_INTERFACE_VERSION is %d.\n"
66                           "Please recompile against the current Samba Version!\n",  
67                           version, SMB_VFS_INTERFACE_VERSION));
68                 return NT_STATUS_OBJECT_TYPE_MISMATCH;
69         }
70
71         if (!name || !name[0] || !vfs_op_tuples) {
72                 DEBUG(0,("smb_register_vfs() called with NULL pointer or empty name!\n"));
73                 return NT_STATUS_INVALID_PARAMETER;
74         }
75
76         if (vfs_find_backend_entry(name)) {
77                 DEBUG(0,("VFS module %s already loaded!\n", name));
78                 return NT_STATUS_OBJECT_NAME_COLLISION;
79         }
80
81         entry = SMB_XMALLOC_P(struct vfs_init_function_entry);
82         entry->name = smb_xstrdup(name);
83         entry->vfs_op_tuples = vfs_op_tuples;
84
85         DLIST_ADD(backends, entry);
86         DEBUG(5, ("Successfully added vfs backend '%s'\n", name));
87         return NT_STATUS_OK;
88 }
89
90 /****************************************************************************
91   initialise default vfs hooks
92 ****************************************************************************/
93
94 static void vfs_init_default(connection_struct *conn)
95 {
96         DEBUG(3, ("Initialising default vfs hooks\n"));
97         vfs_init_custom(conn, DEFAULT_VFS_MODULE_NAME);
98 }
99
100 /****************************************************************************
101   initialise custom vfs hooks
102  ****************************************************************************/
103
104 static inline void vfs_set_operation(struct vfs_ops * vfs, vfs_op_type which,
105                                 struct vfs_handle_struct * handle, void * op)
106 {
107         ((struct vfs_handle_struct **)&vfs->handles)[which] = handle;
108         ((void **)(void *)&vfs->ops)[which] = op;
109 }
110
111 bool vfs_init_custom(connection_struct *conn, const char *vfs_object)
112 {
113         vfs_op_tuple *ops;
114         char *module_path = NULL;
115         char *module_name = NULL;
116         char *module_param = NULL, *p;
117         int i;
118         vfs_handle_struct *handle;
119         struct vfs_init_function_entry *entry;
120         
121         if (!conn||!vfs_object||!vfs_object[0]) {
122                 DEBUG(0,("vfs_init_custon() called with NULL pointer or emtpy vfs_object!\n"));
123                 return False;
124         }
125
126         if(!backends) {
127                 static_init_vfs;
128         }
129
130         DEBUG(3, ("Initialising custom vfs hooks from [%s]\n", vfs_object));
131
132         module_path = smb_xstrdup(vfs_object);
133
134         p = strchr_m(module_path, ':');
135
136         if (p) {
137                 *p = 0;
138                 module_param = p+1;
139                 trim_char(module_param, ' ', ' ');
140         }
141
142         trim_char(module_path, ' ', ' ');
143
144         module_name = smb_xstrdup(module_path);
145
146         if ((module_name[0] == '/') &&
147             (strcmp(module_path, DEFAULT_VFS_MODULE_NAME) != 0)) {
148
149                 /*
150                  * Extract the module name from the path. Just use the base
151                  * name of the last path component.
152                  */
153
154                 SAFE_FREE(module_name);
155                 module_name = smb_xstrdup(strrchr_m(module_path, '/')+1);
156
157                 p = strchr_m(module_name, '.');
158
159                 if (p != NULL) {
160                         *p = '\0';
161                 }
162         }
163
164         /* First, try to load the module with the new module system */
165         if((entry = vfs_find_backend_entry(module_name)) || 
166            (NT_STATUS_IS_OK(smb_probe_module("vfs", module_path)) &&
167                 (entry = vfs_find_backend_entry(module_name)))) {
168
169                 DEBUGADD(5,("Successfully loaded vfs module [%s] with the new modules system\n", vfs_object));
170                 
171                 if ((ops = entry->vfs_op_tuples) == NULL) {
172                         DEBUG(0, ("entry->vfs_op_tuples==NULL for [%s] failed\n", vfs_object));
173                         goto fail;
174                 }
175         } else {
176                 DEBUG(0,("Can't find a vfs module [%s]\n",vfs_object));
177                 goto fail;
178         }
179
180         handle = TALLOC_ZERO_P(conn->mem_ctx,vfs_handle_struct);
181         if (!handle) {
182                 DEBUG(0,("TALLOC_ZERO() failed!\n"));
183                 goto fail;
184         }
185         memcpy(&handle->vfs_next, &conn->vfs, sizeof(struct vfs_ops));
186         handle->conn = conn;
187         if (module_param) {
188                 handle->param = talloc_strdup(conn->mem_ctx, module_param);
189         }
190         DLIST_ADD(conn->vfs_handles, handle);
191
192         for(i=0; ops[i].op != NULL; i++) {
193                 DEBUG(5, ("Checking operation #%d (type %d, layer %d)\n", i, ops[i].type, ops[i].layer));
194                 if(ops[i].layer == SMB_VFS_LAYER_OPAQUE) {
195                         /* If this operation was already made opaque by different module, it
196                          * will be overridden here.
197                          */
198                         DEBUGADD(5, ("Making operation type %d opaque [module %s]\n", ops[i].type, vfs_object));
199                         vfs_set_operation(&conn->vfs_opaque, ops[i].type, handle, ops[i].op);
200                 }
201                 /* Change current VFS disposition*/
202                 DEBUGADD(5, ("Accepting operation type %d from module %s\n", ops[i].type, vfs_object));
203                 vfs_set_operation(&conn->vfs, ops[i].type, handle, ops[i].op);
204         }
205
206         SAFE_FREE(module_path);
207         SAFE_FREE(module_name);
208         return True;
209
210  fail:
211         SAFE_FREE(module_path);
212         SAFE_FREE(module_name);
213         return False;
214 }
215
216 /*****************************************************************
217  Allow VFS modules to extend files_struct with VFS-specific state.
218  This will be ok for small numbers of extensions, but might need to
219  be refactored if it becomes more widely used.
220 ******************************************************************/
221
222 #define EXT_DATA_AREA(e) ((uint8 *)(e) + sizeof(struct vfs_fsp_data))
223
224 void *vfs_add_fsp_extension_notype(vfs_handle_struct *handle, files_struct *fsp, size_t ext_size)
225 {
226         struct vfs_fsp_data *ext;
227         void * ext_data;
228
229         /* Prevent VFS modules adding multiple extensions. */
230         if ((ext_data = vfs_fetch_fsp_extension(handle, fsp))) {
231                 return ext_data;
232         }
233
234         ext = (struct vfs_fsp_data *)TALLOC_ZERO(
235                 handle->conn->mem_ctx, sizeof(struct vfs_fsp_data) + ext_size);
236         if (ext == NULL) {
237                 return NULL;
238         }
239
240         ext->owner = handle;
241         ext->next = fsp->vfs_extension;
242         fsp->vfs_extension = ext;
243         return EXT_DATA_AREA(ext);
244 }
245
246 void vfs_remove_fsp_extension(vfs_handle_struct *handle, files_struct *fsp)
247 {
248         struct vfs_fsp_data *curr;
249         struct vfs_fsp_data *prev;
250
251         for (curr = fsp->vfs_extension, prev = NULL;
252              curr;
253              prev = curr, curr = curr->next) {
254                 if (curr->owner == handle) {
255                     if (prev) {
256                             prev->next = curr->next;
257                     } else {
258                             fsp->vfs_extension = curr->next;
259                     }
260                     TALLOC_FREE(curr);
261                     return;
262                 }
263         }
264 }
265
266 void *vfs_fetch_fsp_extension(vfs_handle_struct *handle, files_struct *fsp)
267 {
268         struct vfs_fsp_data *head;
269
270         for (head = fsp->vfs_extension; head; head = head->next) {
271                 if (head->owner == handle) {
272                         return EXT_DATA_AREA(head);
273                 }
274         }
275
276         return NULL;
277 }
278
279 #undef EXT_DATA_AREA
280
281 /*****************************************************************
282  Generic VFS init.
283 ******************************************************************/
284
285 bool smbd_vfs_init(connection_struct *conn)
286 {
287         const char **vfs_objects;
288         unsigned int i = 0;
289         int j = 0;
290         
291         /* Normal share - initialise with disk access functions */
292         vfs_init_default(conn);
293         vfs_objects = lp_vfs_objects(SNUM(conn));
294
295         /* Override VFS functions if 'vfs object' was not specified*/
296         if (!vfs_objects || !vfs_objects[0])
297                 return True;
298         
299         for (i=0; vfs_objects[i] ;) {
300                 i++;
301         }
302
303         for (j=i-1; j >= 0; j--) {
304                 if (!vfs_init_custom(conn, vfs_objects[j])) {
305                         DEBUG(0, ("smbd_vfs_init: vfs_init_custom failed for %s\n", vfs_objects[j]));
306                         return False;
307                 }
308         }
309         return True;
310 }
311
312 /*******************************************************************
313  Check if directory exists.
314 ********************************************************************/
315
316 bool vfs_directory_exist(connection_struct *conn, const char *dname, SMB_STRUCT_STAT *st)
317 {
318         SMB_STRUCT_STAT st2;
319         bool ret;
320
321         if (!st)
322                 st = &st2;
323
324         if (SMB_VFS_STAT(conn,dname,st) != 0)
325                 return(False);
326
327         ret = S_ISDIR(st->st_mode);
328         if(!ret)
329                 errno = ENOTDIR;
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                 errno = EINVAL;
483                 return -1;
484         }
485
486         ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st);
487         if (ret == -1)
488                 return ret;
489
490         if (len == (SMB_BIG_UINT)st.st_size)
491                 return 0;
492
493         if (len < (SMB_BIG_UINT)st.st_size) {
494                 /* Shrink - use ftruncate. */
495
496                 DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
497                                 fsp->fsp_name, (double)st.st_size ));
498
499                 flush_write_cache(fsp, SIZECHANGE_FLUSH);
500                 if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, (SMB_OFF_T)len)) != -1) {
501                         set_filelen_write_cache(fsp, len);
502                 }
503                 return ret;
504         }
505
506         /* Grow - we need to test if we have enough space. */
507
508         if (!lp_strict_allocate(SNUM(fsp->conn)))
509                 return 0;
510
511         len -= st.st_size;
512         len /= 1024; /* Len is now number of 1k blocks needed. */
513         space_avail = get_dfree_info(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize);
514         if (space_avail == (SMB_BIG_UINT)-1) {
515                 return -1;
516         }
517
518         DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %.0f, space avail = %.0f\n",
519                         fsp->fsp_name, (double)st.st_size, (double)len, (double)space_avail ));
520
521         if (len > space_avail) {
522                 errno = ENOSPC;
523                 return -1;
524         }
525
526         return 0;
527 }
528
529 /****************************************************************************
530  A vfs set_filelen call.
531  set the length of a file from a filedescriptor.
532  Returns 0 on success, -1 on failure.
533 ****************************************************************************/
534
535 int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
536 {
537         int ret;
538
539         release_level_2_oplocks_on_change(fsp);
540         DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len));
541         flush_write_cache(fsp, SIZECHANGE_FLUSH);
542         if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, len)) != -1) {
543                 set_filelen_write_cache(fsp, len);
544                 notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED,
545                              FILE_NOTIFY_CHANGE_SIZE
546                              | FILE_NOTIFY_CHANGE_ATTRIBUTES,
547                              fsp->fsp_name);
548         }
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 char *LastDir = NULL;
683
684         if (!LastDir) {
685                 LastDir = SMB_STRDUP("");
686         }
687
688         if (strcsequal(path,"."))
689                 return(0);
690
691         if (*path == '/' && strcsequal(LastDir,path))
692                 return(0);
693
694         DEBUG(4,("vfs_ChDir to %s\n",path));
695
696         res = SMB_VFS_CHDIR(conn,path);
697         if (!res) {
698                 SAFE_FREE(LastDir);
699                 LastDir = SMB_STRDUP(path);
700         }
701         return(res);
702 }
703
704 /* number of list structures for a caching GetWd function. */
705 #define MAX_GETWDCACHE (50)
706
707 static struct {
708         SMB_DEV_T dev; /* These *must* be compatible with the types returned in a stat() call. */
709         SMB_INO_T inode; /* These *must* be compatible with the types returned in a stat() call. */
710         char *path; /* The pathname. */
711         bool valid;
712 } ino_list[MAX_GETWDCACHE];
713
714 extern bool use_getwd_cache;
715
716 /****************************************************************************
717  Prompte a ptr (to make it recently used)
718 ****************************************************************************/
719
720 static void array_promote(char *array,int elsize,int element)
721 {
722         char *p;
723         if (element == 0)
724                 return;
725
726         p = (char *)SMB_MALLOC(elsize);
727
728         if (!p) {
729                 DEBUG(5,("array_promote: malloc fail\n"));
730                 return;
731         }
732
733         memcpy(p,array + element * elsize, elsize);
734         memmove(array + elsize,array,elsize*element);
735         memcpy(array,p,elsize);
736         SAFE_FREE(p);
737 }
738
739 /*******************************************************************
740  Return the absolute current directory path - given a UNIX pathname.
741  Note that this path is returned in DOS format, not UNIX
742  format. Note this can be called with conn == NULL.
743 ********************************************************************/
744
745 char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn)
746 {
747 #ifdef PATH_MAX
748         char s[PATH_MAX+1];
749 #else
750         pstring s;
751 #endif
752         static bool getwd_cache_init = False;
753         SMB_STRUCT_STAT st, st2;
754         int i;
755         char *ret = NULL;
756
757         *s = 0;
758
759         if (!use_getwd_cache) {
760  nocache:
761                 ret = SMB_VFS_GETWD(conn,s);
762                 if (!ret) {
763                         DEBUG(0,("vfs_GetWd: SMB_VFS_GETWD call failed, "
764                                 "errno %s\n",strerror(errno)));
765                         return NULL;
766                 }
767                 return talloc_strdup(ctx, ret);
768         }
769
770         /* init the cache */
771         if (!getwd_cache_init) {
772                 getwd_cache_init = True;
773                 for (i=0;i<MAX_GETWDCACHE;i++) {
774                         string_set(&ino_list[i].path,"");
775                         ino_list[i].valid = False;
776                 }
777         }
778
779         /*  Get the inode of the current directory, if this doesn't work we're
780                 in trouble :-) */
781
782         if (SMB_VFS_STAT(conn, ".",&st) == -1) {
783                 /* Known to fail for root: the directory may be
784                  * NFS-mounted and exported with root_squash (so has no root access). */
785                 DEBUG(1,("vfs_GetWd: couldn't stat \".\" error %s "
786                         "(NFS problem ?)\n",
787                         strerror(errno) ));
788                 goto nocache;
789         }
790
791
792         for (i=0; i<MAX_GETWDCACHE; i++) {
793                 if (ino_list[i].valid) {
794
795                         /*  If we have found an entry with a matching inode and dev number
796                                 then find the inode number for the directory in the cached string.
797                                 If this agrees with that returned by the stat for the current
798                                 directory then all is o.k. (but make sure it is a directory all
799                                 the same...) */
800
801                         if (st.st_ino == ino_list[i].inode && st.st_dev == ino_list[i].dev) {
802                                 if (SMB_VFS_STAT(conn,ino_list[i].path,&st2) == 0) {
803                                         if (st.st_ino == st2.st_ino && st.st_dev == st2.st_dev &&
804                                                         (st2.st_mode & S_IFMT) == S_IFDIR) {
805
806                                                 ret = talloc_strdup(ctx,
807                                                         ino_list[i].path);
808
809                                                 /* promote it for future use */
810                                                 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
811                                                 if (ret == NULL) {
812                                                         errno = ENOMEM;
813                                                 }
814                                                 return ret;
815                                         } else {
816                                                 /*  If the inode is different then something's changed,
817                                                         scrub the entry and start from scratch. */
818                                                 ino_list[i].valid = False;
819                                         }
820                                 }
821                         }
822                 }
823         }
824
825         /*  We don't have the information to hand so rely on traditional
826          *  methods. The very slow getcwd, which spawns a process on some
827          *  systems, or the not quite so bad getwd. */
828
829         if (!SMB_VFS_GETWD(conn,s)) {
830                 DEBUG(0,("vfs_GetWd: SMB_VFS_GETWD call failed, errno %s\n",
831                                 strerror(errno)));
832                 return (NULL);
833         }
834
835         ret = talloc_strdup(ctx,s);
836
837         DEBUG(5,("vfs_GetWd %s, inode %.0f, dev %.0f\n",
838                                 s,(double)st.st_ino,(double)st.st_dev));
839
840         /* add it to the cache */
841         i = MAX_GETWDCACHE - 1;
842         string_set(&ino_list[i].path,s);
843         ino_list[i].dev = st.st_dev;
844         ino_list[i].inode = st.st_ino;
845         ino_list[i].valid = True;
846
847         /* put it at the top of the list */
848         array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
849
850         if (ret == NULL) {
851                 errno = ENOMEM;
852         }
853         return ret;
854 }
855
856 /*******************************************************************
857  Reduce a file name, removing .. elements and checking that
858  it is below dir in the heirachy. This uses realpath.
859 ********************************************************************/
860
861 NTSTATUS check_reduced_name(connection_struct *conn, const char *fname)
862 {
863 #ifdef REALPATH_TAKES_NULL
864         bool free_resolved_name = True;
865 #else
866 #ifdef PATH_MAX
867         char resolved_name_buf[PATH_MAX+1];
868 #else
869         pstring resolved_name_buf;
870 #endif
871         bool free_resolved_name = False;
872 #endif
873         char *resolved_name = NULL;
874         size_t con_path_len = strlen(conn->connectpath);
875         char *p = NULL;
876
877         DEBUG(3,("reduce_name [%s] [%s]\n", fname, conn->connectpath));
878
879 #ifdef REALPATH_TAKES_NULL
880         resolved_name = SMB_VFS_REALPATH(conn,fname,NULL);
881 #else
882         resolved_name = SMB_VFS_REALPATH(conn,fname,resolved_name_buf);
883 #endif
884
885         if (!resolved_name) {
886                 switch (errno) {
887                         case ENOTDIR:
888                                 DEBUG(3,("reduce_name: Component not a directory in getting realpath for %s\n", fname));
889                                 return map_nt_error_from_unix(errno);
890                         case ENOENT:
891                         {
892                                 TALLOC_CTX *tmp_ctx = talloc_stackframe();
893                                 char *tmp_fname = NULL;
894                                 char *last_component = NULL;
895                                 /* Last component didn't exist. Remove it and try and canonicalise the directory. */
896
897                                 tmp_fname = talloc_strdup(tmp_ctx, fname);
898                                 if (!tmp_fname) {
899                                         TALLOC_FREE(tmp_ctx);
900                                         return NT_STATUS_NO_MEMORY;
901                                 }
902                                 p = strrchr_m(tmp_fname, '/');
903                                 if (p) {
904                                         *p++ = '\0';
905                                         last_component = p;
906                                 } else {
907                                         last_component = tmp_fname;
908                                         tmp_fname = talloc_strdup(tmp_ctx,
909                                                         ".");
910                                         if (!tmp_fname) {
911                                                 TALLOC_FREE(tmp_ctx);
912                                                 return NT_STATUS_NO_MEMORY;
913                                         }
914                                 }
915
916 #ifdef REALPATH_TAKES_NULL
917                                 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,NULL);
918 #else
919                                 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,resolved_name_buf);
920 #endif
921                                 if (!resolved_name) {
922                                         DEBUG(3,("reduce_name: couldn't get realpath for %s\n", fname));
923                                         TALLOC_FREE(tmp_ctx);
924                                         return map_nt_error_from_unix(errno);
925                                 }
926                                 tmp_fname = talloc_asprintf(tmp_ctx,
927                                                 "%s/%s",
928                                                 resolved_name,
929                                                 last_component);
930                                 if (!tmp_fname) {
931                                         TALLOC_FREE(tmp_ctx);
932                                         return NT_STATUS_NO_MEMORY;
933                                 }
934 #ifdef REALPATH_TAKES_NULL
935                                 SAFE_FREE(resolved_name);
936                                 resolved_name = SMB_STRDUP(tmp_fname);
937                                 if (!resolved_name) {
938                                         DEBUG(0,("reduce_name: malloc fail for %s\n", tmp_fname));
939                                         return NT_STATUS_NO_MEMORY;
940                                 }
941 #else
942 #ifdef PATH_MAX
943                                 safe_strcpy(resolved_name_buf, tmp_fname, PATH_MAX);
944 #else
945                                 pstrcpy(resolved_name_buf, tmp_fname);
946 #endif
947                                 resolved_name = resolved_name_buf;
948 #endif
949                                 TALLOC_FREE(tmp_ctx);
950                                 break;
951                         }
952                         default:
953                                 DEBUG(1,("reduce_name: couldn't get realpath for %s\n", fname));
954                                 return map_nt_error_from_unix(errno);
955                 }
956         }
957
958         DEBUG(10,("reduce_name realpath [%s] -> [%s]\n", fname, resolved_name));
959
960         if (*resolved_name != '/') {
961                 DEBUG(0,("reduce_name: realpath doesn't return absolute paths !\n"));
962                 if (free_resolved_name) {
963                         SAFE_FREE(resolved_name);
964                 }
965                 return NT_STATUS_OBJECT_NAME_INVALID;
966         }
967
968         /* Check for widelinks allowed. */
969         if (!lp_widelinks(SNUM(conn)) && (strncmp(conn->connectpath, resolved_name, con_path_len) != 0)) {
970                 DEBUG(2, ("reduce_name: Bad access attempt: %s is a symlink outside the share path", fname));
971                 if (free_resolved_name) {
972                         SAFE_FREE(resolved_name);
973                 }
974                 return NT_STATUS_ACCESS_DENIED;
975         }
976
977         /* Check if we are allowing users to follow symlinks */
978         /* Patch from David Clerc <David.Clerc@cui.unige.ch>
979                 University of Geneva */
980
981 #ifdef S_ISLNK
982         if (!lp_symlinks(SNUM(conn))) {
983                 SMB_STRUCT_STAT statbuf;
984                 if ( (SMB_VFS_LSTAT(conn,fname,&statbuf) != -1) &&
985                                 (S_ISLNK(statbuf.st_mode)) ) {
986                         if (free_resolved_name) {
987                                 SAFE_FREE(resolved_name);
988                         }
989                         DEBUG(3,("reduce_name: denied: file path name %s is a symlink\n",resolved_name));
990                         return NT_STATUS_ACCESS_DENIED;
991                 }
992         }
993 #endif
994
995         DEBUG(3,("reduce_name: %s reduced to %s\n", fname, resolved_name));
996         if (free_resolved_name) {
997                 SAFE_FREE(resolved_name);
998         }
999         return NT_STATUS_OK;
1000 }