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
30struct vfs_init_function_entry {
31	char *name;
32 	vfs_op_tuple *vfs_op_tuples;
33	struct vfs_init_function_entry *prev, *next;
34};
35
36static struct vfs_init_function_entry *backends = NULL;
37
38/* Some structures to help us initialise the vfs operations table */
39
40struct 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
49static 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
156static 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
168NTSTATUS 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
204static 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
216BOOL 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
302BOOL 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
333BOOL 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
355int 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
380BOOL 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
398BOOL 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
416ssize_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
437ssize_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
463ssize_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/* Foxconn modified start pling 11/18/2009 */
482//ssize_t vfs_pwrite_data(files_struct *fsp,const char *buffer,
483//                size_t N, SMB_OFF_T offset)
484ssize_t vfs_pwrite_data(files_struct *fsp,const char *buffer,
485                size_t N, SMB_BIG_UINT offset)
486/* Foxconn modified end pling 11/18/2009 */
487{
488    /* Foxconn modified start pling 11/18/2009 */
489	//size_t total=0;
490	//ssize_t ret;
491	SMB_BIG_UINT total=0;
492	SMB_BIG_UINT ret;
493    /* Foxconn modified end pling 11/18/2009 */
494
495	while (total < N) {
496		ret = SMB_VFS_PWRITE(fsp, fsp->fd, buffer + total,
497                                N - total, offset + total);
498
499		if (ret == -1)
500			return -1;
501		if (ret == 0)
502			return total;
503
504		total += ret;
505	}
506	return (ssize_t)total;
507}
508/****************************************************************************
509 An allocate file space call using the vfs interface.
510 Allocates space for a file from a filedescriptor.
511 Returns 0 on success, -1 on failure.
512****************************************************************************/
513
514int vfs_allocate_file_space(files_struct *fsp, SMB_BIG_UINT len)
515{
516	int ret;
517	SMB_STRUCT_STAT st;
518	connection_struct *conn = fsp->conn;
519	SMB_BIG_UINT space_avail;
520	SMB_BIG_UINT bsize,dfree,dsize;
521
522	release_level_2_oplocks_on_change(fsp);
523
524	/*
525	 * Actually try and commit the space on disk....
526	 */
527
528	DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", fsp->fsp_name, (double)len ));
529
530    /* Foxconn removed start pling 11/18/2009 */
531    /* Don't check negative length, to avoid "disk full" error
532     * when copy file from Vista/Win7 to USB.
533     */
534#if 0
535	if (((SMB_OFF_T)len) < 0) {
536		DEBUG(0,("vfs_allocate_file_space: %s negative len requested.\n", fsp->fsp_name ));
537		return -1;
538	}
539#endif
540    /* Foxconn removed end pling 11/18/2009 */
541
542	ret = SMB_VFS_FSTAT(fsp,fsp->fd,&st);
543	if (ret == -1)
544		return ret;
545
546	if (len == (SMB_BIG_UINT)st.st_size)
547		return 0;
548
549	if (len < (SMB_BIG_UINT)st.st_size) {
550		/* Shrink - use ftruncate. */
551
552		DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
553				fsp->fsp_name, (double)st.st_size ));
554
555		flush_write_cache(fsp, SIZECHANGE_FLUSH);
556		if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fd, (SMB_OFF_T)len)) != -1) {
557			set_filelen_write_cache(fsp, len);
558		}
559		return ret;
560	}
561
562	/* Grow - we need to test if we have enough space. */
563
564	if (!lp_strict_allocate(SNUM(fsp->conn)))
565		return 0;
566
567	len -= st.st_size;
568	len /= 1024; /* Len is now number of 1k blocks needed. */
569	space_avail = SMB_VFS_DISK_FREE(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize);
570	if (space_avail == (SMB_BIG_UINT)-1) {
571		return -1;
572	}
573
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 ));
576
577	if (len > space_avail) {
578		errno = ENOSPC;
579		return -1;
580	}
581
582	return 0;
583}
584
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****************************************************************************/
590
591int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
592{
593	int ret;
594
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
599	/* foxconn modified start, zacker, 07/07/2011 */
600        /* Workaround: ftruncate is slow in VFAT, just do it
601	 * for small (16MB) file editing, to workaround the
602	 * edit problem with notepad in Windows
603	 * */
604        if (len > 0 && len < 0x1000000) {
605               if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fd, len)) != -1)
606                   set_filelen_write_cache(fsp, len);
607               } else {
608                   ret = 0;
609        }
610        /* foxconn modified end, zacker, 07/07/2011 */
611
612        ret = 0;
613        /* foxconn modified end , 04/01/2009 */
614
615	return ret;
616}
617
618/****************************************************************************
619 Transfer some data (n bytes) between two file_struct's.
620****************************************************************************/
621
622static files_struct *in_fsp;
623static files_struct *out_fsp;
624
625static ssize_t read_fn(int fd, void *buf, size_t len)
626{
627	return SMB_VFS_READ(in_fsp, fd, buf, len);
628}
629
630static ssize_t write_fn(int fd, const void *buf, size_t len)
631{
632	return SMB_VFS_WRITE(out_fsp, fd, buf, len);
633}
634
635SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n)
636{
637	in_fsp = in;
638	out_fsp = out;
639
640	return transfer_file_internal(in_fsp->fd, out_fsp->fd, n, read_fn, write_fn);
641}
642
643/*******************************************************************
644 A vfs_readdir wrapper which just returns the file name.
645********************************************************************/
646
647char *vfs_readdirname(connection_struct *conn, void *p)
648{
649	SMB_STRUCT_DIRENT *ptr= NULL;
650	char *dname;
651
652	if (!p)
653		return(NULL);
654
655	ptr = SMB_VFS_READDIR(conn,p);
656	if (!ptr)
657		return(NULL);
658
659	dname = ptr->d_name;
660
661#ifdef NEXT2
662	if (telldir(p) < 0)
663		return(NULL);
664#endif
665
666#ifdef HAVE_BROKEN_READDIR
667	/* using /usr/ucb/cc is BAD */
668	dname = dname - 2;
669#endif
670
671	return(dname);
672}
673
674/*******************************************************************
675 A wrapper for vfs_chdir().
676********************************************************************/
677
678int vfs_ChDir(connection_struct *conn, const char *path)
679{
680	int res;
681	static pstring LastDir="";
682
683	if (strcsequal(path,"."))
684		return(0);
685
686	if (*path == '/' && strcsequal(LastDir,path))
687		return(0);
688
689	DEBUG(4,("vfs_ChDir to %s\n",path));
690
691	res = SMB_VFS_CHDIR(conn,path);
692	if (!res)
693		pstrcpy(LastDir,path);
694	return(res);
695}
696
697/* number of list structures for a caching GetWd function. */
698#define MAX_GETWDCACHE (50)
699
700static struct {
701	SMB_DEV_T dev; /* These *must* be compatible with the types returned in a stat() call. */
702	SMB_INO_T inode; /* These *must* be compatible with the types returned in a stat() call. */
703	char *dos_path; /* The pathname in DOS format. */
704	BOOL valid;
705} ino_list[MAX_GETWDCACHE];
706
707extern BOOL use_getwd_cache;
708
709/****************************************************************************
710 Prompte a ptr (to make it recently used)
711****************************************************************************/
712
713static void array_promote(char *array,int elsize,int element)
714{
715	char *p;
716	if (element == 0)
717		return;
718
719	p = (char *)SMB_MALLOC(elsize);
720
721	if (!p) {
722		DEBUG(5,("array_promote: malloc fail\n"));
723		return;
724	}
725
726	memcpy(p,array + element * elsize, elsize);
727	memmove(array + elsize,array,elsize*element);
728	memcpy(array,p,elsize);
729	SAFE_FREE(p);
730}
731
732/*******************************************************************
733 Return the absolute current directory path - given a UNIX pathname.
734 Note that this path is returned in DOS format, not UNIX
735 format. Note this can be called with conn == NULL.
736********************************************************************/
737
738char *vfs_GetWd(connection_struct *conn, char *path)
739{
740	pstring s;
741	static BOOL getwd_cache_init = False;
742	SMB_STRUCT_STAT st, st2;
743	int i;
744
745	*s = 0;
746
747	if (!use_getwd_cache)
748		return(SMB_VFS_GETWD(conn,path));
749
750	/* init the cache */
751	if (!getwd_cache_init) {
752		getwd_cache_init = True;
753		for (i=0;i<MAX_GETWDCACHE;i++) {
754			string_set(&ino_list[i].dos_path,"");
755			ino_list[i].valid = False;
756		}
757	}
758
759	/*  Get the inode of the current directory, if this doesn't work we're
760		in trouble :-) */
761
762	if (SMB_VFS_STAT(conn, ".",&st) == -1) {
763		DEBUG(0,("Very strange, couldn't stat \".\" path=%s\n", path));
764		return(SMB_VFS_GETWD(conn,path));
765	}
766
767
768	for (i=0; i<MAX_GETWDCACHE; i++) {
769		if (ino_list[i].valid) {
770
771			/*  If we have found an entry with a matching inode and dev number
772				then find the inode number for the directory in the cached string.
773				If this agrees with that returned by the stat for the current
774				directory then all is o.k. (but make sure it is a directory all
775				the same...) */
776
777			if (st.st_ino == ino_list[i].inode && st.st_dev == ino_list[i].dev) {
778				if (SMB_VFS_STAT(conn,ino_list[i].dos_path,&st2) == 0) {
779					if (st.st_ino == st2.st_ino && st.st_dev == st2.st_dev &&
780							(st2.st_mode & S_IFMT) == S_IFDIR) {
781						pstrcpy (path, ino_list[i].dos_path);
782
783						/* promote it for future use */
784						array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
785						return (path);
786					} else {
787						/*  If the inode is different then something's changed,
788							scrub the entry and start from scratch. */
789						ino_list[i].valid = False;
790					}
791				}
792			}
793		}
794	}
795
796	/*  We don't have the information to hand so rely on traditional methods.
797		The very slow getcwd, which spawns a process on some systems, or the
798		not quite so bad getwd. */
799
800	if (!SMB_VFS_GETWD(conn,s)) {
801		DEBUG(0,("vfs_GetWd: SMB_VFS_GETWD call failed, errno %s\n",strerror(errno)));
802		return (NULL);
803	}
804
805	pstrcpy(path,s);
806
807	DEBUG(5,("vfs_GetWd %s, inode %.0f, dev %.0f\n",s,(double)st.st_ino,(double)st.st_dev));
808
809	/* add it to the cache */
810	i = MAX_GETWDCACHE - 1;
811	string_set(&ino_list[i].dos_path,s);
812	ino_list[i].dev = st.st_dev;
813	ino_list[i].inode = st.st_ino;
814	ino_list[i].valid = True;
815
816	/* put it at the top of the list */
817	array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
818
819	return (path);
820}
821
822BOOL canonicalize_path(connection_struct *conn, pstring path)
823{
824#ifdef REALPATH_TAKES_NULL
825	char *resolved_name = SMB_VFS_REALPATH(conn,path,NULL);
826	if (!resolved_name) {
827		return False;
828	}
829	pstrcpy(path, resolved_name);
830	SAFE_FREE(resolved_name);
831	return True;
832#else
833#ifdef PATH_MAX
834        char resolved_name_buf[PATH_MAX+1];
835#else
836        pstring resolved_name_buf;
837#endif
838	char *resolved_name = SMB_VFS_REALPATH(conn,path,resolved_name_buf);
839	if (!resolved_name) {
840		return False;
841	}
842	pstrcpy(path, resolved_name);
843	return True;
844#endif /* REALPATH_TAKES_NULL */
845}
846
847/*******************************************************************
848 Reduce a file name, removing .. elements and checking that
849 it is below dir in the heirachy. This uses realpath.
850********************************************************************/
851
852BOOL reduce_name(connection_struct *conn, const pstring fname)
853{
854#ifdef REALPATH_TAKES_NULL
855	BOOL free_resolved_name = True;
856#else
857#ifdef PATH_MAX
858        char resolved_name_buf[PATH_MAX+1];
859#else
860        pstring resolved_name_buf;
861#endif
862	BOOL free_resolved_name = False;
863#endif
864	char *resolved_name = NULL;
865	size_t con_path_len = strlen(conn->connectpath);
866	char *p = NULL;
867	int saved_errno = errno;
868
869	DEBUG(3,("reduce_name [%s] [%s]\n", fname, conn->connectpath));
870
871#ifdef REALPATH_TAKES_NULL
872	resolved_name = SMB_VFS_REALPATH(conn,fname,NULL);
873#else
874	resolved_name = SMB_VFS_REALPATH(conn,fname,resolved_name_buf);
875#endif
876
877	if (!resolved_name) {
878		switch (errno) {
879			case ENOTDIR:
880				DEBUG(3,("reduce_name: Component not a directory in getting realpath for %s\n", fname));
881				errno = saved_errno;
882				return False;
883			case ENOENT:
884			{
885				pstring tmp_fname;
886				fstring last_component;
887				/* Last component didn't exist. Remove it and try and canonicalise the directory. */
888
889				pstrcpy(tmp_fname, fname);
890				p = strrchr_m(tmp_fname, '/');
891				if (p) {
892					*p++ = '\0';
893					fstrcpy(last_component, p);
894				} else {
895					fstrcpy(last_component, tmp_fname);
896					pstrcpy(tmp_fname, ".");
897				}
898
899#ifdef REALPATH_TAKES_NULL
900				resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,NULL);
901#else
902				resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,resolved_name_buf);
903#endif
904				if (!resolved_name) {
905					DEBUG(3,("reduce_name: couldn't get realpath for %s\n", fname));
906					errno = saved_errno;
907					return False;
908				}
909				pstrcpy(tmp_fname, resolved_name);
910				pstrcat(tmp_fname, "/");
911				pstrcat(tmp_fname, last_component);
912#ifdef REALPATH_TAKES_NULL
913				SAFE_FREE(resolved_name);
914				resolved_name = SMB_STRDUP(tmp_fname);
915				if (!resolved_name) {
916					DEBUG(0,("reduce_name: malloc fail for %s\n", tmp_fname));
917					errno = saved_errno;
918					return False;
919				}
920#else
921#ifdef PATH_MAX
922				safe_strcpy(resolved_name_buf, tmp_fname, PATH_MAX);
923#else
924				pstrcpy(pstring resolved_name_buf, tmp_fname);
925#endif
926				resolved_name = resolved_name_buf;
927#endif
928				break;
929			}
930			default:
931				DEBUG(1,("reduce_name: couldn't get realpath for %s\n", fname));
932				/* Don't restore the saved errno. We need to return the error that
933				   realpath caused here as it was not one of the cases we handle. JRA. */
934				return False;
935		}
936	}
937
938	DEBUG(10,("reduce_name realpath [%s] -> [%s]\n", fname, resolved_name));
939
940	if (*resolved_name != '/') {
941		DEBUG(0,("reduce_name: realpath doesn't return absolute paths !\n"));
942		if (free_resolved_name)
943			SAFE_FREE(resolved_name);
944		errno = saved_errno;
945		return False;
946	}
947
948	/* Check for widelinks allowed. */
949	if (!lp_widelinks(SNUM(conn)) && (strncmp(conn->connectpath, resolved_name, con_path_len) != 0)) {
950		DEBUG(2, ("reduce_name: Bad access attempt: %s is a symlink outside the share path", fname));
951		if (free_resolved_name)
952			SAFE_FREE(resolved_name);
953		errno = EACCES;
954		return False;
955	}
956
957        /* Check if we are allowing users to follow symlinks */
958        /* Patch from David Clerc <David.Clerc@cui.unige.ch>
959                University of Geneva */
960
961#ifdef S_ISLNK
962        if (!lp_symlinks(SNUM(conn))) {
963                SMB_STRUCT_STAT statbuf;
964                if ( (SMB_VFS_LSTAT(conn,fname,&statbuf) != -1) &&
965                                (S_ISLNK(statbuf.st_mode)) ) {
966			if (free_resolved_name)
967				SAFE_FREE(resolved_name);
968                        DEBUG(3,("reduce_name: denied: file path name %s is a symlink\n",resolved_name));
969                        errno = EACCES;
970			return False;
971                }
972        }
973#endif
974
975	DEBUG(3,("reduce_name: %s reduced to %s\n", fname, resolved_name));
976	if (free_resolved_name)
977		SAFE_FREE(resolved_name);
978	errno = saved_errno;
979	return(True);
980}
981