resolving full path when creating a new file on freebsd 4.x (and more)

"Patrick Bihan-Faou" <[email protected]>
Newsgroups gmane.linux.dazuko.devel
Message-ID <[email protected]>
Hi,


Testing dazuko 2.0.3-pre4 on freebsd I noticed that I was never getting the
OPEN/CLOSE events for files that were non-existant previously. After some
investigation, I found that when the file does not exist, the namei() call
in freebsd_get_full_fileinfo() (called from xp_file_struct_check()) returns
ENOENT leading in the name not being resolved.

Here is a patch for freebsd_get_full_fileinfo() that tries to resolve the
first parent directory of a file if the file itself does not exist (ENOENT).


The provided patch has been slightly tested on a FreeBSD 4.9 system with
good success so far.

Also, while there, I have replaced the vrele calls that were following
NDINIT/namei calls with more adequate NDFREE() calls that also free the
memory that could have been allocated during the namei() call.


Now I have another question regarding the closed/modified event:

To support the closed-modified event, dazuko monitors the write system call.
However in FreeBSD there are at least 4 calls that can modify a file:

- write() (already handled)

- writev() (handles scattered buffers for a single write operation)

- pwrite() (write at a specific offset)

- aio_write (asynchronous IO call)

Only the first syscall is handled and none of the last 3. Wouldn't that
invalidate the usefulleness of the closed-modified event ?

If indeed the other syscalls should be handled as well, I am willing to
provide patches for that.


I have more questions and suggestions, but they will come later.


Patrick.

_______________________________________________
Dazuko-devel mailing list
[email protected]
http://lists.nongnu.org/mailman/listinfo/dazuko-devel
dazuko_freebsd.c.patch (application/octet-stream, 4.6 KB)
--- dazuko_freebsd.c.orig	Fri Aug 27 14:19:20 2004
+++ dazuko_freebsd.c	Fri Aug 27 15:30:32 2004
@@ -53,6 +53,7 @@
 #include <sys/namei.h>
 #include <sys/param.h>
 #include <sys/vnode.h>
+#include <sys/fcntl.h>
 
 #include "dazuko_freebsd.h"
 #include "dazuko_xp.h"
