r5825: Fix one more DISK_FREE call - spotted by Ying Li <ying.li2@hp.com>.
[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
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
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 struct vfs_init_function_entry {
31         char *name;
32         vfs_op_tuple *vfs_op_tuples;
33         struct vfs_init_function_entry *prev, *next;
34 };
35
36 static struct vfs_init_function_entry *backends = NULL;
37
38 /* Some structures to help us initialise the vfs operations table */
39
40 struct vfs_syminfo {
41         char *name;
42         void *fptr;
43 };
44
45 /* Default vfs hooks.  WARNING: The order of these initialisers is
46    very important.  They must be in the same order as defined in
47    vfs.h.  Change at your own peril. */
48
49 static struct vfs_ops default_vfs = {
50
51         {
52                 /* Disk operations */
53         
54                 vfswrap_dummy_connect,
55                 vfswrap_dummy_disconnect,
56                 vfswrap_disk_free,
57                 vfswrap_get_quota,
58                 vfswrap_set_quota,
59                 vfswrap_get_shadow_copy_data,
60         
61                 /* Directory operations */
62         
63                 vfswrap_opendir,
64                 vfswrap_readdir,
65                 vfswrap_seekdir,
66                 vfswrap_telldir,
67                 vfswrap_rewinddir,
68                 vfswrap_mkdir,
69                 vfswrap_rmdir,
70                 vfswrap_closedir,
71         
72                 /* File operations */
73         
74                 vfswrap_open,
75                 vfswrap_close,
76                 vfswrap_read,
77                 vfswrap_pread,
78                 vfswrap_write,
79                 vfswrap_pwrite,
80                 vfswrap_lseek,
81                 vfswrap_sendfile,
82                 vfswrap_rename,
83                 vfswrap_fsync,
84                 vfswrap_stat,
85                 vfswrap_fstat,
86                 vfswrap_lstat,
87                 vfswrap_unlink,
88                 vfswrap_chmod,
89                 vfswrap_fchmod,
90                 vfswrap_chown,
91                 vfswrap_fchown,
92                 vfswrap_chdir,
93                 vfswrap_getwd,
94                 vfswrap_utime,
95                 vfswrap_ftruncate,
96                 vfswrap_lock,
97                 vfswrap_symlink,
98                 vfswrap_readlink,
99                 vfswrap_link,
100                 vfswrap_mknod,
101                 vfswrap_realpath,
102         
103                 /* Windows ACL operations. */
104                 vfswrap_fget_nt_acl,
105                 vfswrap_get_nt_acl,
106                 vfswrap_fset_nt_acl,
107                 vfswrap_set_nt_acl,
108         
109                 /* POSIX ACL operations. */
110                 vfswrap_chmod_acl,
111                 vfswrap_fchmod_acl,
112
113                 vfswrap_sys_acl_get_entry,
114                 vfswrap_sys_acl_get_tag_type,
115                 vfswrap_sys_acl_get_permset,
116                 vfswrap_sys_acl_get_qualifier,
117                 vfswrap_sys_acl_get_file,
118                 vfswrap_sys_acl_get_fd,
119                 vfswrap_sys_acl_clear_perms,
120                 vfswrap_sys_acl_add_perm,
121                 vfswrap_sys_acl_to_text,
122                 vfswrap_sys_acl_init,
123                 vfswrap_sys_acl_create_entry,
124                 vfswrap_sys_acl_set_tag_type,
125                 vfswrap_sys_acl_set_qualifier,
126                 vfswrap_sys_acl_set_permset,
127                 vfswrap_sys_acl_valid,
128                 vfswrap_sys_acl_set_file,
129                 vfswrap_sys_acl_set_fd,
130                 vfswrap_sys_acl_delete_def_file,
131                 vfswrap_sys_acl_get_perm,
132                 vfswrap_sys_acl_free_text,
133                 vfswrap_sys_acl_free_acl,
134                 vfswrap_sys_acl_free_qualifier,
135
136                 /* EA operations. */
137                 vfswrap_getxattr,
138                 vfswrap_lgetxattr,
139                 vfswrap_fgetxattr,
140                 vfswrap_listxattr,
141                 vfswrap_llistxattr,
142                 vfswrap_flistxattr,
143                 vfswrap_removexattr,
144                 vfswrap_lremovexattr,
145                 vfswrap_fremovexattr,
146                 vfswrap_setxattr,
147                 vfswrap_lsetxattr,
148                 vfswrap_fsetxattr
149         }
150 };
151
152 /****************************************************************************
153     maintain the list of available backends
154 ****************************************************************************/
155
156 static struct vfs_init_function_entry *vfs_find_backend_entry(const char *name)
157 {
158         struct vfs_init_function_entry *entry = backends;
159  
160         while(entry) {
161                 if (strcmp(entry->name, name)==0) return entry;
162                 entry = entry->next;
163         }
164
165         return NULL;
166 }
167
168 NTSTATUS smb_register_vfs(int version, const char *name, vfs_op_tuple *vfs_op_tuples)
169 {
170         struct vfs_init_function_entry *entry = backends;
171
172         if ((version != SMB_VFS_INTERFACE_VERSION)) {
173                 DEBUG(0, ("Failed to register vfs module.\n"
174                           "The module was compiled against SMB_VFS_INTERFACE_VERSION %d,\n"
175                           "current SMB_VFS_INTERFACE_VERSION is %d.\n"
176                           "Please recompile against the current Samba Version!\n",  
177                           version, SMB_VFS_INTERFACE_VERSION));
178                 return NT_STATUS_OBJECT_TYPE_MISMATCH;
179         }
180
181         if (!name || !name[0] || !vfs_op_tuples) {
182                 DEBUG(0,("smb_register_vfs() called with NULL pointer or empty name!\n"));
183                 return NT_STATUS_INVALID_PARAMETER;
184         }
185
186         if (vfs_find_backend_entry(name)) {
187                 DEBUG(0,("VFS module %s already loaded!\n", name));
188                 return NT_STATUS_OBJECT_NAME_COLLISION;
189         }
190
191         entry = SMB_XMALLOC_P(struct vfs_init_function_entry);
192         entry->name = smb_xstrdup(name);
193         entry->vfs_op_tuples = vfs_op_tuples;
194
195         DLIST_ADD(backends, entry);
196         DEBUG(5, ("Successfully added vfs backend '%s'\n", name));
197         return NT_STATUS_OK;
198 }
199
200 /****************************************************************************
201   initialise default vfs hooks
202 ****************************************************************************/
203
204 static void vfs_init_default(connection_struct *conn)
205 {
206         DEBUG(3, ("Initialising default vfs hooks\n"));
207
208         memcpy(&conn->vfs.ops, &default_vfs.ops, sizeof(default_vfs.ops));
209         memcpy(&conn->vfs_opaque.ops, &default_vfs.ops, sizeof(default_vfs.ops));
210 }
211
212 /****************************************************************************
213   initialise custom vfs hooks
214  ****************************************************************************/
215
216 BOOL vfs_init_custom(connection_struct *conn, const char *vfs_object)
217 {
218         vfs_op_tuple *ops;
219         char *module_name = NULL;
220         char *module_param = NULL, *p;
221         int i;
222         vfs_handle_struct *handle;
223         struct vfs_init_function_entry *entry;
224         
225         if (!conn||!vfs_object||!vfs_object[0]) {
226                 DEBUG(0,("vfs_init_custon() called with NULL pointer or emtpy vfs_object!\n"));
227                 return False;
228         }
229
230         if(!backends) static_init_vfs;
231
232         DEBUG(3, ("Initialising custom vfs hooks from [%s]\n", vfs_object));
233
234         module_name = smb_xstrdup(vfs_object);
235
236         p = strchr(module_name, ':');
237
238         if (p) {
239                 *p = 0;
240                 module_param = p+1;
241                 trim_char(module_param, ' ', ' ');
242         }
243
244         trim_char(module_name, ' ', ' ');
245
246         /* First, try to load the module with the new module system */
247         if((entry = vfs_find_backend_entry(module_name)) || 
248            (NT_STATUS_IS_OK(smb_probe_module("vfs", module_name)) && 
249                 (entry = vfs_find_backend_entry(module_name)))) {
250
251                 DEBUGADD(5,("Successfully loaded vfs module [%s] with the new modules system\n", vfs_object));
252                 
253                 if ((ops = entry->vfs_op_tuples) == NULL) {
254                         DEBUG(0, ("entry->vfs_op_tuples==NULL for [%s] failed\n", vfs_object));
255                         SAFE_FREE(module_name);
256                         return False;
257                 }
258         } else {
259                 DEBUG(0,("Can't find a vfs module [%s]\n",vfs_object));
260                 SAFE_FREE(module_name);
261                 return False;
262         }
263
264         handle = TALLOC_ZERO_P(conn->mem_ctx,vfs_handle_struct);
265         if (!handle) {
266                 DEBUG(0,("talloc_zero() failed!\n"));
267                 SAFE_FREE(module_name);
268                 return False;
269         }
270         memcpy(&handle->vfs_next, &conn->vfs, sizeof(struct vfs_ops));
271         handle->conn = conn;
272         if (module_param) {
273                 handle->param = talloc_strdup(conn->mem_ctx, module_param);
274         }
275         DLIST_ADD(conn->vfs_handles, handle);
276
277         for(i=0; ops[i].op != NULL; i++) {
278           DEBUG(5, ("Checking operation #%d (type %d, layer %d)\n", i, ops[i].type, ops[i].layer));
279           if(ops[i].layer == SMB_VFS_LAYER_OPAQUE) {
280             /* Check whether this operation was already made opaque by different module */
281             if(((void**)&conn->vfs_opaque.ops)[ops[i].type] == ((void**)&default_vfs.ops)[ops[i].type]) {
282               /* No, it isn't overloaded yet. Overload. */
283               DEBUGADD(5, ("Making operation type %d opaque [module %s]\n", ops[i].type, vfs_object));
284               ((void**)&conn->vfs_opaque.ops)[ops[i].type] = ops[i].op;
285               ((vfs_handle_struct **)&conn->vfs_opaque.handles)[ops[i].type] = handle;
286             }
287           }
288           /* Change current VFS disposition*/
289           DEBUGADD(5, ("Accepting operation type %d from module %s\n", ops[i].type, vfs_object));
290           ((void**)&conn->vfs.ops)[ops[i].type] = ops[i].op;
291           ((vfs_handle_struct **)&conn->vfs.handles)[ops[i].type] = handle;
292         }
293
294         SAFE_FREE(module_name);
295         return True;
296 }
297
298 /*****************************************************************
299  Generic VFS init.
300 ******************************************************************/
301
302 BOOL smbd_vfs_init(connection_struct *conn)
303 {
304         const char **vfs_objects;
305         unsigned int i = 0;
306         int j = 0;
307         
308         /* Normal share - initialise with disk access functions */
309         vfs_init_default(conn);
310         vfs_objects = lp_vfs_objects(SNUM(conn));
311
312         /* Override VFS functions if 'vfs object' was not specified*/
313         if (!vfs_objects || !vfs_objects[0])
314                 return True;
315         
316         for (i=0; vfs_objects[i] ;) {
317                 i++;
318         }
319
320         for (j=i-1; j >= 0; j--) {
321                 if (!vfs_init_custom(conn, vfs_objects[j])) {
322                         DEBUG(0, ("smbd_vfs_init: vfs_init_custom failed for %s\n", vfs_objects[j]));
323                         return False;
324                 }
325         }
326         return True;
327 }
328
329 /*******************************************************************
330  Check if directory exists.
331 ********************************************************************/
332
333 BOOL vfs_directory_exist(connection_struct *conn, const char *dname, SMB_STRUCT_STAT *st)
334 {
335         SMB_STRUCT_STAT st2;
336         BOOL ret;
337
338         if (!st)
339                 st = &st2;
340
341         if (SMB_VFS_STAT(conn,dname,st) != 0)
342                 return(False);
343
344         ret = S_ISDIR(st->st_mode);
345         if(!ret)
346                 errno = ENOTDIR;
347
348         return ret;
349 }
350
351 /*******************************************************************
352  vfs mkdir wrapper 
353 ********************************************************************/
354
355 int vfs_MkDir(connection_struct *conn, const char *name, mode_t mode)
356 {
357         int ret;
358         SMB_STRUCT_STAT sbuf;
359
360         if(!(ret=SMB_VFS_MKDIR(conn, name, mode))) {
361
362                 inherit_access_acl(conn, name, mode);
363
364                 /*
365                  * Check if high bits should have been set,
366                  * then (if bits are missing): add them.
367                  * Consider bits automagically set by UNIX, i.e. SGID bit from parent dir.
368                  */
369                 if(mode & ~(S_IRWXU|S_IRWXG|S_IRWXO) &&
370                                 !SMB_VFS_STAT(conn,name,&sbuf) && (mode & ~sbuf.st_mode))
371                         SMB_VFS_CHMOD(conn,name,sbuf.st_mode | (mode & ~sbuf.st_mode));
372         }
373         return ret;
374 }
375
376 /*******************************************************************
377  Check if an object exists in the vfs.
378 ********************************************************************/
379
380 BOOL vfs_object_exist(connection_struct *conn,const char *fname,SMB_STRUCT_STAT *sbuf)
381 {
382         SMB_STRUCT_STAT st;
383
384         if (!sbuf)
385                 sbuf = &st;
386
387         ZERO_STRUCTP(sbuf);
388
389         if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
390                 return(False);
391         return True;
392 }
393
394 /*******************************************************************
395  Check if a file exists in the vfs.
396 ********************************************************************/
397
398 BOOL vfs_file_exist(connection_struct *conn, const char *fname,SMB_STRUCT_STAT *sbuf)
399 {
400         SMB_STRUCT_STAT st;
401
402         if (!sbuf)
403                 sbuf = &st;
404
405         ZERO_STRUCTP(sbuf);
406
407         if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
408                 return False;
409         return(S_ISREG(sbuf->st_mode));
410 }
411
412 /****************************************************************************
413  Read data from fsp on the vfs. (note: EINTR re-read differs from vfs_write_data)
414 ****************************************************************************/
415
416 ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count)
417 {
418         size_t total=0;
419
420         while (total < byte_count)
421         {
422                 ssize_t ret = SMB_VFS_READ(fsp, fsp->fd, buf + total,
423                                         byte_count - total);
424
425                 if (ret == 0) return total;
426                 if (ret == -1) {
427                         if (errno == EINTR)
428                                 continue;
429                         else
430                                 return -1;
431                 }
432                 total += ret;
433         }
434         return (ssize_t)total;
435 }
436
437 ssize_t vfs_pread_data(files_struct *fsp, char *buf,
438                 size_t byte_count, SMB_OFF_T offset)
439 {
440         size_t total=0;
441
442         while (total < byte_count)
443         {
444                 ssize_t ret = SMB_VFS_PREAD(fsp, fsp->fd, buf + total,
445                                         byte_count - total, offset + total);
446
447                 if (ret == 0) return total;
448                 if (ret == -1) {
449                         if (errno == EINTR)
450                                 continue;
451                         else
452                                 return -1;
453                 }
454                 total += ret;
455         }
456         return (ssize_t)total;
457 }
458
459 /****************************************************************************
460  Write data to a fd on the vfs.
461 ****************************************************************************/
462
463 ssize_t vfs_write_data(files_struct *fsp,const char *buffer,size_t N)
464 {
465         size_t total=0;
466         ssize_t ret;
467
468         while (total < N) {
469                 ret = SMB_VFS_WRITE(fsp,fsp->fd,buffer + total,N - total);
470
471                 if (ret == -1)
472                         return -1;
473                 if (ret == 0)
474                         return total;
475
476                 total += ret;
477         }
478         return (ssize_t)total;
479 }
480
481 ssize_t vfs_pwrite_data(files_struct *fsp,const char *buffer,
482                 size_t N, SMB_OFF_T offset)
483 {
484         size_t total=0;
485         ssize_t ret;
486
487         while (total < N) {
488                 ret = SMB_VFS_PWRITE(fsp, fsp->fd, buffer + total,
489                                 N - total, offset + total);
490
491                 if (ret == -1)
492                         return -1;
493                 if (ret == 0)
494                         return total;
495
496                 total += ret;
497         }
498         return (ssize_t)total;
499 }
500 /****************************************************************************
501  An allocate file space call using the vfs interface.
502  Allocates space for a file from a filedescriptor.
503  Returns 0 on success, -1 on failure.
504 ****************************************************************************/
505
506 int vfs_allocate_file_space(files_struct *fsp, SMB_BIG_UINT len)
507 {
508         int ret;
509         SMB_STRUCT_STAT st;
510         connection_struct *conn = fsp->conn;
511         SMB_BIG_UINT space_avail;
512         SMB_BIG_UINT bsize,dfree,dsize;
513
514         release_level_2_oplocks_on_change(fsp);
515
516         /*
517          * Actually try and commit the space on disk....
518          */
519
520         DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", fsp->fsp_name, (double)len ));
521
522         if (((SMB_OFF_T)len) < 0) {
523                 DEBUG(0,("vfs_allocate_file_space: %s negative len requested.\n", fsp->fsp_name ));
524                 return -1;
525         }
526
527         ret = SMB_VFS_FSTAT(fsp,fsp->fd,&st);
528         if (ret == -1)
529                 return ret;
530
531         if (len == (SMB_BIG_UINT)st.st_size)
532                 return 0;
533
534         if (len < (SMB_BIG_UINT)st.st_size) {
535                 /* Shrink - use ftruncate. */
536
537                 DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
538                                 fsp->fsp_name, (double)st.st_size ));
539
540                 flush_write_cache(fsp, SIZECHANGE_FLUSH);
541                 if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fd, (SMB_OFF_T)len)) != -1) {
542                         set_filelen_write_cache(fsp, len);
543                 }
544                 return ret;
545         }
546
547         /* Grow - we need to test if we have enough space. */
548
549         if (!lp_strict_allocate(SNUM(fsp->conn)))
550                 return 0;
551
552         len -= st.st_size;
553         len /= 1024; /* Len is now number of 1k blocks needed. */
554         space_avail = SMB_VFS_DISK_FREE(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize);
555         if (space_avail == (SMB_BIG_UINT)-1) {
556                 return -1;
557         }
558
559         DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %.0f, space avail = %.0f\n",
560                         fsp->fsp_name, (double)st.st_size, (double)len, (double)space_avail ));
561
562         if (len > space_avail) {
563                 errno = ENOSPC;
564                 return -1;
565         }
566
567         return 0;
568 }
569
570 /****************************************************************************
571  A vfs set_filelen call.
572  set the length of a file from a filedescriptor.
573  Returns 0 on success, -1 on failure.
574 ****************************************************************************/
575
576 int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
577 {
578         int ret;
579
580         release_level_2_oplocks_on_change(fsp);
581         DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len));
582         flush_write_cache(fsp, SIZECHANGE_FLUSH);
583         if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fd, len)) != -1)
584                 set_filelen_write_cache(fsp, len);
585
586         return ret;
587 }
588
589 /****************************************************************************
590  Transfer some data (n bytes) between two file_struct's.
591 ****************************************************************************/
592
593 static files_struct *in_fsp;
594 static files_struct *out_fsp;
595
596 static ssize_t read_fn(int fd, void *buf, size_t len)
597 {
598         return SMB_VFS_READ(in_fsp, fd, buf, len);
599 }
600
601 static ssize_t write_fn(int fd, const void *buf, size_t len)
602 {
603         return SMB_VFS_WRITE(out_fsp, fd, buf, len);
604 }
605
606 SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n)
607 {
608         in_fsp = in;
609         out_fsp = out;
610
611         return transfer_file_internal(in_fsp->fd, out_fsp->fd, n, read_fn, write_fn);
612 }
613
614 /*******************************************************************
615  A vfs_readdir wrapper which just returns the file name.
616 ********************************************************************/
617
618 char *vfs_readdirname(connection_struct *conn, void *p)
619 {
620         SMB_STRUCT_DIRENT *ptr= NULL;
621         char *dname;
622
623         if (!p)
624                 return(NULL);
625
626         ptr = SMB_VFS_READDIR(conn,p);
627         if (!ptr)
628                 return(NULL);
629
630         dname = ptr->d_name;
631
632 #ifdef NEXT2
633         if (telldir(p) < 0)
634                 return(NULL);
635 #endif
636
637 #ifdef HAVE_BROKEN_READDIR
638         /* using /usr/ucb/cc is BAD */
639         dname = dname - 2;
640 #endif
641
642         return(dname);
643 }
644
645 /*******************************************************************
646  A wrapper for vfs_chdir().
647 ********************************************************************/
648
649 int vfs_ChDir(connection_struct *conn, const char *path)
650 {
651         int res;
652         static pstring LastDir="";
653
654         if (strcsequal(path,"."))
655                 return(0);
656
657         if (*path == '/' && strcsequal(LastDir,path))
658                 return(0);
659
660         DEBUG(4,("vfs_ChDir to %s\n",path));
661
662         res = SMB_VFS_CHDIR(conn,path);
663         if (!res)
664                 pstrcpy(LastDir,path);
665         return(res);
666 }
667
668 /* number of list structures for a caching GetWd function. */
669 #define MAX_GETWDCACHE (50)
670
671 static struct {
672         SMB_DEV_T dev; /* These *must* be compatible with the types returned in a stat() call. */
673         SMB_INO_T inode; /* These *must* be compatible with the types returned in a stat() call. */
674         char *dos_path; /* The pathname in DOS format. */
675         BOOL valid;
676 } ino_list[MAX_GETWDCACHE];
677
678 extern BOOL use_getwd_cache;
679
680 /****************************************************************************
681  Prompte a ptr (to make it recently used)
682 ****************************************************************************/
683
684 static void array_promote(char *array,int elsize,int element)
685 {
686         char *p;
687         if (element == 0)
688                 return;
689
690         p = (char *)SMB_MALLOC(elsize);
691
692         if (!p) {
693                 DEBUG(5,("array_promote: malloc fail\n"));
694                 return;
695         }
696
697         memcpy(p,array + element * elsize, elsize);
698         memmove(array + elsize,array,elsize*element);
699         memcpy(array,p,elsize);
700         SAFE_FREE(p);
701 }
702
703 /*******************************************************************
704  Return the absolute current directory path - given a UNIX pathname.
705  Note that this path is returned in DOS format, not UNIX
706  format. Note this can be called with conn == NULL.
707 ********************************************************************/
708
709 char *vfs_GetWd(connection_struct *conn, char *path)
710 {
711         pstring s;
712         static BOOL getwd_cache_init = False;
713         SMB_STRUCT_STAT st, st2;
714         int i;
715
716         *s = 0;
717
718         if (!use_getwd_cache)
719                 return(SMB_VFS_GETWD(conn,path));
720
721         /* init the cache */
722         if (!getwd_cache_init) {
723                 getwd_cache_init = True;
724                 for (i=0;i<MAX_GETWDCACHE;i++) {
725                         string_set(&ino_list[i].dos_path,"");
726                         ino_list[i].valid = False;
727                 }
728         }
729
730         /*  Get the inode of the current directory, if this doesn't work we're
731                 in trouble :-) */
732
733         if (SMB_VFS_STAT(conn, ".",&st) == -1) {
734                 DEBUG(0,("Very strange, couldn't stat \".\" path=%s\n", path));
735                 return(SMB_VFS_GETWD(conn,path));
736         }
737
738
739         for (i=0; i<MAX_GETWDCACHE; i++) {
740                 if (ino_list[i].valid) {
741
742                         /*  If we have found an entry with a matching inode and dev number
743                                 then find the inode number for the directory in the cached string.
744                                 If this agrees with that returned by the stat for the current
745                                 directory then all is o.k. (but make sure it is a directory all
746                                 the same...) */
747
748                         if (st.st_ino == ino_list[i].inode && st.st_dev == ino_list[i].dev) {
749                                 if (SMB_VFS_STAT(conn,ino_list[i].dos_path,&st2) == 0) {
750                                         if (st.st_ino == st2.st_ino && st.st_dev == st2.st_dev &&
751                                                         (st2.st_mode & S_IFMT) == S_IFDIR) {
752                                                 pstrcpy (path, ino_list[i].dos_path);
753
754                                                 /* promote it for future use */
755                                                 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
756                                                 return (path);
757                                         } else {
758                                                 /*  If the inode is different then something's changed,
759                                                         scrub the entry and start from scratch. */
760                                                 ino_list[i].valid = False;
761                                         }
762                                 }
763                         }
764                 }
765         }
766
767         /*  We don't have the information to hand so rely on traditional methods.
768                 The very slow getcwd, which spawns a process on some systems, or the
769                 not quite so bad getwd. */
770
771         if (!SMB_VFS_GETWD(conn,s)) {
772                 DEBUG(0,("vfs_GetWd: SMB_VFS_GETWD call failed, errno %s\n",strerror(errno)));
773                 return (NULL);
774         }
775
776         pstrcpy(path,s);
777
778         DEBUG(5,("vfs_GetWd %s, inode %.0f, dev %.0f\n",s,(double)st.st_ino,(double)st.st_dev));
779
780         /* add it to the cache */
781         i = MAX_GETWDCACHE - 1;
782         string_set(&ino_list[i].dos_path,s);
783         ino_list[i].dev = st.st_dev;
784         ino_list[i].inode = st.st_ino;
785         ino_list[i].valid = True;
786
787         /* put it at the top of the list */
788         array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
789
790         return (path);
791 }
792
793 BOOL canonicalize_path(connection_struct *conn, pstring path)
794 {
795 #ifdef REALPATH_TAKES_NULL
796         char *resolved_name = SMB_VFS_REALPATH(conn,path,NULL);
797         if (!resolved_name) {
798                 return False;
799         }
800         pstrcpy(path, resolved_name);
801         SAFE_FREE(resolved_name);
802         return True;
803 #else
804 #ifdef PATH_MAX
805         char resolved_name_buf[PATH_MAX+1];
806 #else
807         pstring resolved_name_buf;
808 #endif
809         char *resolved_name = SMB_VFS_REALPATH(conn,path,resolved_name_buf);
810         if (!resolved_name) {
811                 return False;
812         }
813         pstrcpy(path, resolved_name);
814         return True;
815 #endif /* REALPATH_TAKES_NULL */
816 }
817
818 /*******************************************************************
819  Reduce a file name, removing .. elements and checking that
820  it is below dir in the heirachy. This uses realpath.
821 ********************************************************************/
822
823 BOOL reduce_name(connection_struct *conn, const pstring fname)
824 {
825 #ifdef REALPATH_TAKES_NULL
826         BOOL free_resolved_name = True;
827 #else
828 #ifdef PATH_MAX
829         char resolved_name_buf[PATH_MAX+1];
830 #else
831         pstring resolved_name_buf;
832 #endif
833         BOOL free_resolved_name = False;
834 #endif
835         char *resolved_name = NULL;
836         size_t con_path_len = strlen(conn->connectpath);
837         char *p = NULL;
838         int saved_errno = errno;
839
840         DEBUG(3,("reduce_name [%s] [%s]\n", fname, conn->connectpath));
841
842 #ifdef REALPATH_TAKES_NULL
843         resolved_name = SMB_VFS_REALPATH(conn,fname,NULL);
844 #else
845         resolved_name = SMB_VFS_REALPATH(conn,fname,resolved_name_buf);
846 #endif
847
848         if (!resolved_name) {
849                 switch (errno) {
850                         case ENOTDIR:
851                                 DEBUG(3,("reduce_name: Component not a directory in getting realpath for %s\n", fname));
852                                 errno = saved_errno;
853                                 return False;
854                         case ENOENT:
855                         {
856                                 pstring tmp_fname;
857                                 fstring last_component;
858                                 /* Last component didn't exist. Remove it and try and canonicalise the directory. */
859
860                                 pstrcpy(tmp_fname, fname);
861                                 p = strrchr_m(tmp_fname, '/');
862                                 if (p) {
863                                         *p++ = '\0';
864                                         fstrcpy(last_component, p);
865                                 } else {
866                                         fstrcpy(last_component, tmp_fname);
867                                         pstrcpy(tmp_fname, ".");
868                                 }
869
870 #ifdef REALPATH_TAKES_NULL
871                                 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,NULL);
872 #else
873                                 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,resolved_name_buf);
874 #endif
875                                 if (!resolved_name) {
876                                         DEBUG(3,("reduce_name: couldn't get realpath for %s\n", fname));
877                                         errno = saved_errno;
878                                         return False;
879                                 }
880                                 pstrcpy(tmp_fname, resolved_name);
881                                 pstrcat(tmp_fname, "/");
882                                 pstrcat(tmp_fname, last_component);
883 #ifdef REALPATH_TAKES_NULL
884                                 SAFE_FREE(resolved_name);
885                                 resolved_name = SMB_STRDUP(tmp_fname);
886                                 if (!resolved_name) {
887                                         DEBUG(0,("reduce_name: malloc fail for %s\n", tmp_fname));
888                                         errno = saved_errno;
889                                         return False;
890                                 }
891 #else
892 #ifdef PATH_MAX
893                                 safe_strcpy(resolved_name_buf, tmp_fname, PATH_MAX);
894 #else
895                                 pstrcpy(pstring resolved_name_buf, tmp_fname);
896 #endif
897                                 resolved_name = resolved_name_buf;
898 #endif
899                                 break;
900                         }
901                         default:
902                                 DEBUG(1,("reduce_name: couldn't get realpath for %s\n", fname));
903                                 /* Don't restore the saved errno. We need to return the error that
904                                    realpath caused here as it was not one of the cases we handle. JRA. */
905                                 return False;
906                 }
907         }
908
909         DEBUG(10,("reduce_name realpath [%s] -> [%s]\n", fname, resolved_name));
910
911         if (*resolved_name != '/') {
912                 DEBUG(0,("reduce_name: realpath doesn't return absolute paths !\n"));
913                 if (free_resolved_name)
914                         SAFE_FREE(resolved_name);
915                 errno = saved_errno;
916                 return False;
917         }
918
919         /* Check for widelinks allowed. */
920         if (!lp_widelinks(SNUM(conn)) && (strncmp(conn->connectpath, resolved_name, con_path_len) != 0)) {
921                 DEBUG(2, ("reduce_name: Bad access attempt: %s is a symlink outside the share path", fname));
922                 if (free_resolved_name)
923                         SAFE_FREE(resolved_name);
924                 errno = EACCES;
925                 return False;
926         }
927
928         /* Check if we are allowing users to follow symlinks */
929         /* Patch from David Clerc <David.Clerc@cui.unige.ch>
930                 University of Geneva */
931                                                                                                                                                     
932 #ifdef S_ISLNK
933         if (!lp_symlinks(SNUM(conn))) {
934                 SMB_STRUCT_STAT statbuf;
935                 if ( (SMB_VFS_LSTAT(conn,fname,&statbuf) != -1) &&
936                                 (S_ISLNK(statbuf.st_mode)) ) {
937                         if (free_resolved_name)
938                                 SAFE_FREE(resolved_name);
939                         DEBUG(3,("reduce_name: denied: file path name %s is a symlink\n",resolved_name));
940                         errno = EACCES;
941                         return False;
942                 }
943         }
944 #endif
945
946         DEBUG(3,("reduce_name: %s reduced to %s\n", fname, resolved_name));
947         if (free_resolved_name)
948                 SAFE_FREE(resolved_name);
949         errno = saved_errno;
950         return(True);
951 }