r17915: Saturn fixes
[Samba/gbeck.git] / source / smbd / vfs.c
blob2c9403a079092734c535a9596943d4a6537a1b14
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
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.
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.
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.
22 This work was sponsored by Optifacio Software Services, Inc.
25 #include "includes.h"
27 #undef DBGC_CLASS
28 #define DBGC_CLASS DBGC_VFS
30 static_decl_vfs;
32 struct vfs_init_function_entry {
33 char *name;
34 vfs_op_tuple *vfs_op_tuples;
35 struct vfs_init_function_entry *prev, *next;
38 static struct vfs_init_function_entry *backends = NULL;
40 /* Some structures to help us initialise the vfs operations table */
42 struct vfs_syminfo {
43 char *name;
44 void *fptr;
47 /* Default vfs hooks. WARNING: The order of these initialisers is
48 very important. They must be in the same order as defined in
49 vfs.h. Change at your own peril. */
51 static struct vfs_ops default_vfs = {
54 /* Disk operations */
56 vfswrap_dummy_connect,
57 vfswrap_dummy_disconnect,
58 vfswrap_disk_free,
59 vfswrap_get_quota,
60 vfswrap_set_quota,
61 vfswrap_get_shadow_copy_data,
62 vfswrap_statvfs,
64 /* Directory operations */
66 vfswrap_opendir,
67 vfswrap_readdir,
68 vfswrap_seekdir,
69 vfswrap_telldir,
70 vfswrap_rewinddir,
71 vfswrap_mkdir,
72 vfswrap_rmdir,
73 vfswrap_closedir,
75 /* File operations */
77 vfswrap_open,
78 vfswrap_close,
79 vfswrap_read,
80 vfswrap_pread,
81 vfswrap_write,
82 vfswrap_pwrite,
83 vfswrap_lseek,
84 vfswrap_sendfile,
85 vfswrap_rename,
86 vfswrap_fsync,
87 vfswrap_stat,
88 vfswrap_fstat,
89 vfswrap_lstat,
90 vfswrap_unlink,
91 vfswrap_chmod,
92 vfswrap_fchmod,
93 vfswrap_chown,
94 vfswrap_fchown,
95 vfswrap_chdir,
96 vfswrap_getwd,
97 vfswrap_utime,
98 vfswrap_ftruncate,
99 vfswrap_lock,
100 vfswrap_getlock,
101 vfswrap_symlink,
102 vfswrap_readlink,
103 vfswrap_link,
104 vfswrap_mknod,
105 vfswrap_realpath,
107 /* Windows ACL operations. */
108 vfswrap_fget_nt_acl,
109 vfswrap_get_nt_acl,
110 vfswrap_fset_nt_acl,
111 vfswrap_set_nt_acl,
113 /* POSIX ACL operations. */
114 vfswrap_chmod_acl,
115 vfswrap_fchmod_acl,
117 vfswrap_sys_acl_get_entry,
118 vfswrap_sys_acl_get_tag_type,
119 vfswrap_sys_acl_get_permset,
120 vfswrap_sys_acl_get_qualifier,
121 vfswrap_sys_acl_get_file,
122 vfswrap_sys_acl_get_fd,
123 vfswrap_sys_acl_clear_perms,
124 vfswrap_sys_acl_add_perm,
125 vfswrap_sys_acl_to_text,
126 vfswrap_sys_acl_init,
127 vfswrap_sys_acl_create_entry,
128 vfswrap_sys_acl_set_tag_type,
129 vfswrap_sys_acl_set_qualifier,
130 vfswrap_sys_acl_set_permset,
131 vfswrap_sys_acl_valid,
132 vfswrap_sys_acl_set_file,
133 vfswrap_sys_acl_set_fd,
134 vfswrap_sys_acl_delete_def_file,
135 vfswrap_sys_acl_get_perm,
136 vfswrap_sys_acl_free_text,
137 vfswrap_sys_acl_free_acl,
138 vfswrap_sys_acl_free_qualifier,
140 /* EA operations. */
141 vfswrap_getxattr,
142 vfswrap_lgetxattr,
143 vfswrap_fgetxattr,
144 vfswrap_listxattr,
145 vfswrap_llistxattr,
146 vfswrap_flistxattr,
147 vfswrap_removexattr,
148 vfswrap_lremovexattr,
149 vfswrap_fremovexattr,
150 vfswrap_setxattr,
151 vfswrap_lsetxattr,
152 vfswrap_fsetxattr,
154 /* AIO operations. */
155 vfswrap_aio_read,
156 vfswrap_aio_write,
157 vfswrap_aio_return,
158 vfswrap_aio_cancel,
159 vfswrap_aio_error,
160 vfswrap_aio_fsync,
161 vfswrap_aio_suspend
165 /****************************************************************************
166 maintain the list of available backends
167 ****************************************************************************/
169 static struct vfs_init_function_entry *vfs_find_backend_entry(const char *name)
171 struct vfs_init_function_entry *entry = backends;
173 while(entry) {
174 if (strcmp(entry->name, name)==0) return entry;
175 entry = entry->next;
178 return NULL;
181 NTSTATUS smb_register_vfs(int version, const char *name, vfs_op_tuple *vfs_op_tuples)
183 struct vfs_init_function_entry *entry = backends;
185 if ((version != SMB_VFS_INTERFACE_VERSION)) {
186 DEBUG(0, ("Failed to register vfs module.\n"
187 "The module was compiled against SMB_VFS_INTERFACE_VERSION %d,\n"
188 "current SMB_VFS_INTERFACE_VERSION is %d.\n"
189 "Please recompile against the current Samba Version!\n",
190 version, SMB_VFS_INTERFACE_VERSION));
191 return NT_STATUS_OBJECT_TYPE_MISMATCH;
194 if (!name || !name[0] || !vfs_op_tuples) {
195 DEBUG(0,("smb_register_vfs() called with NULL pointer or empty name!\n"));
196 return NT_STATUS_INVALID_PARAMETER;
199 if (vfs_find_backend_entry(name)) {
200 DEBUG(0,("VFS module %s already loaded!\n", name));
201 return NT_STATUS_OBJECT_NAME_COLLISION;
204 entry = SMB_XMALLOC_P(struct vfs_init_function_entry);
205 entry->name = smb_xstrdup(name);
206 entry->vfs_op_tuples = vfs_op_tuples;
208 DLIST_ADD(backends, entry);
209 DEBUG(5, ("Successfully added vfs backend '%s'\n", name));
210 return NT_STATUS_OK;
213 /****************************************************************************
214 initialise default vfs hooks
215 ****************************************************************************/
217 static void vfs_init_default(connection_struct *conn)
219 DEBUG(3, ("Initialising default vfs hooks\n"));
221 memcpy(&conn->vfs.ops, &default_vfs.ops, sizeof(default_vfs.ops));
222 memcpy(&conn->vfs_opaque.ops, &default_vfs.ops, sizeof(default_vfs.ops));
225 /****************************************************************************
226 initialise custom vfs hooks
227 ****************************************************************************/
229 BOOL vfs_init_custom(connection_struct *conn, const char *vfs_object)
231 vfs_op_tuple *ops;
232 char *module_name = NULL;
233 char *module_param = NULL, *p;
234 int i;
235 vfs_handle_struct *handle;
236 struct vfs_init_function_entry *entry;
238 if (!conn||!vfs_object||!vfs_object[0]) {
239 DEBUG(0,("vfs_init_custon() called with NULL pointer or emtpy vfs_object!\n"));
240 return False;
243 if(!backends) {
244 static_init_vfs;
247 DEBUG(3, ("Initialising custom vfs hooks from [%s]\n", vfs_object));
249 module_name = smb_xstrdup(vfs_object);
251 p = strchr_m(module_name, ':');
253 if (p) {
254 *p = 0;
255 module_param = p+1;
256 trim_char(module_param, ' ', ' ');
259 trim_char(module_name, ' ', ' ');
261 /* First, try to load the module with the new module system */
262 if((entry = vfs_find_backend_entry(module_name)) ||
263 (NT_STATUS_IS_OK(smb_probe_module("vfs", module_name)) &&
264 (entry = vfs_find_backend_entry(module_name)))) {
266 DEBUGADD(5,("Successfully loaded vfs module [%s] with the new modules system\n", vfs_object));
268 if ((ops = entry->vfs_op_tuples) == NULL) {
269 DEBUG(0, ("entry->vfs_op_tuples==NULL for [%s] failed\n", vfs_object));
270 SAFE_FREE(module_name);
271 return False;
273 } else {
274 DEBUG(0,("Can't find a vfs module [%s]\n",vfs_object));
275 SAFE_FREE(module_name);
276 return False;
279 handle = TALLOC_ZERO_P(conn->mem_ctx,vfs_handle_struct);
280 if (!handle) {
281 DEBUG(0,("talloc_zero() failed!\n"));
282 SAFE_FREE(module_name);
283 return False;
285 memcpy(&handle->vfs_next, &conn->vfs, sizeof(struct vfs_ops));
286 handle->conn = conn;
287 if (module_param) {
288 handle->param = talloc_strdup(conn->mem_ctx, module_param);
290 DLIST_ADD(conn->vfs_handles, handle);
292 for(i=0; ops[i].op != NULL; i++) {
293 DEBUG(5, ("Checking operation #%d (type %d, layer %d)\n", i, ops[i].type, ops[i].layer));
294 if(ops[i].layer == SMB_VFS_LAYER_OPAQUE) {
295 /* Check whether this operation was already made opaque by different module */
296 if(((void**)&conn->vfs_opaque.ops)[ops[i].type] == ((void**)&default_vfs.ops)[ops[i].type]) {
297 /* No, it isn't overloaded yet. Overload. */
298 DEBUGADD(5, ("Making operation type %d opaque [module %s]\n", ops[i].type, vfs_object));
299 ((void**)&conn->vfs_opaque.ops)[ops[i].type] = ops[i].op;
300 ((vfs_handle_struct **)&conn->vfs_opaque.handles)[ops[i].type] = handle;
303 /* Change current VFS disposition*/
304 DEBUGADD(5, ("Accepting operation type %d from module %s\n", ops[i].type, vfs_object));
305 ((void**)&conn->vfs.ops)[ops[i].type] = ops[i].op;
306 ((vfs_handle_struct **)&conn->vfs.handles)[ops[i].type] = handle;
309 SAFE_FREE(module_name);
310 return True;
313 /*****************************************************************
314 Generic VFS init.
315 ******************************************************************/
317 BOOL smbd_vfs_init(connection_struct *conn)
319 const char **vfs_objects;
320 unsigned int i = 0;
321 int j = 0;
323 /* Normal share - initialise with disk access functions */
324 vfs_init_default(conn);
325 vfs_objects = lp_vfs_objects(SNUM(conn));
327 /* Override VFS functions if 'vfs object' was not specified*/
328 if (!vfs_objects || !vfs_objects[0])
329 return True;
331 for (i=0; vfs_objects[i] ;) {
332 i++;
335 for (j=i-1; j >= 0; j--) {
336 if (!vfs_init_custom(conn, vfs_objects[j])) {
337 DEBUG(0, ("smbd_vfs_init: vfs_init_custom failed for %s\n", vfs_objects[j]));
338 return False;
341 return True;
344 /*******************************************************************
345 Check if directory exists.
346 ********************************************************************/
348 BOOL vfs_directory_exist(connection_struct *conn, const char *dname, SMB_STRUCT_STAT *st)
350 SMB_STRUCT_STAT st2;
351 BOOL ret;
353 if (!st)
354 st = &st2;
356 if (SMB_VFS_STAT(conn,dname,st) != 0)
357 return(False);
359 ret = S_ISDIR(st->st_mode);
360 if(!ret)
361 errno = ENOTDIR;
363 return ret;
366 /*******************************************************************
367 vfs mkdir wrapper
368 ********************************************************************/
370 int vfs_MkDir(connection_struct *conn, const char *name, mode_t mode)
372 int ret;
373 SMB_STRUCT_STAT sbuf;
375 if(!(ret=SMB_VFS_MKDIR(conn, name, mode))) {
377 inherit_access_acl(conn, name, mode);
380 * Check if high bits should have been set,
381 * then (if bits are missing): add them.
382 * Consider bits automagically set by UNIX, i.e. SGID bit from parent dir.
384 if(mode & ~(S_IRWXU|S_IRWXG|S_IRWXO) &&
385 !SMB_VFS_STAT(conn,name,&sbuf) && (mode & ~sbuf.st_mode))
386 SMB_VFS_CHMOD(conn,name,sbuf.st_mode | (mode & ~sbuf.st_mode));
388 return ret;
391 /*******************************************************************
392 Check if an object exists in the vfs.
393 ********************************************************************/
395 BOOL vfs_object_exist(connection_struct *conn,const char *fname,SMB_STRUCT_STAT *sbuf)
397 SMB_STRUCT_STAT st;
399 if (!sbuf)
400 sbuf = &st;
402 ZERO_STRUCTP(sbuf);
404 if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
405 return(False);
406 return True;
409 /*******************************************************************
410 Check if a file exists in the vfs.
411 ********************************************************************/
413 BOOL vfs_file_exist(connection_struct *conn, const char *fname,SMB_STRUCT_STAT *sbuf)
415 SMB_STRUCT_STAT st;
417 if (!sbuf)
418 sbuf = &st;
420 ZERO_STRUCTP(sbuf);
422 if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
423 return False;
424 return(S_ISREG(sbuf->st_mode));
427 /****************************************************************************
428 Read data from fsp on the vfs. (note: EINTR re-read differs from vfs_write_data)
429 ****************************************************************************/
431 ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count)
433 size_t total=0;
435 while (total < byte_count)
437 ssize_t ret = SMB_VFS_READ(fsp, fsp->fh->fd, buf + total,
438 byte_count - total);
440 if (ret == 0) return total;
441 if (ret == -1) {
442 if (errno == EINTR)
443 continue;
444 else
445 return -1;
447 total += ret;
449 return (ssize_t)total;
452 ssize_t vfs_pread_data(files_struct *fsp, char *buf,
453 size_t byte_count, SMB_OFF_T offset)
455 size_t total=0;
457 while (total < byte_count)
459 ssize_t ret = SMB_VFS_PREAD(fsp, fsp->fh->fd, buf + total,
460 byte_count - total, offset + total);
462 if (ret == 0) return total;
463 if (ret == -1) {
464 if (errno == EINTR)
465 continue;
466 else
467 return -1;
469 total += ret;
471 return (ssize_t)total;
474 /****************************************************************************
475 Write data to a fd on the vfs.
476 ****************************************************************************/
478 ssize_t vfs_write_data(files_struct *fsp,const char *buffer,size_t N)
480 size_t total=0;
481 ssize_t ret;
483 while (total < N) {
484 ret = SMB_VFS_WRITE(fsp,fsp->fh->fd,buffer + total,N - total);
486 if (ret == -1)
487 return -1;
488 if (ret == 0)
489 return total;
491 total += ret;
493 return (ssize_t)total;
496 ssize_t vfs_pwrite_data(files_struct *fsp,const char *buffer,
497 size_t N, SMB_OFF_T offset)
499 size_t total=0;
500 ssize_t ret;
502 while (total < N) {
503 ret = SMB_VFS_PWRITE(fsp, fsp->fh->fd, buffer + total,
504 N - total, offset + total);
506 if (ret == -1)
507 return -1;
508 if (ret == 0)
509 return total;
511 total += ret;
513 return (ssize_t)total;
515 /****************************************************************************
516 An allocate file space call using the vfs interface.
517 Allocates space for a file from a filedescriptor.
518 Returns 0 on success, -1 on failure.
519 ****************************************************************************/
521 int vfs_allocate_file_space(files_struct *fsp, SMB_BIG_UINT len)
523 int ret;
524 SMB_STRUCT_STAT st;
525 connection_struct *conn = fsp->conn;
526 SMB_BIG_UINT space_avail;
527 SMB_BIG_UINT bsize,dfree,dsize;
529 release_level_2_oplocks_on_change(fsp);
532 * Actually try and commit the space on disk....
535 DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", fsp->fsp_name, (double)len ));
537 if (((SMB_OFF_T)len) < 0) {
538 DEBUG(0,("vfs_allocate_file_space: %s negative len requested.\n", fsp->fsp_name ));
539 return -1;
542 ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st);
543 if (ret == -1)
544 return ret;
546 if (len == (SMB_BIG_UINT)st.st_size)
547 return 0;
549 if (len < (SMB_BIG_UINT)st.st_size) {
550 /* Shrink - use ftruncate. */
552 DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
553 fsp->fsp_name, (double)st.st_size ));
555 flush_write_cache(fsp, SIZECHANGE_FLUSH);
556 if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, (SMB_OFF_T)len)) != -1) {
557 set_filelen_write_cache(fsp, len);
559 return ret;
562 /* Grow - we need to test if we have enough space. */
564 if (!lp_strict_allocate(SNUM(fsp->conn)))
565 return 0;
567 len -= st.st_size;
568 len /= 1024; /* Len is now number of 1k blocks needed. */
569 space_avail = get_dfree_info(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize);
570 if (space_avail == (SMB_BIG_UINT)-1) {
571 return -1;
574 DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %.0f, space avail = %.0f\n",
575 fsp->fsp_name, (double)st.st_size, (double)len, (double)space_avail ));
577 if (len > space_avail) {
578 errno = ENOSPC;
579 return -1;
582 return 0;
585 /****************************************************************************
586 A vfs set_filelen call.
587 set the length of a file from a filedescriptor.
588 Returns 0 on success, -1 on failure.
589 ****************************************************************************/
591 int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
593 int ret;
595 release_level_2_oplocks_on_change(fsp);
596 DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len));
597 flush_write_cache(fsp, SIZECHANGE_FLUSH);
598 if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, len)) != -1)
599 set_filelen_write_cache(fsp, len);
601 return ret;
604 /****************************************************************************
605 A vfs fill sparse call.
606 Writes zeros from the end of file to len, if len is greater than EOF.
607 Used only by strict_sync.
608 Returns 0 on success, -1 on failure.
609 ****************************************************************************/
611 static char *sparse_buf;
612 #define SPARSE_BUF_WRITE_SIZE (32*1024)
614 int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len)
616 int ret;
617 SMB_STRUCT_STAT st;
618 SMB_OFF_T offset;
619 size_t total;
620 size_t num_to_write;
621 ssize_t pwrite_ret;
623 release_level_2_oplocks_on_change(fsp);
624 ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st);
625 if (ret == -1) {
626 return ret;
629 if (len <= st.st_size) {
630 return 0;
633 DEBUG(10,("vfs_fill_sparse: write zeros in file %s from len %.0f to len %.0f (%.0f bytes)\n",
634 fsp->fsp_name, (double)st.st_size, (double)len, (double)(len - st.st_size)));
636 flush_write_cache(fsp, SIZECHANGE_FLUSH);
638 if (!sparse_buf) {
639 sparse_buf = SMB_CALLOC_ARRAY(char, SPARSE_BUF_WRITE_SIZE);
640 if (!sparse_buf) {
641 errno = ENOMEM;
642 return -1;
646 offset = st.st_size;
647 num_to_write = len - st.st_size;
648 total = 0;
650 while (total < num_to_write) {
651 size_t curr_write_size = MIN(SPARSE_BUF_WRITE_SIZE, (num_to_write - total));
653 pwrite_ret = SMB_VFS_PWRITE(fsp, fsp->fh->fd, sparse_buf, curr_write_size, offset + total);
654 if (pwrite_ret == -1) {
655 DEBUG(10,("vfs_fill_sparse: SMB_VFS_PWRITE for file %s failed with error %s\n",
656 fsp->fsp_name, strerror(errno) ));
657 return -1;
659 if (pwrite_ret == 0) {
660 return 0;
663 total += pwrite_ret;
666 set_filelen_write_cache(fsp, len);
667 return 0;
670 /****************************************************************************
671 Transfer some data (n bytes) between two file_struct's.
672 ****************************************************************************/
674 static files_struct *in_fsp;
675 static files_struct *out_fsp;
677 static ssize_t read_fn(int fd, void *buf, size_t len)
679 return SMB_VFS_READ(in_fsp, fd, buf, len);
682 static ssize_t write_fn(int fd, const void *buf, size_t len)
684 return SMB_VFS_WRITE(out_fsp, fd, buf, len);
687 SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n)
689 in_fsp = in;
690 out_fsp = out;
692 return transfer_file_internal(in_fsp->fh->fd, out_fsp->fh->fd, n, read_fn, write_fn);
695 /*******************************************************************
696 A vfs_readdir wrapper which just returns the file name.
697 ********************************************************************/
699 char *vfs_readdirname(connection_struct *conn, void *p)
701 SMB_STRUCT_DIRENT *ptr= NULL;
702 char *dname;
704 if (!p)
705 return(NULL);
707 ptr = SMB_VFS_READDIR(conn,p);
708 if (!ptr)
709 return(NULL);
711 dname = ptr->d_name;
713 #ifdef NEXT2
714 if (telldir(p) < 0)
715 return(NULL);
716 #endif
718 #ifdef HAVE_BROKEN_READDIR_NAME
719 /* using /usr/ucb/cc is BAD */
720 dname = dname - 2;
721 #endif
723 return(dname);
726 /*******************************************************************
727 A wrapper for vfs_chdir().
728 ********************************************************************/
730 int vfs_ChDir(connection_struct *conn, const char *path)
732 int res;
733 static pstring LastDir="";
735 if (strcsequal(path,"."))
736 return(0);
738 if (*path == '/' && strcsequal(LastDir,path))
739 return(0);
741 DEBUG(4,("vfs_ChDir to %s\n",path));
743 res = SMB_VFS_CHDIR(conn,path);
744 if (!res)
745 pstrcpy(LastDir,path);
746 return(res);
749 /* number of list structures for a caching GetWd function. */
750 #define MAX_GETWDCACHE (50)
752 static struct {
753 SMB_DEV_T dev; /* These *must* be compatible with the types returned in a stat() call. */
754 SMB_INO_T inode; /* These *must* be compatible with the types returned in a stat() call. */
755 char *dos_path; /* The pathname in DOS format. */
756 BOOL valid;
757 } ino_list[MAX_GETWDCACHE];
759 extern BOOL use_getwd_cache;
761 /****************************************************************************
762 Prompte a ptr (to make it recently used)
763 ****************************************************************************/
765 static void array_promote(char *array,int elsize,int element)
767 char *p;
768 if (element == 0)
769 return;
771 p = (char *)SMB_MALLOC(elsize);
773 if (!p) {
774 DEBUG(5,("array_promote: malloc fail\n"));
775 return;
778 memcpy(p,array + element * elsize, elsize);
779 memmove(array + elsize,array,elsize*element);
780 memcpy(array,p,elsize);
781 SAFE_FREE(p);
784 /*******************************************************************
785 Return the absolute current directory path - given a UNIX pathname.
786 Note that this path is returned in DOS format, not UNIX
787 format. Note this can be called with conn == NULL.
788 ********************************************************************/
790 char *vfs_GetWd(connection_struct *conn, char *path)
792 pstring s;
793 static BOOL getwd_cache_init = False;
794 SMB_STRUCT_STAT st, st2;
795 int i;
797 *s = 0;
799 if (!use_getwd_cache)
800 return(SMB_VFS_GETWD(conn,path));
802 /* init the cache */
803 if (!getwd_cache_init) {
804 getwd_cache_init = True;
805 for (i=0;i<MAX_GETWDCACHE;i++) {
806 string_set(&ino_list[i].dos_path,"");
807 ino_list[i].valid = False;
811 /* Get the inode of the current directory, if this doesn't work we're
812 in trouble :-) */
814 if (SMB_VFS_STAT(conn, ".",&st) == -1) {
815 /* Known to fail for root: the directory may be
816 * NFS-mounted and exported with root_squash (so has no root access). */
817 DEBUG(1,("vfs_GetWd: couldn't stat \".\" path=%s error %s (NFS problem ?)\n", path, strerror(errno) ));
818 return(SMB_VFS_GETWD(conn,path));
822 for (i=0; i<MAX_GETWDCACHE; i++) {
823 if (ino_list[i].valid) {
825 /* If we have found an entry with a matching inode and dev number
826 then find the inode number for the directory in the cached string.
827 If this agrees with that returned by the stat for the current
828 directory then all is o.k. (but make sure it is a directory all
829 the same...) */
831 if (st.st_ino == ino_list[i].inode && st.st_dev == ino_list[i].dev) {
832 if (SMB_VFS_STAT(conn,ino_list[i].dos_path,&st2) == 0) {
833 if (st.st_ino == st2.st_ino && st.st_dev == st2.st_dev &&
834 (st2.st_mode & S_IFMT) == S_IFDIR) {
835 pstrcpy (path, ino_list[i].dos_path);
837 /* promote it for future use */
838 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
839 return (path);
840 } else {
841 /* If the inode is different then something's changed,
842 scrub the entry and start from scratch. */
843 ino_list[i].valid = False;
850 /* We don't have the information to hand so rely on traditional methods.
851 The very slow getcwd, which spawns a process on some systems, or the
852 not quite so bad getwd. */
854 if (!SMB_VFS_GETWD(conn,s)) {
855 DEBUG(0,("vfs_GetWd: SMB_VFS_GETWD call failed, errno %s\n",strerror(errno)));
856 return (NULL);
859 pstrcpy(path,s);
861 DEBUG(5,("vfs_GetWd %s, inode %.0f, dev %.0f\n",s,(double)st.st_ino,(double)st.st_dev));
863 /* add it to the cache */
864 i = MAX_GETWDCACHE - 1;
865 string_set(&ino_list[i].dos_path,s);
866 ino_list[i].dev = st.st_dev;
867 ino_list[i].inode = st.st_ino;
868 ino_list[i].valid = True;
870 /* put it at the top of the list */
871 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
873 return (path);
876 BOOL canonicalize_path(connection_struct *conn, pstring path)
878 #ifdef REALPATH_TAKES_NULL
879 char *resolved_name = SMB_VFS_REALPATH(conn,path,NULL);
880 if (!resolved_name) {
881 return False;
883 pstrcpy(path, resolved_name);
884 SAFE_FREE(resolved_name);
885 return True;
886 #else
887 #ifdef PATH_MAX
888 char resolved_name_buf[PATH_MAX+1];
889 #else
890 pstring resolved_name_buf;
891 #endif
892 char *resolved_name = SMB_VFS_REALPATH(conn,path,resolved_name_buf);
893 if (!resolved_name) {
894 return False;
896 pstrcpy(path, resolved_name);
897 return True;
898 #endif /* REALPATH_TAKES_NULL */
901 /*******************************************************************
902 Reduce a file name, removing .. elements and checking that
903 it is below dir in the heirachy. This uses realpath.
904 ********************************************************************/
906 BOOL reduce_name(connection_struct *conn, const pstring fname)
908 #ifdef REALPATH_TAKES_NULL
909 BOOL free_resolved_name = True;
910 #else
911 #ifdef PATH_MAX
912 char resolved_name_buf[PATH_MAX+1];
913 #else
914 pstring resolved_name_buf;
915 #endif
916 BOOL free_resolved_name = False;
917 #endif
918 char *resolved_name = NULL;
919 size_t con_path_len = strlen(conn->connectpath);
920 char *p = NULL;
921 int saved_errno = errno;
923 DEBUG(3,("reduce_name [%s] [%s]\n", fname, conn->connectpath));
925 #ifdef REALPATH_TAKES_NULL
926 resolved_name = SMB_VFS_REALPATH(conn,fname,NULL);
927 #else
928 resolved_name = SMB_VFS_REALPATH(conn,fname,resolved_name_buf);
929 #endif
931 if (!resolved_name) {
932 switch (errno) {
933 case ENOTDIR:
934 DEBUG(3,("reduce_name: Component not a directory in getting realpath for %s\n", fname));
935 errno = saved_errno;
936 return False;
937 case ENOENT:
939 pstring tmp_fname;
940 fstring last_component;
941 /* Last component didn't exist. Remove it and try and canonicalise the directory. */
943 pstrcpy(tmp_fname, fname);
944 p = strrchr_m(tmp_fname, '/');
945 if (p) {
946 *p++ = '\0';
947 fstrcpy(last_component, p);
948 } else {
949 fstrcpy(last_component, tmp_fname);
950 pstrcpy(tmp_fname, ".");
953 #ifdef REALPATH_TAKES_NULL
954 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,NULL);
955 #else
956 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,resolved_name_buf);
957 #endif
958 if (!resolved_name) {
959 DEBUG(3,("reduce_name: couldn't get realpath for %s\n", fname));
960 errno = saved_errno;
961 return False;
963 pstrcpy(tmp_fname, resolved_name);
964 pstrcat(tmp_fname, "/");
965 pstrcat(tmp_fname, last_component);
966 #ifdef REALPATH_TAKES_NULL
967 SAFE_FREE(resolved_name);
968 resolved_name = SMB_STRDUP(tmp_fname);
969 if (!resolved_name) {
970 DEBUG(0,("reduce_name: malloc fail for %s\n", tmp_fname));
971 errno = saved_errno;
972 return False;
974 #else
975 #ifdef PATH_MAX
976 safe_strcpy(resolved_name_buf, tmp_fname, PATH_MAX);
977 #else
978 pstrcpy(resolved_name_buf, tmp_fname);
979 #endif
980 resolved_name = resolved_name_buf;
981 #endif
982 break;
984 default:
985 DEBUG(1,("reduce_name: couldn't get realpath for %s\n", fname));
986 /* Don't restore the saved errno. We need to return the error that
987 realpath caused here as it was not one of the cases we handle. JRA. */
988 return False;
992 DEBUG(10,("reduce_name realpath [%s] -> [%s]\n", fname, resolved_name));
994 if (*resolved_name != '/') {
995 DEBUG(0,("reduce_name: realpath doesn't return absolute paths !\n"));
996 if (free_resolved_name)
997 SAFE_FREE(resolved_name);
998 errno = saved_errno;
999 return False;
1002 /* Check for widelinks allowed. */
1003 if (!lp_widelinks(SNUM(conn)) && (strncmp(conn->connectpath, resolved_name, con_path_len) != 0)) {
1004 DEBUG(2, ("reduce_name: Bad access attempt: %s is a symlink outside the share path", fname));
1005 if (free_resolved_name)
1006 SAFE_FREE(resolved_name);
1007 errno = EACCES;
1008 return False;
1011 /* Check if we are allowing users to follow symlinks */
1012 /* Patch from David Clerc <David.Clerc@cui.unige.ch>
1013 University of Geneva */
1015 #ifdef S_ISLNK
1016 if (!lp_symlinks(SNUM(conn))) {
1017 SMB_STRUCT_STAT statbuf;
1018 if ( (SMB_VFS_LSTAT(conn,fname,&statbuf) != -1) &&
1019 (S_ISLNK(statbuf.st_mode)) ) {
1020 if (free_resolved_name)
1021 SAFE_FREE(resolved_name);
1022 DEBUG(3,("reduce_name: denied: file path name %s is a symlink\n",resolved_name));
1023 errno = EACCES;
1024 return False;
1027 #endif
1029 DEBUG(3,("reduce_name: %s reduced to %s\n", fname, resolved_name));
1030 if (free_resolved_name)
1031 SAFE_FREE(resolved_name);
1032 errno = saved_errno;
1033 return(True);