@@ -342,12 +343,13 @@ inline int xp_compare_file(struct xp_fil
 
 /* file structure */
 
-static void freebsd_get_full_fileinfo(struct proc *p, const char *path, char **fullpath, char **freefullpath, struct file_properties *file_p)
+static void freebsd_get_full_fileinfo(struct proc *p, const char *path, char **fullpath, char **freefullpath, struct file_properties *file_p, int follow_symlinks)
 {
 	struct proc			localp;
 	struct nameidata		nd;
 	struct filedesc			localfd;
 	struct vattr			vattr;
+	int err;
 
 	if (p == NULL || path == NULL || fullpath == NULL || freefullpath == NULL || file_p == NULL)
 		return;
@@ -357,13 +359,102 @@ static void freebsd_get_full_fileinfo(st
 	dazuko_bzero(&localfd, sizeof(localfd));
 	dazuko_bzero(file_p, sizeof(struct file_properties));
 
-	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, path, p);
+	NDINIT(&nd, LOOKUP, follow_symlinks ? FOLLOW: NOFOLLOW, UIO_USERSPACE, path, p);
 
-	if (namei(&nd) != 0)
+	if ((err=namei(&nd)) != 0)
 	{
 		/*
 		we need to understand why this fails sometimes
 		*/
+
+		if ( (err == ENOENT)
+			&& (path[0] != '/') )
+		{
+			/* let's try to resolve the parent dir (if possible) */
+			char * kpath = xp_malloc(MAXPATHLEN+1);
+			char * fname = kpath;
+			char * lookuppath = ".";
+			char * pfullpath = NULL;
+			char * pfreefullpath = NULL;
+			size_t len;
+			int i;
+			struct nameidata ndparent;
+
+			if (!kpath)
+			{
+				xp_print("failed to allocate memory for path resolution\n");
+				NDFREE(&nd, 0);
+				return;
+			}
+
+			dazuko_bzero(kpath, MAXPATHLEN+1);
+			copyinstr(path, kpath, MAXPATHLEN+1, &len);
+
+			/* find the last / */
+			for (i = strlen(kpath); i >= 0; i--)
+			{
+				if (kpath[i] == '/')
+				{
+					kpath[i] = 0;
+					fname = kpath + i + 1;
+					lookuppath = kpath;
+					break;
+				}
+			}
+
+			/* at this point we habe:
+			 * lookuppath = the name of the parent directory to lookup
+			 * fname = the file name that was not found by the previous namei
+			 */
+
+			dazuko_bzero(&ndparent, sizeof(ndparent));
+			NDINIT(&ndparent, LOOKUP, follow_symlinks ? FOLLOW : NOFOLLOW, UIO_SYSSPACE, lookuppath, p);
+
+			if ( (err = namei(&ndparent)) != 0 )
+			{
+				NDFREE(&nd, 0);
+				NDFREE(&ndparent, 0);
+				xp_free(kpath);
+				return;
+			}
+
+			if (!ndparent.ni_vp || (ndparent.ni_vp->v_type != VDIR))
+			{
+				/* we did not find a vnode or the vnode is not a directory... */
+				NDFREE(&nd, 0);
+				NDFREE(&ndparent, 0);
+				xp_free(kpath);
+				return;
+			}
+
+			localp.p_textvp = ndparent.ni_vp;
+			localp.p_fd = &localfd;
+			if (orig_rootmnt)
+				localfd.fd_rdir = orig_rootmnt;
+			else
+				localfd.fd_rdir = nd.ni_rootdir;
+
+			textvp_fullpath(&localp, &pfullpath, &pfreefullpath);
+
+			if (pfreefullpath)
+			{
+				int flen = strlen(pfullpath) + strlen(fname) + 2;
+				*fullpath = malloc(flen, M_TEMP, M_WAITOK);
+				if (*fullpath)
+				{
+					strcpy(*fullpath, pfullpath);
+					strcat(*fullpath, "/");
+					strcat(*fullpath, fname);
+				}
+				*freefullpath = *fullpath;
+				free(pfreefullpath, M_TEMP);
+			}
+
+			NDFREE(&nd,0);
+			NDFREE(&ndparent,0);
+			xp_free(kpath);
+			return;
+		}
 	}
 	else
 	{
@@ -393,7 +484,7 @@ static void freebsd_get_full_fileinfo(st
 			}
 
 			/* deref looked up vnode */
-			vrele(nd.ni_vp);
+			NDFREE(&nd, 0);
 		}
 	}
 }
@@ -404,7 +495,7 @@ inline int xp_file_struct_check(struct d
 	char	*freefullpath = NULL;
 	int	length;
 
-	freebsd_get_full_fileinfo(dfs->extra_data->p, dfs->extra_data->user_filename, &fullpath, &freefullpath, &(dfs->file_p));
+	freebsd_get_full_fileinfo(dfs->extra_data->p, dfs->extra_data->user_filename, &fullpath, &freefullpath, &(dfs->file_p), 1);
 
 	if (freefullpath)
 	{
@@ -1188,6 +1279,8 @@ int freebsd_dazuko_device_close(dev_t de
 
 /* init/exit */
 
+
+
 static int dazuko_loader(struct module *m, int what, void *arg)
 {
 	int			err = 0;
@@ -1205,17 +1298,24 @@ static int dazuko_loader(struct module *
 				if (namei(&nd))
 					xp_print("dazuko: warning: failed to get root mount\n");
 				else
+				{
 					orig_rootmnt = nd.ni_rootdir;
+					vref(orig_rootmnt);
+				}
 
 				/* deref looked up vnode */
-				if (nd.ni_vp)
-					vrele(nd.ni_vp);
+				NDFREE(&nd, 0);
 			}
 			break;
 
 		case MOD_UNLOAD:
 			if (dazuko_exit() != 0)
 				err = EPERM;
+			if (orig_rootmnt)
+			{
+				vrele(orig_rootmnt);
+				orig_rootmnt = NULL;
+			}
 			break;
 
 		default:
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.