r20837: Use real type name, to fix compilation with -WC++-compat
[Samba.git] / source / smbd / vfs.c
bloba4ecff921af665142b4b49712c27dda9aa719030
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
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
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.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 This work was sponsored by Optifacio Software Services, Inc.
26 #include "includes.h"
28 #undef DBGC_CLASS
29 #define DBGC_CLASS DBGC_VFS
31 static_decl_vfs;
33 struct vfs_init_function_entry {
34 char *name;
35 vfs_op_tuple *vfs_op_tuples;
36 struct vfs_init_function_entry *prev, *next;
39 static struct vfs_init_function_entry *backends = NULL;
41 /****************************************************************************
42 maintain the list of available backends
43 ****************************************************************************/
45 static struct vfs_init_function_entry *vfs_find_backend_entry(const char *name)
47 struct vfs_init_function_entry *entry = backends;
49 while(entry) {
50 if (strcmp(entry->name, name)==0) return entry;
51 entry = entry->next;
54 return NULL;
57 NTSTATUS smb_register_vfs(int version, const char *name, vfs_op_tuple *vfs_op_tuples)
59 struct vfs_init_function_entry *entry = backends;
61 if ((version != SMB_VFS_INTERFACE_VERSION)) {
62 DEBUG(0, ("Failed to register vfs module.\n"
63 "The module was compiled against SMB_VFS_INTERFACE_VERSION %d,\n"
64 "current SMB_VFS_INTERFACE_VERSION is %d.\n"
65 "Please recompile against the current Samba Version!\n",
66 version, SMB_VFS_INTERFACE_VERSION));
67 return NT_STATUS_OBJECT_TYPE_MISMATCH;
70 if (!name || !name[0] || !vfs_op_tuples) {
71 DEBUG(0,("smb_register_vfs() called with NULL pointer or empty name!\n"));
72 return NT_STATUS_INVALID_PARAMETER;
75 if (vfs_find_backend_entry(name)) {
76 DEBUG(0,("VFS module %s already loaded!\n", name));
77 return NT_STATUS_OBJECT_NAME_COLLISION;
80 entry = SMB_XMALLOC_P(struct vfs_init_function_entry);
81 entry->name = smb_xstrdup(name);
82 entry->vfs_op_tuples = vfs_op_tuples;
84 DLIST_ADD(backends, entry);
85 DEBUG(5, ("Successfully added vfs backend '%s'\n", name));
86 return NT_STATUS_OK;
89 /****************************************************************************
90 initialise default vfs hooks
91 ****************************************************************************/
93 static void vfs_init_default(connection_struct *conn)
95 DEBUG(3, ("Initialising default vfs hooks\n"));
96 vfs_init_custom(conn, DEFAULT_VFS_MODULE_NAME);
99 /****************************************************************************
100 initialise custom vfs hooks
101 ****************************************************************************/
103 static inline void vfs_set_operation(struct vfs_ops * vfs, vfs_op_type which,
104 struct vfs_handle_struct * handle, void * op)
106 ((struct vfs_handle_struct **)&vfs->handles)[which] = handle;
107 ((void **)(void *)&vfs->ops)[which] = op;
110 BOOL vfs_init_custom(connection_struct *conn, const char *vfs_object)
112 vfs_op_tuple *ops;
113 char *module_name = NULL;
114 char *module_param = NULL, *p;
115 int i;
116 vfs_handle_struct *handle;
117 struct vfs_init_function_entry *entry;
119 if (!conn||!vfs_object||!vfs_object[0]) {
120 DEBUG(0,("vfs_init_custon() called with NULL pointer or emtpy vfs_object!\n"));
121 return False;
124 if(!backends) {
125 static_init_vfs;
128 DEBUG(3, ("Initialising custom vfs hooks from [%s]\n", vfs_object));
130 module_name = smb_xstrdup(vfs_object);
132 p = strchr_m(module_name, ':');
134 if (p) {
135 *p = 0;
136 module_param = p+1;
137 trim_char(module_param, ' ', ' ');
140 trim_char(module_name, ' ', ' ');
142 /* First, try to load the module with the new module system */
143 if((entry = vfs_find_backend_entry(module_name)) ||
144 (NT_STATUS_IS_OK(smb_probe_module("vfs", module_name)) &&
145 (entry = vfs_find_backend_entry(module_name)))) {
147 DEBUGADD(5,("Successfully loaded vfs module [%s] with the new modules system\n", vfs_object));
149 if ((ops = entry->vfs_op_tuples) == NULL) {
150 DEBUG(0, ("entry->vfs_op_tuples==NULL for [%s] failed\n", vfs_object));
151 SAFE_FREE(module_name);
152 return False;
154 } else {
155 DEBUG(0,("Can't find a vfs module [%s]\n",vfs_object));
156 SAFE_FREE(module_name);
157 return False;
160 handle = TALLOC_ZERO_P(conn->mem_ctx,vfs_handle_struct);
161 if (!handle) {
162 DEBUG(0,("talloc_zero() failed!\n"));
163 SAFE_FREE(module_name);
164 return False;
166 memcpy(&handle->vfs_next, &conn->vfs, sizeof(struct vfs_ops));
167 handle->conn = conn;
168 if (module_param) {
169 handle->param = talloc_strdup(conn->mem_ctx, module_param);
171 DLIST_ADD(conn->vfs_handles, handle);
173 for(i=0; ops[i].op != NULL; i++) {
174 DEBUG(5, ("Checking operation #%d (type %d, layer %d)\n", i, ops[i].type, ops[i].layer));
175 if(ops[i].layer == SMB_VFS_LAYER_OPAQUE) {
176 /* If this operation was already made opaque by different module, it
177 * will be overridded here.
179 DEBUGADD(5, ("Making operation type %d opaque [module %s]\n", ops[i].type, vfs_object));
180 vfs_set_operation(&conn->vfs_opaque, ops[i].type, handle, ops[i].op);
182 /* Change current VFS disposition*/
183 DEBUGADD(5, ("Accepting operation type %d from module %s\n", ops[i].type, vfs_object));
184 vfs_set_operation(&conn->vfs, ops[i].type, handle, ops[i].op);
187 SAFE_FREE(module_name);
188 return True;
191 /*****************************************************************
192 Allow VFS modules to extend files_struct with VFS-specific state.
193 This will be ok for small numbers of extensions, but might need to
194 be refactored if it becomes more widely used.
195 ******************************************************************/
197 #define EXT_DATA_AREA(e) ((uint8 *)(e) + sizeof(struct vfs_fsp_data))
199 void *vfs_add_fsp_extension_notype(vfs_handle_struct *handle, files_struct *fsp, size_t ext_size)
201 struct vfs_fsp_data *ext;
202 void * ext_data;
204 /* Prevent VFS modules adding multiple extensions. */
205 if ((ext_data = vfs_fetch_fsp_extension(handle, fsp))) {
206 return ext_data;
209 ext = (struct vfs_fsp_data *)TALLOC_ZERO(
210 handle->conn->mem_ctx, sizeof(struct vfs_fsp_data) + ext_size);
211 if (ext == NULL) {
212 return NULL;
215 ext->owner = handle;
216 ext->next = fsp->vfs_extension;
217 fsp->vfs_extension = ext;
218 return EXT_DATA_AREA(ext);
221 void vfs_remove_fsp_extension(vfs_handle_struct *handle, files_struct *fsp)
223 struct vfs_fsp_data *curr;
224 struct vfs_fsp_data *prev;
226 for (curr = fsp->vfs_extension, prev = NULL;
227 curr;
228 prev = curr, curr = curr->next) {
229 if (curr->owner == handle) {
230 if (prev) {
231 prev->next = curr->next;
232 } else {
233 fsp->vfs_extension = curr->next;
235 TALLOC_FREE(curr);
236 return;
241 void *vfs_fetch_fsp_extension(vfs_handle_struct *handle, files_struct *fsp)
243 struct vfs_fsp_data *head;
245 for (head = fsp->vfs_extension; head; head = head->next) {
246 if (head->owner == handle) {
247 return EXT_DATA_AREA(head);
251 return NULL;
254 #undef EXT_DATA_AREA
256 /*****************************************************************
257 Generic VFS init.
258 ******************************************************************/
260 BOOL smbd_vfs_init(connection_struct *conn)
262 const char **vfs_objects;
263 unsigned int i = 0;
264 int j = 0;
266 /* Normal share - initialise with disk access functions */
267 vfs_init_default(conn);
268 vfs_objects = lp_vfs_objects(SNUM(conn));
270 /* Override VFS functions if 'vfs object' was not specified*/
271 if (!vfs_objects || !vfs_objects[0])
272 return True;
274 for (i=0; vfs_objects[i] ;) {
275 i++;
278 for (j=i-1; j >= 0; j--) {
279 if (!vfs_init_custom(conn, vfs_objects[j])) {
280 DEBUG(0, ("smbd_vfs_init: vfs_init_custom failed for %s\n", vfs_objects[j]));
281 return False;
284 return True;
287 /*******************************************************************
288 Check if directory exists.
289 ********************************************************************/
291 BOOL vfs_directory_exist(connection_struct *conn, const char *dname, SMB_STRUCT_STAT *st)
293 SMB_STRUCT_STAT st2;
294 BOOL ret;
296 if (!st)
297 st = &st2;
299 if (SMB_VFS_STAT(conn,dname,st) != 0)
300 return(False);
302 ret = S_ISDIR(st->st_mode);
303 if(!ret)
304 errno = ENOTDIR;
306 return ret;
309 /*******************************************************************
310 Check if an object exists in the vfs.
311 ********************************************************************/
313 BOOL vfs_object_exist(connection_struct *conn,const char *fname,SMB_STRUCT_STAT *sbuf)
315 SMB_STRUCT_STAT st;
317 if (!sbuf)
318 sbuf = &st;
320 ZERO_STRUCTP(sbuf);
322 if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
323 return(False);
324 return True;
327 /*******************************************************************
328 Check if a file exists in the vfs.
329 ********************************************************************/
331 BOOL vfs_file_exist(connection_struct *conn, const char *fname,SMB_STRUCT_STAT *sbuf)
333 SMB_STRUCT_STAT st;
335 if (!sbuf)
336 sbuf = &st;
338 ZERO_STRUCTP(sbuf);
340 if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
341 return False;
342 return(S_ISREG(sbuf->st_mode));
345 /****************************************************************************
346 Read data from fsp on the vfs. (note: EINTR re-read differs from vfs_write_data)
347 ****************************************************************************/
349 ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count)
351 size_t total=0;
353 while (total < byte_count)
355 ssize_t ret = SMB_VFS_READ(fsp, fsp->fh->fd, buf + total,
356 byte_count - total);
358 if (ret == 0) return total;
359 if (ret == -1) {
360 if (errno == EINTR)
361 continue;
362 else
363 return -1;
365 total += ret;
367 return (ssize_t)total;
370 ssize_t vfs_pread_data(files_struct *fsp, char *buf,
371 size_t byte_count, SMB_OFF_T offset)
373 size_t total=0;
375 while (total < byte_count)
377 ssize_t ret = SMB_VFS_PREAD(fsp, fsp->fh->fd, buf + total,
378 byte_count - total, offset + total);
380 if (ret == 0) return total;
381 if (ret == -1) {
382 if (errno == EINTR)
383 continue;
384 else
385 return -1;
387 total += ret;
389 return (ssize_t)total;
392 /****************************************************************************
393 Write data to a fd on the vfs.
394 ****************************************************************************/
396 ssize_t vfs_write_data(files_struct *fsp,const char *buffer,size_t N)
398 size_t total=0;
399 ssize_t ret;
401 while (total < N) {
402 ret = SMB_VFS_WRITE(fsp,fsp->fh->fd,buffer + total,N - total);
404 if (ret == -1)
405 return -1;
406 if (ret == 0)
407 return total;
409 total += ret;
411 return (ssize_t)total;
414 ssize_t vfs_pwrite_data(files_struct *fsp,const char *buffer,
415 size_t N, SMB_OFF_T offset)
417 size_t total=0;
418 ssize_t ret;
420 while (total < N) {
421 ret = SMB_VFS_PWRITE(fsp, fsp->fh->fd, buffer + total,
422 N - total, offset + total);
424 if (ret == -1)
425 return -1;
426 if (ret == 0)
427 return total;
429 total += ret;
431 return (ssize_t)total;
433 /****************************************************************************
434 An allocate file space call using the vfs interface.
435 Allocates space for a file from a filedescriptor.
436 Returns 0 on success, -1 on failure.
437 ****************************************************************************/
439 int vfs_allocate_file_space(files_struct *fsp, SMB_BIG_UINT len)
441 int ret;
442 SMB_STRUCT_STAT st;
443 connection_struct *conn = fsp->conn;
444 SMB_BIG_UINT space_avail;
445 SMB_BIG_UINT bsize,dfree,dsize;
447 release_level_2_oplocks_on_change(fsp);
450 * Actually try and commit the space on disk....
453 DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", fsp->fsp_name, (double)len ));
455 if (((SMB_OFF_T)len) < 0) {
456 DEBUG(0,("vfs_allocate_file_space: %s negative len requested.\n", fsp->fsp_name ));
457 return -1;
460 ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st);
461 if (ret == -1)
462 return ret;
464 if (len == (SMB_BIG_UINT)st.st_size)
465 return 0;
467 if (len < (SMB_BIG_UINT)st.st_size) {
468 /* Shrink - use ftruncate. */
470 DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
471 fsp->fsp_name, (double)st.st_size ));
473 flush_write_cache(fsp, SIZECHANGE_FLUSH);
474 if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, (SMB_OFF_T)len)) != -1) {
475 set_filelen_write_cache(fsp, len);
477 return ret;
480 /* Grow - we need to test if we have enough space. */
482 if (!lp_strict_allocate(SNUM(fsp->conn)))
483 return 0;
485 len -= st.st_size;
486 len /= 1024; /* Len is now number of 1k blocks needed. */
487 space_avail = get_dfree_info(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize);
488 if (space_avail == (SMB_BIG_UINT)-1) {
489 return -1;
492 DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %.0f, space avail = %.0f\n",
493 fsp->fsp_name, (double)st.st_size, (double)len, (double)space_avail ));
495 if (len > space_avail) {
496 errno = ENOSPC;
497 return -1;
500 return 0;
503 /****************************************************************************
504 A vfs set_filelen call.
505 set the length of a file from a filedescriptor.
506 Returns 0 on success, -1 on failure.
507 ****************************************************************************/
509 int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
511 int ret;
513 release_level_2_oplocks_on_change(fsp);
514 DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len));
515 flush_write_cache(fsp, SIZECHANGE_FLUSH);
516 if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, len)) != -1)
517 set_filelen_write_cache(fsp, len);
519 return ret;
522 /****************************************************************************
523 A vfs fill sparse call.
524 Writes zeros from the end of file to len, if len is greater than EOF.
525 Used only by strict_sync.
526 Returns 0 on success, -1 on failure.
527 ****************************************************************************/
529 static char *sparse_buf;
530 #define SPARSE_BUF_WRITE_SIZE (32*1024)
532 int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len)
534 int ret;
535 SMB_STRUCT_STAT st;
536 SMB_OFF_T offset;
537 size_t total;
538 size_t num_to_write;
539 ssize_t pwrite_ret;
541 release_level_2_oplocks_on_change(fsp);
542 ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st);
543 if (ret == -1) {
544 return ret;
547 if (len <= st.st_size) {
548 return 0;
551 DEBUG(10,("vfs_fill_sparse: write zeros in file %s from len %.0f to len %.0f (%.0f bytes)\n",
552 fsp->fsp_name, (double)st.st_size, (double)len, (double)(len - st.st_size)));
554 flush_write_cache(fsp, SIZECHANGE_FLUSH);
556 if (!sparse_buf) {
557 sparse_buf = SMB_CALLOC_ARRAY(char, SPARSE_BUF_WRITE_SIZE);
558 if (!sparse_buf) {
559 errno = ENOMEM;
560 return -1;
564 offset = st.st_size;
565 num_to_write = len - st.st_size;
566 total = 0;
568 while (total < num_to_write) {
569 size_t curr_write_size = MIN(SPARSE_BUF_WRITE_SIZE, (num_to_write - total));
571 pwrite_ret = SMB_VFS_PWRITE(fsp, fsp->fh->fd, sparse_buf, curr_write_size, offset + total);
572 if (pwrite_ret == -1) {
573 DEBUG(10,("vfs_fill_sparse: SMB_VFS_PWRITE for file %s failed with error %s\n",
574 fsp->fsp_name, strerror(errno) ));
575 return -1;
577 if (pwrite_ret == 0) {
578 return 0;
581 total += pwrite_ret;
584 set_filelen_write_cache(fsp, len);
585 return 0;
588 /****************************************************************************
589 Transfer some data (n bytes) between two file_struct's.
590 ****************************************************************************/
592 static files_struct *in_fsp;
593 static files_struct *out_fsp;
595 static ssize_t read_fn(int fd, void *buf, size_t len)
597 return SMB_VFS_READ(in_fsp, fd, buf, len);
600 static ssize_t write_fn(int fd, const void *buf, size_t len)
602 return SMB_VFS_WRITE(out_fsp, fd, buf, len);
605 SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n)
607 in_fsp = in;
608 out_fsp = out;
610 return transfer_file_internal(in_fsp->fh->fd, out_fsp->fh->fd, n, read_fn, write_fn);
613 /*******************************************************************
614 A vfs_readdir wrapper which just returns the file name.
615 ********************************************************************/
617 char *vfs_readdirname(connection_struct *conn, void *p)
619 SMB_STRUCT_DIRENT *ptr= NULL;
620 char *dname;
622 if (!p)
623 return(NULL);
625 ptr = SMB_VFS_READDIR(conn, (DIR *)p);
626 if (!ptr)
627 return(NULL);
629 dname = ptr->d_name;
631 #ifdef NEXT2
632 if (telldir(p) < 0)
633 return(NULL);
634 #endif
636 #ifdef HAVE_BROKEN_READDIR_NAME
637 /* using /usr/ucb/cc is BAD */
638 dname = dname - 2;
639 #endif
641 return(dname);
644 /*******************************************************************
645 A wrapper for vfs_chdir().
646 ********************************************************************/
648 int vfs_ChDir(connection_struct *conn, const char *path)
650 int res;
651 static pstring LastDir="";
653 if (strcsequal(path,"."))
654 return(0);
656 if (*path == '/' && strcsequal(LastDir,path))
657 return(0);
659 DEBUG(4,("vfs_ChDir to %s\n",path));
661 res = SMB_VFS_CHDIR(conn,path);
662 if (!res)
663 pstrcpy(LastDir,path);
664 return(res);
667 /* number of list structures for a caching GetWd function. */
668 #define MAX_GETWDCACHE (50)
670 static struct {
671 SMB_DEV_T dev; /* These *must* be compatible with the types returned in a stat() call. */
672 SMB_INO_T inode; /* These *must* be compatible with the types returned in a stat() call. */
673 char *dos_path; /* The pathname in DOS format. */
674 BOOL valid;
675 } ino_list[MAX_GETWDCACHE];
677 extern BOOL use_getwd_cache;
679 /****************************************************************************
680 Prompte a ptr (to make it recently used)
681 ****************************************************************************/
683 static void array_promote(char *array,int elsize,int element)
685 char *p;
686 if (element == 0)
687 return;
689 p = (char *)SMB_MALLOC(elsize);
691 if (!p) {
692 DEBUG(5,("array_promote: malloc fail\n"));
693 return;
696 memcpy(p,array + element * elsize, elsize);
697 memmove(array + elsize,array,elsize*element);
698 memcpy(array,p,elsize);
699 SAFE_FREE(p);
702 /*******************************************************************
703 Return the absolute current directory path - given a UNIX pathname.
704 Note that this path is returned in DOS format, not UNIX
705 format. Note this can be called with conn == NULL.
706 ********************************************************************/
708 char *vfs_GetWd(connection_struct *conn, char *path)
710 pstring s;
711 static BOOL getwd_cache_init = False;
712 SMB_STRUCT_STAT st, st2;
713 int i;
715 *s = 0;
717 if (!use_getwd_cache)
718 return(SMB_VFS_GETWD(conn,path));
720 /* init the cache */
721 if (!getwd_cache_init) {
722 getwd_cache_init = True;
723 for (i=0;i<MAX_GETWDCACHE;i++) {
724 string_set(&ino_list[i].dos_path,"");
725 ino_list[i].valid = False;
729 /* Get the inode of the current directory, if this doesn't work we're
730 in trouble :-) */
732 if (SMB_VFS_STAT(conn, ".",&st) == -1) {
733 /* Known to fail for root: the directory may be
734 * NFS-mounted and exported with root_squash (so has no root access). */
735 DEBUG(1,("vfs_GetWd: couldn't stat \".\" path=%s error %s (NFS problem ?)\n", path, strerror(errno) ));
736 return(SMB_VFS_GETWD(conn,path));
740 for (i=0; i<MAX_GETWDCACHE; i++) {
741 if (ino_list[i].valid) {
743 /* If we have found an entry with a matching inode and dev number
744 then find the inode number for the directory in the cached string.
745 If this agrees with that returned by the stat for the current
746 directory then all is o.k. (but make sure it is a directory all
747 the same...) */
749 if (st.st_ino == ino_list[i].inode && st.st_dev == ino_list[i].dev) {
750 if (SMB_VFS_STAT(conn,ino_list[i].dos_path,&st2) == 0) {
751 if (st.st_ino == st2.st_ino && st.st_dev == st2.st_dev &&
752 (st2.st_mode & S_IFMT) == S_IFDIR) {
753 pstrcpy (path, ino_list[i].dos_path);
755 /* promote it for future use */
756 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
757 return (path);
758 } else {
759 /* If the inode is different then something's changed,
760 scrub the entry and start from scratch. */
761 ino_list[i].valid = False;
768 /* We don't have the information to hand so rely on traditional methods.
769 The very slow getcwd, which spawns a process on some systems, or the
770 not quite so bad getwd. */
772 if (!SMB_VFS_GETWD(conn,s)) {
773 DEBUG(0,("vfs_GetWd: SMB_VFS_GETWD call failed, errno %s\n",strerror(errno)));
774 return (NULL);
777 pstrcpy(path,s);
779 DEBUG(5,("vfs_GetWd %s, inode %.0f, dev %.0f\n",s,(double)st.st_ino,(double)st.st_dev));
781 /* add it to the cache */
782 i = MAX_GETWDCACHE - 1;
783 string_set(&ino_list[i].dos_path,s);
784 ino_list[i].dev = st.st_dev;
785 ino_list[i].inode = st.st_ino;
786 ino_list[i].valid = True;
788 /* put it at the top of the list */
789 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
791 return (path);
794 BOOL canonicalize_path(connection_struct *conn, pstring path)
796 #ifdef REALPATH_TAKES_NULL
797 char *resolved_name = SMB_VFS_REALPATH(conn,path,NULL);
798 if (!resolved_name) {
799 return False;
801 pstrcpy(path, resolved_name);
802 SAFE_FREE(resolved_name);
803 return True;
804 #else
805 #ifdef PATH_MAX
806 char resolved_name_buf[PATH_MAX+1];
807 #else
808 pstring resolved_name_buf;
809 #endif
810 char *resolved_name = SMB_VFS_REALPATH(conn,path,resolved_name_buf);
811 if (!resolved_name) {
812 return False;
814 pstrcpy(path, resolved_name);
815 return True;
816 #endif /* REALPATH_TAKES_NULL */
819 /*******************************************************************
820 Reduce a file name, removing .. elements and checking that
821 it is below dir in the heirachy. This uses realpath.
822 ********************************************************************/
824 BOOL reduce_name(connection_struct *conn, const pstring fname)
826 #ifdef REALPATH_TAKES_NULL
827 BOOL free_resolved_name = True;
828 #else
829 #ifdef PATH_MAX
830 char resolved_name_buf[PATH_MAX+1];
831 #else
832 pstring resolved_name_buf;
833 #endif
834 BOOL free_resolved_name = False;
835 #endif
836 char *resolved_name = NULL;
837 size_t con_path_len = strlen(conn->connectpath);
838 char *p = NULL;
839 int saved_errno = errno;
841 DEBUG(3,("reduce_name [%s] [%s]\n", fname, conn->connectpath));
843 #ifdef REALPATH_TAKES_NULL
844 resolved_name = SMB_VFS_REALPATH(conn,fname,NULL);
845 #else
846 resolved_name = SMB_VFS_REALPATH(conn,fname,resolved_name_buf);
847 #endif
849 if (!resolved_name) {
850 switch (errno) {
851 case ENOTDIR:
852 DEBUG(3,("reduce_name: Component not a directory in getting realpath for %s\n", fname));
853 errno = saved_errno;
854 return False;
855 case ENOENT:
857 pstring tmp_fname;
858 fstring last_component;
859 /* Last component didn't exist. Remove it and try and canonicalise the directory. */
861 pstrcpy(tmp_fname, fname);
862 p = strrchr_m(tmp_fname, '/');
863 if (p) {
864 *p++ = '\0';
865 fstrcpy(last_component, p);
866 } else {
867 fstrcpy(last_component, tmp_fname);
868 pstrcpy(tmp_fname, ".");
871 #ifdef REALPATH_TAKES_NULL
872 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,NULL);
873 #else
874 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,resolved_name_buf);
875 #endif
876 if (!resolved_name) {
877 DEBUG(3,("reduce_name: couldn't get realpath for %s\n", fname));
878 errno = saved_errno;
879 return False;
881 pstrcpy(tmp_fname, resolved_name);
882 pstrcat(tmp_fname, "/");
883 pstrcat(tmp_fname, last_component);
884 #ifdef REALPATH_TAKES_NULL
885 SAFE_FREE(resolved_name);
886 resolved_name = SMB_STRDUP(tmp_fname);
887 if (!resolved_name) {
888 DEBUG(0,("reduce_name: malloc fail for %s\n", tmp_fname));
889 errno = saved_errno;
890 return False;
892 #else
893 #ifdef PATH_MAX
894 safe_strcpy(resolved_name_buf, tmp_fname, PATH_MAX);
895 #else
896 pstrcpy(resolved_name_buf, tmp_fname);
897 #endif
898 resolved_name = resolved_name_buf;
899 #endif
900 break;
902 default:
903 DEBUG(1,("reduce_name: couldn't get realpath for %s\n", fname));
904 /* Don't restore the saved errno. We need to return the error that
905 realpath caused here as it was not one of the cases we handle. JRA. */
906 return False;
910 DEBUG(10,("reduce_name realpath [%s] -> [%s]\n", fname, resolved_name));
912 if (*resolved_name != '/') {
913 DEBUG(0,("reduce_name: realpath doesn't return absolute paths !\n"));
914 if (free_resolved_name)
915 SAFE_FREE(resolved_name);
916 errno = saved_errno;
917 return False;
920 /* Check for widelinks allowed. */
921 if (!lp_widelinks(SNUM(conn)) && (strncmp(conn->connectpath, resolved_name, con_path_len) != 0)) {
922 DEBUG(2, ("reduce_name: Bad access attempt: %s is a symlink outside the share path", fname));
923 if (free_resolved_name)
924 SAFE_FREE(resolved_name);
925 errno = EACCES;
926 return False;
929 /* Check if we are allowing users to follow symlinks */
930 /* Patch from David Clerc <David.Clerc@cui.unige.ch>
931 University of Geneva */
933 #ifdef S_ISLNK
934 if (!lp_symlinks(SNUM(conn))) {
935 SMB_STRUCT_STAT statbuf;
936 if ( (SMB_VFS_LSTAT(conn,fname,&statbuf) != -1) &&
937 (S_ISLNK(statbuf.st_mode)) ) {
938 if (free_resolved_name)
939 SAFE_FREE(resolved_name);
940 DEBUG(3,("reduce_name: denied: file path name %s is a symlink\n",resolved_name));
941 errno = EACCES;
942 return False;
945 #endif
947 DEBUG(3,("reduce_name: %s reduced to %s\n", fname, resolved_name));
948 if (free_resolved_name)
949 SAFE_FREE(resolved_name);
950 errno = saved_errno;
951 return(True);