r6284: Starting on 3.0.14:
[Samba.git] / source / smbd / vfs.c
blob28441c91abc970309677a77dac9a769621808da1
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 struct vfs_init_function_entry {
31 char *name;
32 vfs_op_tuple *vfs_op_tuples;
33 struct vfs_init_function_entry *prev, *next;
36 static struct vfs_init_function_entry *backends = NULL;
38 /* Some structures to help us initialise the vfs operations table */
40 struct vfs_syminfo {
41 char *name;
42 void *fptr;
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. */
49 static struct vfs_ops default_vfs = {
52 /* Disk operations */
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,
61 /* Directory operations */
63 vfswrap_opendir,
64 vfswrap_readdir,
65 vfswrap_seekdir,
66 vfswrap_telldir,
67 vfswrap_rewinddir,
68 vfswrap_mkdir,
69 vfswrap_rmdir,
70 vfswrap_closedir,
72 /* File operations */
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,
103 /* Windows ACL operations. */
104 vfswrap_fget_nt_acl,
105 vfswrap_get_nt_acl,
106 vfswrap_fset_nt_acl,
107 vfswrap_set_nt_acl,
109 /* POSIX ACL operations. */
110 vfswrap_chmod_acl,
111 vfswrap_fchmod_acl,
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,
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
152 /****************************************************************************
153 maintain the list of available backends
154 ****************************************************************************/
156 static struct vfs_init_function_entry *vfs_find_backend_entry(const char *name)
158 struct vfs_init_function_entry *entry = backends;
160 while(entry) {
161 if (strcmp(entry->name, name)==0) return entry;
162 entry = entry->next;
165 return NULL;
168 NTSTATUS smb_register_vfs(int version, const char *name, vfs_op_tuple *vfs_op_tuples)
170 struct vfs_init_function_entry *entry = backends;
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;
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;
186 if (vfs_find_backend_entry(name)) {
187 DEBUG(0,("VFS module %s already loaded!\n", name));
188 return NT_STATUS_OBJECT_NAME_COLLISION;
191 entry = SMB_XMALLOC_P(struct vfs_init_function_entry);
192 entry->name = smb_xstrdup(name);
193 entry->vfs_op_tuples = vfs_op_tuples;
195 DLIST_ADD(backends, entry);
196 DEBUG(5, ("Successfully added vfs backend '%s'\n", name));
197 return NT_STATUS_OK;
200 /****************************************************************************
201 initialise default vfs hooks
202 ****************************************************************************/
204 static void vfs_init_default(connection_struct *conn)
206 DEBUG(3, ("Initialising default vfs hooks\n"));
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));
212 /****************************************************************************
213 initialise custom vfs hooks
214 ****************************************************************************/
216 BOOL vfs_init_custom(connection_struct *conn, const char *vfs_object)
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;
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;
230 if(!backends) static_init_vfs;
232 DEBUG(3, ("Initialising custom vfs hooks from [%s]\n", vfs_object));
234 module_name = smb_xstrdup(vfs_object);
236 p = strchr(module_name, ':');
238 if (p) {
239 *p = 0;
240 module_param = p+1;
241 trim_char(module_param, ' ', ' ');
244 trim_char(module_name, ' ', ' ');
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)))) {
251 DEBUGADD(5,("Successfully loaded vfs module [%s] with the new modules system\n", vfs_object));
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;
258 } else {
259 DEBUG(0,("Can't find a vfs module [%s]\n",vfs_object));
260 SAFE_FREE(module_name);
261 return False;
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;
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);
275 DLIST_ADD(conn->vfs_handles, handle);
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;
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;
294 SAFE_FREE(module_name);
295 return True;
298 /*****************************************************************
299 Generic VFS init.
300 ******************************************************************/
302 BOOL smbd_vfs_init(connection_struct *conn)
304 const char **vfs_objects;
305 unsigned int i = 0;
306 int j = 0;
308 /* Normal share - initialise with disk access functions */
309 vfs_init_default(conn);
310 vfs_objects = lp_vfs_objects(SNUM(conn));
312 /* Override VFS functions if 'vfs object' was not specified*/
313 if (!vfs_objects || !vfs_objects[0])
314 return True;
316 for (i=0; vfs_objects[i] ;) {
317 i++;
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;
326 return True;
329 /*******************************************************************
330 Check if directory exists.
331 ********************************************************************/
333 BOOL vfs_directory_exist(connection_struct *conn, const char *dname, SMB_STRUCT_STAT *st)
335 SMB_STRUCT_STAT st2;
336 BOOL ret;
338 if (!st)
339 st = &st2;
341 if (SMB_VFS_STAT(conn,dname,st) != 0)
342 return(False);
344 ret = S_ISDIR(st->st_mode);
345 if(!ret)
346 errno = ENOTDIR;
348 return ret;
351 /*******************************************************************
352 vfs mkdir wrapper
353 ********************************************************************/
355 int vfs_MkDir(connection_struct *conn, const char *name, mode_t mode)
357 int ret;
358 SMB_STRUCT_STAT sbuf;
360 if(!(ret=SMB_VFS_MKDIR(conn, name, mode))) {
362 inherit_access_acl(conn, name, mode);
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.
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));
373 return ret;
376 /*******************************************************************
377 Check if an object exists in the vfs.
378 ********************************************************************/
380 BOOL vfs_object_exist(connection_struct *conn,const char *fname,SMB_STRUCT_STAT *sbuf)
382 SMB_STRUCT_STAT st;
384 if (!sbuf)
385 sbuf = &st;
387 ZERO_STRUCTP(sbuf);
389 if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
390 return(False);
391 return True;
394 /*******************************************************************
395 Check if a file exists in the vfs.
396 ********************************************************************/
398 BOOL vfs_file_exist(connection_struct *conn, const char *fname,SMB_STRUCT_STAT *sbuf)
400 SMB_STRUCT_STAT st;
402 if (!sbuf)
403 sbuf = &st;
405 ZERO_STRUCTP(sbuf);
407 if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
408 return False;
409 return(S_ISREG(sbuf->st_mode));
412 /****************************************************************************
413 Read data from fsp on the vfs. (note: EINTR re-read differs from vfs_write_data)
414 ****************************************************************************/
416 ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count)
418 size_t total=0;
420 while (total < byte_count)
422 ssize_t ret = SMB_VFS_READ(fsp, fsp->fd, buf + total,
423 byte_count - total);
425 if (ret == 0) return total;
426 if (ret == -1) {
427 if (errno == EINTR)
428 continue;
429 else
430 return -1;
432 total += ret;
434 return (ssize_t)total;
437 ssize_t vfs_pread_data(files_struct *fsp, char *buf,
438 size_t byte_count, SMB_OFF_T offset)
440 size_t total=0;
442 while (total < byte_count)
444 ssize_t ret = SMB_VFS_PREAD(fsp, fsp->fd, buf + total,
445 byte_count - total, offset + total);
447 if (ret == 0) return total;
448 if (ret == -1) {
449 if (errno == EINTR)
450 continue;
451 else
452 return -1;
454 total += ret;
456 return (ssize_t)total;
459 /****************************************************************************
460 Write data to a fd on the vfs.
461 ****************************************************************************/
463 ssize_t vfs_write_data(files_struct *fsp,const char *buffer,size_t N)
465 size_t total=0;
466 ssize_t ret;
468 while (total < N) {
469 ret = SMB_VFS_WRITE(fsp,fsp->fd,buffer + total,N - total);
471 if (ret == -1)
472 return -1;
473 if (ret == 0)
474 return total;
476 total += ret;
478 return (ssize_t)total;
481 ssize_t vfs_pwrite_data(files_struct *fsp,const char *buffer,
482 size_t N, SMB_OFF_T offset)
484 size_t total=0;
485 ssize_t ret;
487 while (total < N) {
488 ret = SMB_VFS_PWRITE(fsp, fsp->fd, buffer + total,
489 N - total, offset + total);
491 if (ret == -1)
492 return -1;
493 if (ret == 0)
494 return total;
496 total += ret;
498 return (ssize_t)total;
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 ****************************************************************************/
506 int vfs_allocate_file_space(files_struct *fsp, SMB_BIG_UINT len)
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;
514 release_level_2_oplocks_on_change(fsp);
517 * Actually try and commit the space on disk....
520 DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", fsp->fsp_name, (double)len ));
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;
527 ret = SMB_VFS_FSTAT(fsp,fsp->fd,&st);
528 if (ret == -1)
529 return ret;
531 if (len == (SMB_BIG_UINT)st.st_size)
532 return 0;
534 if (len < (SMB_BIG_UINT)st.st_size) {
535 /* Shrink - use ftruncate. */
537 DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
538 fsp->fsp_name, (double)st.st_size ));
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);
544 return ret;
547 /* Grow - we need to test if we have enough space. */
549 if (!lp_strict_allocate(SNUM(fsp->conn)))
550 return 0;
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;
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 ));
562 if (len > space_avail) {
563 errno = ENOSPC;
564 return -1;
567 return 0;
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 ****************************************************************************/
576 int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
578 int ret;
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);
586 return ret;
589 /****************************************************************************
590 Transfer some data (n bytes) between two file_struct's.
591 ****************************************************************************/
593 static files_struct *in_fsp;
594 static files_struct *out_fsp;
596 static ssize_t read_fn(int fd, void *buf, size_t len)
598 return SMB_VFS_READ(in_fsp, fd, buf, len);
601 static ssize_t write_fn(int fd, const void *buf, size_t len)
603 return SMB_VFS_WRITE(out_fsp, fd, buf, len);
606 SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n)
608 in_fsp = in;
609 out_fsp = out;
611 return transfer_file_internal(in_fsp->fd, out_fsp->fd, n, read_fn, write_fn);
614 /*******************************************************************
615 A vfs_readdir wrapper which just returns the file name.
616 ********************************************************************/
618 char *vfs_readdirname(connection_struct *conn, void *p)
620 SMB_STRUCT_DIRENT *ptr= NULL;
621 char *dname;
623 if (!p)
624 return(NULL);
626 ptr = SMB_VFS_READDIR(conn,p);
627 if (!ptr)
628 return(NULL);
630 dname = ptr->d_name;
632 #ifdef NEXT2
633 if (telldir(p) < 0)
634 return(NULL);
635 #endif
637 #ifdef HAVE_BROKEN_READDIR
638 /* using /usr/ucb/cc is BAD */
639 dname = dname - 2;
640 #endif
642 return(dname);
645 /*******************************************************************
646 A wrapper for vfs_chdir().
647 ********************************************************************/
649 int vfs_ChDir(connection_struct *conn, const char *path)
651 int res;
652 static pstring LastDir="";
654 if (strcsequal(path,"."))
655 return(0);
657 if (*path == '/' && strcsequal(LastDir,path))
658 return(0);
660 DEBUG(4,("vfs_ChDir to %s\n",path));
662 res = SMB_VFS_CHDIR(conn,path);
663 if (!res)
664 pstrcpy(LastDir,path);
665 return(res);
668 /* number of list structures for a caching GetWd function. */
669 #define MAX_GETWDCACHE (50)
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];
678 extern BOOL use_getwd_cache;
680 /****************************************************************************
681 Prompte a ptr (to make it recently used)
682 ****************************************************************************/
684 static void array_promote(char *array,int elsize,int element)
686 char *p;
687 if (element == 0)
688 return;
690 p = (char *)SMB_MALLOC(elsize);
692 if (!p) {
693 DEBUG(5,("array_promote: malloc fail\n"));
694 return;
697 memcpy(p,array + element * elsize, elsize);
698 memmove(array + elsize,array,elsize*element);
699 memcpy(array,p,elsize);
700 SAFE_FREE(p);
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 ********************************************************************/
709 char *vfs_GetWd(connection_struct *conn, char *path)
711 pstring s;
712 static BOOL getwd_cache_init = False;
713 SMB_STRUCT_STAT st, st2;
714 int i;
716 *s = 0;
718 if (!use_getwd_cache)
719 return(SMB_VFS_GETWD(conn,path));
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;
730 /* Get the inode of the current directory, if this doesn't work we're
731 in trouble :-) */
733 if (SMB_VFS_STAT(conn, ".",&st) == -1) {
734 /* Known to fail for root: the directory may be
735 * NFS-mounted and exported with root_squash (so has no root access). */
736 DEBUG(1,("vfs_GetWd: couldn't stat \".\" path=%s error %s (NFS problem ?)\n", path, strerror(errno) ));
737 return(SMB_VFS_GETWD(conn,path));
741 for (i=0; i<MAX_GETWDCACHE; i++) {
742 if (ino_list[i].valid) {
744 /* If we have found an entry with a matching inode and dev number
745 then find the inode number for the directory in the cached string.
746 If this agrees with that returned by the stat for the current
747 directory then all is o.k. (but make sure it is a directory all
748 the same...) */
750 if (st.st_ino == ino_list[i].inode && st.st_dev == ino_list[i].dev) {
751 if (SMB_VFS_STAT(conn,ino_list[i].dos_path,&st2) == 0) {
752 if (st.st_ino == st2.st_ino && st.st_dev == st2.st_dev &&
753 (st2.st_mode & S_IFMT) == S_IFDIR) {
754 pstrcpy (path, ino_list[i].dos_path);
756 /* promote it for future use */
757 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
758 return (path);
759 } else {
760 /* If the inode is different then something's changed,
761 scrub the entry and start from scratch. */
762 ino_list[i].valid = False;
769 /* We don't have the information to hand so rely on traditional methods.
770 The very slow getcwd, which spawns a process on some systems, or the
771 not quite so bad getwd. */
773 if (!SMB_VFS_GETWD(conn,s)) {
774 DEBUG(0,("vfs_GetWd: SMB_VFS_GETWD call failed, errno %s\n",strerror(errno)));
775 return (NULL);
778 pstrcpy(path,s);
780 DEBUG(5,("vfs_GetWd %s, inode %.0f, dev %.0f\n",s,(double)st.st_ino,(double)st.st_dev));
782 /* add it to the cache */
783 i = MAX_GETWDCACHE - 1;
784 string_set(&ino_list[i].dos_path,s);
785 ino_list[i].dev = st.st_dev;
786 ino_list[i].inode = st.st_ino;
787 ino_list[i].valid = True;
789 /* put it at the top of the list */
790 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
792 return (path);
795 BOOL canonicalize_path(connection_struct *conn, pstring path)
797 #ifdef REALPATH_TAKES_NULL
798 char *resolved_name = SMB_VFS_REALPATH(conn,path,NULL);
799 if (!resolved_name) {
800 return False;
802 pstrcpy(path, resolved_name);
803 SAFE_FREE(resolved_name);
804 return True;
805 #else
806 #ifdef PATH_MAX
807 char resolved_name_buf[PATH_MAX+1];
808 #else
809 pstring resolved_name_buf;
810 #endif
811 char *resolved_name = SMB_VFS_REALPATH(conn,path,resolved_name_buf);
812 if (!resolved_name) {
813 return False;
815 pstrcpy(path, resolved_name);
816 return True;
817 #endif /* REALPATH_TAKES_NULL */
820 /*******************************************************************
821 Reduce a file name, removing .. elements and checking that
822 it is below dir in the heirachy. This uses realpath.
823 ********************************************************************/
825 BOOL reduce_name(connection_struct *conn, const pstring fname)
827 #ifdef REALPATH_TAKES_NULL
828 BOOL free_resolved_name = True;
829 #else
830 #ifdef PATH_MAX
831 char resolved_name_buf[PATH_MAX+1];
832 #else
833 pstring resolved_name_buf;
834 #endif
835 BOOL free_resolved_name = False;
836 #endif
837 char *resolved_name = NULL;
838 size_t con_path_len = strlen(conn->connectpath);
839 char *p = NULL;
840 int saved_errno = errno;
842 DEBUG(3,("reduce_name [%s] [%s]\n", fname, conn->connectpath));
844 #ifdef REALPATH_TAKES_NULL
845 resolved_name = SMB_VFS_REALPATH(conn,fname,NULL);
846 #else
847 resolved_name = SMB_VFS_REALPATH(conn,fname,resolved_name_buf);
848 #endif
850 if (!resolved_name) {
851 switch (errno) {
852 case ENOTDIR:
853 DEBUG(3,("reduce_name: Component not a directory in getting realpath for %s\n", fname));
854 errno = saved_errno;
855 return False;
856 case ENOENT:
858 pstring tmp_fname;
859 fstring last_component;
860 /* Last component didn't exist. Remove it and try and canonicalise the directory. */
862 pstrcpy(tmp_fname, fname);
863 p = strrchr_m(tmp_fname, '/');
864 if (p) {
865 *p++ = '\0';
866 fstrcpy(last_component, p);
867 } else {
868 fstrcpy(last_component, tmp_fname);
869 pstrcpy(tmp_fname, ".");
872 #ifdef REALPATH_TAKES_NULL
873 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,NULL);
874 #else
875 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,resolved_name_buf);
876 #endif
877 if (!resolved_name) {
878 DEBUG(3,("reduce_name: couldn't get realpath for %s\n", fname));
879 errno = saved_errno;
880 return False;
882 pstrcpy(tmp_fname, resolved_name);
883 pstrcat(tmp_fname, "/");
884 pstrcat(tmp_fname, last_component);
885 #ifdef REALPATH_TAKES_NULL
886 SAFE_FREE(resolved_name);
887 resolved_name = SMB_STRDUP(tmp_fname);
888 if (!resolved_name) {
889 DEBUG(0,("reduce_name: malloc fail for %s\n", tmp_fname));
890 errno = saved_errno;
891 return False;
893 #else
894 #ifdef PATH_MAX
895 safe_strcpy(resolved_name_buf, tmp_fname, PATH_MAX);
896 #else
897 pstrcpy(pstring resolved_name_buf, tmp_fname);
898 #endif
899 resolved_name = resolved_name_buf;
900 #endif
901 break;
903 default:
904 DEBUG(1,("reduce_name: couldn't get realpath for %s\n", fname));
905 /* Don't restore the saved errno. We need to return the error that
906 realpath caused here as it was not one of the cases we handle. JRA. */
907 return False;
911 DEBUG(10,("reduce_name realpath [%s] -> [%s]\n", fname, resolved_name));
913 if (*resolved_name != '/') {
914 DEBUG(0,("reduce_name: realpath doesn't return absolute paths !\n"));
915 if (free_resolved_name)
916 SAFE_FREE(resolved_name);
917 errno = saved_errno;
918 return False;
921 /* Check for widelinks allowed. */
922 if (!lp_widelinks(SNUM(conn)) && (strncmp(conn->connectpath, resolved_name, con_path_len) != 0)) {
923 DEBUG(2, ("reduce_name: Bad access attempt: %s is a symlink outside the share path", fname));
924 if (free_resolved_name)
925 SAFE_FREE(resolved_name);
926 errno = EACCES;
927 return False;
930 /* Check if we are allowing users to follow symlinks */
931 /* Patch from David Clerc <David.Clerc@cui.unige.ch>
932 University of Geneva */
934 #ifdef S_ISLNK
935 if (!lp_symlinks(SNUM(conn))) {
936 SMB_STRUCT_STAT statbuf;
937 if ( (SMB_VFS_LSTAT(conn,fname,&statbuf) != -1) &&
938 (S_ISLNK(statbuf.st_mode)) ) {
939 if (free_resolved_name)
940 SAFE_FREE(resolved_name);
941 DEBUG(3,("reduce_name: denied: file path name %s is a symlink\n",resolved_name));
942 errno = EACCES;
943 return False;
946 #endif
948 DEBUG(3,("reduce_name: %s reduced to %s\n", fname, resolved_name));
949 if (free_resolved_name)
950 SAFE_FREE(resolved_name);
951 errno = saved_errno;
952 return(True);