diff options
author | patacongo <patacongo@7fd9a85b-ad96-42d3-883c-3090e2eb8679> | 2012-06-09 15:55:10 +0000 |
---|---|---|
committer | patacongo <patacongo@7fd9a85b-ad96-42d3-883c-3090e2eb8679> | 2012-06-09 15:55:10 +0000 |
commit | b063105e5f3ef222ed3e32f54c621fa3a4ff4c49 (patch) | |
tree | b2bcdba62940f6fdedc7ba0ab8e96f6d7622ddec /nuttx/fs | |
parent | f06204ab7b08145c79275c5a32b7e1ce1ecc3272 (diff) |
NFS update
git-svn-id: https://nuttx.svn.sourceforge.net/svnroot/nuttx/trunk@4820 7fd9a85b-ad96-42d3-883c-3090e2eb8679
Diffstat (limited to 'nuttx/fs')
-rw-r--r-- | nuttx/fs/nfs/nfs_vfsops.c | 271 | ||||
-rw-r--r-- | nuttx/fs/nfs/rpc_clnt.c | 152 |
2 files changed, 239 insertions, 184 deletions
diff --git a/nuttx/fs/nfs/nfs_vfsops.c b/nuttx/fs/nfs/nfs_vfsops.c index c78825fe88..0f948b5741 100644 --- a/nuttx/fs/nfs/nfs_vfsops.c +++ b/nuttx/fs/nfs/nfs_vfsops.c @@ -99,6 +99,8 @@ struct nfs_dirent * Private Function Prototypes ****************************************************************************/ +static int nfs_create(FAR struct nfsmount *nmp, struct nfsnode *np, + FAR const char *relpath, mode_t mode); static int nfs_open(FAR struct file *filep, const char *relpath, int oflags, mode_t mode); static ssize_t nfs_read(FAR struct file *filep, char *buffer, size_t buflen); @@ -172,6 +174,72 @@ const struct mountpt_operations nfs_operations = ****************************************************************************/ /**************************************************************************** + * Name: nfs_create + * + * Description: + * Create a file. This is part of the file open logic that is executed if + * the user asks to create a file. + * + * Returned Value: + * 0 on success; a positive errno value on failure. + * + ****************************************************************************/ + +static int nfs_create(FAR struct nfsmount *nmp, struct nfsnode *np, + FAR const char *relpath, mode_t mode) +{ +//struct nfs_fattr vap; + struct nfsv3_sattr sp; + struct CREATE3args create; + struct rpc_reply_create resok; + int error = 0; + + do + { + nfsstats.rpccnt[NFSPROC_CREATE]++; + memset(&sp, 0, sizeof(struct nfsv3_sattr)); + //memset(&vap, 0, sizeof(struct nfs_fattr)); + //vap = nmp->nm_head->n_fattr; + sp.sa_modetrue = true; + sp.sa_mode = txdr_unsigned(mode); + sp.sa_uidfalse = nfs_xdrneg1; + sp.sa_gidfalse = nfs_xdrneg1; + sp.sa_sizefalse = 0; + sp.sa_atimetype = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE); + sp.sa_mtimetype = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE); + //txdr_nfsv3time2(&vap.fa3_atime, &sp.sa_atime); + //txdr_nfsv3time2(&vap.fa3_mtime, &sp.sa_mtime); + + memset(&create, 0, sizeof(struct CREATE3args)); + memset(&resok, 0, sizeof(struct rpc_reply_create)); + memcpy(&create.how, &sp, sizeof(struct nfsv3_sattr)); +#warning "BUG HERE: np has not yet been initialized" + create.where.dir.length = txdr_unsigned(np->n_fhsize); + memcpy(&create.where.dir.handle, &np->n_fhp, sizeof(nfsfh_t)); + create.where.length = txdr_unsigned(64); + strncpy(create.where.name, relpath, 64); + + error = nfs_request(nmp, NFSPROC_CREATE, (FAR const void *)&create, + (void *)&resok, sizeof(struct rpc_reply_create)); + } + while (error == EOPNOTSUPP); + + if (error == 0) + { + //np->nfsv3_type = fxdr_unsigned(uint32_t, resok.attributes.fa_type); + + np->n_open = true; + memcpy(&np->n_fhp, &resok.create.fshandle.handle, sizeof(nfsfh_t)); + np->n_size = fxdr_hyper(&resok.create.attributes.fa3_size); + memcpy(&resok.create.attributes, &np->n_fattr, sizeof(struct nfs_fattr)); + fxdr_nfsv3time(&resok.create.attributes.fa3_mtime, &np->n_mtime) + np->n_ctime = fxdr_hyper(&resok.create.attributes.fa3_ctime); + } + + return error; +} + + /**************************************************************************** * Name: nfs_open * * Description: @@ -186,13 +254,12 @@ const struct mountpt_operations nfs_operations = static int nfs_open(FAR struct file *filep, FAR const char *relpath, int oflags, mode_t mode) { + struct stat buf; struct inode *in; //struct nfs_fattr vap; - struct nfsv3_sattr sp; struct nfsmount *nmp; struct nfsnode *np; - struct CREATE3args create; - struct rpc_reply_create resok; + bool readonly; int error = 0; /* Sanity checks */ @@ -203,12 +270,20 @@ static int nfs_open(FAR struct file *filep, FAR const char *relpath, * mountpoint private data from the inode structure */ - in = filep->f_inode; + in = filep->f_inode; nmp = (struct nfsmount*)in->i_private; - np = (struct nfsnode*)filep->f_priv; DEBUGASSERT(nmp != NULL); + /* Pre-allocate the file private data to describe the opened file. */ + + np = (struct nfsnode *)kzalloc(sizeof(struct nfsnode)); + if (!np) + { + fdbg("ERROR: Failed to allocate private data\n"); + return -ENOMEM; + } + /* Check if the mount is still healthy */ nfs_semtake(nmp); @@ -218,121 +293,133 @@ static int nfs_open(FAR struct file *filep, FAR const char *relpath, goto errout_with_semaphore; } - if (oflags == O_CREAT) - { - /* Sanity checks */ - - DEBUGASSERT(filep->f_priv == NULL); -again: - nfsstats.rpccnt[NFSPROC_CREATE]++; - memset(&sp, 0, sizeof(struct nfsv3_sattr)); - //memset(&vap, 0, sizeof(struct nfs_fattr)); - //vap = nmp->nm_head->n_fattr; - sp.sa_modetrue = true; - sp.sa_mode = txdr_unsigned(mode); - sp.sa_uidfalse = nfs_xdrneg1; - sp.sa_gidfalse = nfs_xdrneg1; - sp.sa_sizefalse = 0; - sp.sa_atimetype = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE); - sp.sa_mtimetype = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE); - //txdr_nfsv3time2(&vap.fa3_atime, &sp.sa_atime); - //txdr_nfsv3time2(&vap.fa3_mtime, &sp.sa_mtime); + /* First check if the file already exists */ - memset(&create, 0, sizeof(struct CREATE3args)); - memset(&resok, 0, sizeof(struct rpc_reply_create)); - memcpy(&create.how, &sp, sizeof(struct nfsv3_sattr)); - create.where.dir.length = txdr_unsigned(np->n_fhsize); - memcpy(&create.where.dir.handle, &np->n_fhp, sizeof(nfsfh_t)); - create.where.length = txdr_unsigned(64); - strncpy(create.where.name, relpath, 64); + error = nfs_getfsinfo(nmp, relpath, &buf); + if (error == 0) + { + /* Check if the file is a directory */ - error = nfs_request(nmp, NFSPROC_CREATE, (FAR const void *)&create, - (void *)&resok, sizeof(struct rpc_reply_create)); - if (!error) + if (S_ISDIR(buf.st_mode)) { - /* Create an instance of the file private data to describe the opened - * file. - */ - - np = (struct nfsnode *)kzalloc(sizeof(struct nfsnode)); - if (!np) - { - fdbg("ERROR: Failed to allocate private data\n"); - error = -ENOMEM; - goto errout_with_semaphore; - } - - /* Initialize the file private data (only need to initialize - * non-zero elements) - */ - - // np->nfsv3_type = fxdr_unsigned(uint32_t, resok.attributes.fa_type); + /* Exit with EISDIR if we attempt to open an directory */ - /* The full path exists -- but is the final component a file - * or a directory? - */ + fdbg("ERROR: Path is a directory\n"); + error = EISDIR; + goto errout_with_semaphore; + } - if (np->nfsv3_type == NFDIR) - { - /* It is a directory */ + /* Check if the caller has sufficient privileges to open the file */ - error = EISDIR; - fdbg("ERROR: '%s' is a directory\n", relpath); - goto errout_with_semaphore; - } + readonly = ((buf.st_mode & (S_IWOTH|S_IWGRP|S_IXUSR)) == 0); + if (((oflags & O_WRONLY) != 0) && readonly) + { + fdbg("ERROR: File is read-only\n"); + error = EACCES; + goto errout_with_semaphore; + } - np->n_open = true; - memcpy(&np->n_fhp, &resok.create.fshandle.handle, sizeof(nfsfh_t)); - np->n_size = fxdr_hyper(&resok.create.attributes.fa3_size); - memcpy(&resok.create.attributes, &np->n_fattr, sizeof(struct nfs_fattr)); - fxdr_nfsv3time(&resok.create.attributes.fa3_mtime, &np->n_mtime) - np->n_ctime = fxdr_hyper(&resok.create.attributes.fa3_ctime); + /* It would be an error if we are asked to create it exclusively */ - /* Attach the private date to the struct file instance */ + if ((oflags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL)) + { + /* Already exists -- can't create it exclusively */ - filep->f_priv = np; + fdbg("ERROR: File exists\n"); + error = EEXIST; + goto errout_with_semaphore; + } - /* Then insert the new instance into the mountpoint structure. - * It needs to be there (1) to handle error conditions that effect - * all files, and (2) to inform the umount logic that we are busy - * (but a simple reference count could have done that). - */ + /* If O_TRUNC is specified and the file is opened for writing, + * then truncate the file. This operation requires that the file is + * writable, but we have already checked that. O_TRUNC without write + * access is ignored. + */ - np->n_next = nmp->nm_head; - nmp->nm_head = np->n_next; - error = 0; - } - else + if ((oflags & (O_TRUNC|O_WRONLY)) == (O_TRUNC|O_WRONLY)) { - if (error == EOPNOTSUPP) - { - goto again; - } + /* Truncate the file to zero length */ + + fvdbg("Truncating file\n"); +#warning "Missing logic" } - np->n_flag |= NMODIFIED; + /* Initialize the file private data from the FSINFO return data */ + /* NOTE: This will require some re-structuring */ +#if 0 + np->n_open = true; + memcpy(&np->n_fhp, &resok.fsinfo.fshandle.handle, sizeof(nfsfh_t)); + np->n_size = fxdr_hyper(&resok.fsinfo.attributes.fa3_size); + memcpy(&resok.fsinfo.attributes, &np->n_fattr, sizeof(struct nfs_fattr)); + fxdr_nfsv3time(&resok.fsinfo.attributes.fa3_mtime, &np->n_mtime) + np->n_ctime = fxdr_hyper(&resok.fsinfo.attributes.fa3_ctime); +#else +#warning "Missing logic" + fdbg("ERROR: Logic to open an existing file is not fully implemented"); + errno = ENOSYS; /* Just fail for now */ + goto errout_with_semaphore; +#endif + /* Fall through to finish the file open operation */ } + + /* An error occurred while getting the file status */ + else { - if (np->nfsv3_type != NFREG) + /* Check if the stat failed because the file does not exist. */ +#warning "Missing logic" + + /* If the file does not exist then check if we were asked to create + * the file. If the O_CREAT bit is set in the oflags then we should + * create the file if it does not exist. + */ + + if ((oflags & O_CREAT) == 0) { - fdbg("ERROR: open eacces typ=%d\n", np->nfsv3_type); - error = EACCES; + /* Return ENOENT if the file does not exist and we were not asked + * to create it. + */ + + fdbg("ERROR: File does not exist\n"); + error = ENOENT; goto errout_with_semaphore; } + + /* Create the file */ - if (np->n_flag & NMODIFIED) + error = nfs_create(nmp, np, relpath, mode); + if (error != 0) { - if (np->nfsv3_type == NFDIR) - { - np->n_direofoffset = 0; - } + fdbg("ERROR: nfs_create failed: %d\n", error); + goto errout_with_semaphore; } + + /* Fall through to finish the file open operation */ } + /* Initialize the file private data (only need to initialize + * non-zero elements) + */ + + /* Attach the private data to the struct file instance */ + + filep->f_priv = np; + + /* Then insert the new instance into the mountpoint structure. + * It needs to be there (1) to handle error conditions that effect + * all files, and (2) to inform the umount logic that we are busy + * (but a simple reference count could have done that). + */ + + np->n_next = nmp->nm_head; + np->n_flag |= NMODIFIED; + nmp->nm_head = np->n_next; + /* For open/close consistency. */ NFS_INVALIDATE_ATTRCACHE(np); + nfs_semgive(nmp); + return OK; errout_with_semaphore: kfree(np); diff --git a/nuttx/fs/nfs/rpc_clnt.c b/nuttx/fs/nfs/rpc_clnt.c index 243bbb0f04..a78bc6d78e 100644 --- a/nuttx/fs/nfs/rpc_clnt.c +++ b/nuttx/fs/nfs/rpc_clnt.c @@ -241,10 +241,12 @@ rpcclnt_send(struct socket *so, struct sockaddr *nam, int procid, int prog, void *call, struct rpctask *rep) { struct sockaddr *sendnam; + ssize_t nbytes; int error = ESRCH; #ifdef CONFIG_NFS_TCPIP int soflags; #endif + int length; int flags; if (rep != NULL) @@ -290,34 +292,29 @@ rpcclnt_send(struct socket *so, struct sockaddr *nam, int procid, int prog, flags = 0; } + /* Get the length of the call messsage */ + + error = 0; if (prog == PMAPPROG) { - if (procid == PMAPPROC_GETPORT) + if (procid == PMAPPROC_GETPORT || procid == PMAPPROC_UNSET) { - struct rpc_call_pmap *callmsg = (struct rpc_call_pmap *)call; - error = psock_sendto(so, callmsg, sizeof(*callmsg), flags, - sendnam, sizeof(*sendnam)); + length = sizeof(struct rpc_call_pmap); } - else if (procid == PMAPPROC_UNSET) + else { - struct rpc_call_pmap *callmsg = (struct rpc_call_pmap *)call; - error = psock_sendto(so, callmsg, sizeof(*callmsg), flags, - sendnam, sizeof(*sendnam)); + error = EINVAL; } } else if (prog == RPCPROG_MNT) { - if (procid == RPCMNT_UMOUNT) + if (procid == RPCMNT_UMOUNT || procid == RPCMNT_MOUNT) { - struct rpc_call_mount *callmsg = (struct rpc_call_mount *)call; - error = psock_sendto(so, callmsg, sizeof(*callmsg), flags, - sendnam, sizeof(*sendnam)); + length = sizeof(struct rpc_call_mount); } - else if (procid == RPCMNT_MOUNT) + else { - struct rpc_call_mount *callmsg = (struct rpc_call_mount *)call; - error = psock_sendto(so, callmsg, sizeof(*callmsg), flags, - sendnam, sizeof(*sendnam)); + error = EINVAL; } } else if (prog == NFS_PROG) @@ -325,127 +322,98 @@ rpcclnt_send(struct socket *so, struct sockaddr *nam, int procid, int prog, switch (procid) { case NFSPROC_CREATE: - { - struct rpc_call_create *callmsg = (struct rpc_call_create *)call; - error = psock_sendto(so, callmsg, sizeof(*callmsg), flags, - sendnam, sizeof(*sendnam)); - } + length = sizeof(struct rpc_call_create); break; case NFSPROC_READ: - { - struct rpc_call_read *callmsg = (struct rpc_call_read *)call; - error = psock_sendto(so, callmsg, sizeof(*callmsg), flags, - sendnam, sizeof(*sendnam)); - } + length = sizeof(struct rpc_call_read); break; case NFSPROC_WRITE: - { - struct rpc_call_write *callmsg = (struct rpc_call_write *)call; - error = psock_sendto(so, callmsg, sizeof(*callmsg), flags, - sendnam, sizeof(*sendnam)); - } + length = sizeof(struct rpc_call_write); break; case NFSPROC_READDIR: - { - struct rpc_call_readdir *callmsg = (struct rpc_call_readdir *)call; - error = psock_sendto(so, callmsg, sizeof(*callmsg), flags, - sendnam, sizeof(*sendnam)); - } + length = sizeof(struct rpc_call_readdir); break; case NFSPROC_FSSTAT: - { - struct rpc_call_fs *callmsg = (struct rpc_call_fs *)call; - error = psock_sendto(so, callmsg, sizeof(*callmsg), flags, - sendnam, sizeof(*sendnam)); - } + length = sizeof(struct rpc_call_fs); break; case NFSPROC_GETATTR: - { - struct rpc_call_fs *callmsg = (struct rpc_call_fs *)call; - error = psock_sendto(so, callmsg, sizeof(*callmsg), flags, - sendnam, sizeof(*sendnam)); - } + length = sizeof(struct rpc_call_fs); break; case NFSPROC_REMOVE: - { - struct rpc_call_remove *callmsg = (struct rpc_call_remove *)call; - error = psock_sendto(so, callmsg, sizeof(*callmsg), flags, - sendnam, sizeof(*sendnam)); - } + length = sizeof(struct rpc_call_remove); break; case NFSPROC_MKDIR: - { - struct rpc_call_mkdir *callmsg = (struct rpc_call_mkdir *)call; - error = psock_sendto(so, callmsg, sizeof(*callmsg), flags, - sendnam, sizeof(*sendnam)); - } + length = sizeof(struct rpc_call_mkdir); break; case NFSPROC_RMDIR: - { - struct rpc_call_rmdir *callmsg = (struct rpc_call_rmdir *)call; - error = psock_sendto(so, callmsg, sizeof(*callmsg), flags, - sendnam, sizeof(*sendnam)); - } + length = sizeof(struct rpc_call_rmdir); break; case NFSPROC_RENAME: - { - struct rpc_call_rename *callmsg = (struct rpc_call_rename *)call; - error = psock_sendto(so, callmsg, sizeof(*callmsg), flags, - sendnam, sizeof(*sendnam)); - } + length = sizeof(struct rpc_call_rename); break; case NFSPROC_FSINFO: - { - struct rpc_call_fs *callmsg = (struct rpc_call_fs *)call; - error = psock_sendto(so, callmsg, sizeof(*callmsg), flags, - sendnam, sizeof(*sendnam)); - } + length = sizeof(struct rpc_call_fs); break; default: + error = EINVAL; break; } } + else + { + error = EINVAL; + } - if (error < 0) + /* Send the call message */ + + if (error == 0) { - if (rep != NULL) + /* On success, psock_sendto returns the number of bytes sent; + * On failure, it returns -1 with the specific error in errno. + */ + + nbytes = psock_sendto(so, call, length, flags, + sendnam, sizeof(struct sockaddr)); + if (nbytes < 0) { - fdbg("rpc send error %d for service %s\n", error, - rep->r_rpcclnt->rc_prog->prog_name); + /* psock_sendto failed, Sample the error value (subsequent + * calls can change the errno value! + */ - /* Deal with errors for the client side. */ + error = errno; + fdbg("ERROR: psock_sendto failed: %d\n", error); - if (rep->r_flags & TASK_SOFTTERM) + if (rep != NULL) { - error = EINTR; - } - else - { - rep->r_flags |= TASK_MUSTRESEND; + fdbg("rpc send error %d for service %s\n", error, + rep->r_rpcclnt->rc_prog->prog_name); + + /* Deal with errors for the client side. */ + + if (rep->r_flags & TASK_SOFTTERM) + { + error = EINTR; + } + else + { + rep->r_flags |= TASK_MUSTRESEND; + } } } - else - { - fdbg("rpc service send error %d\n", error); - } - - return error; - } - else - { - return 0; } + + return error; } /* Receive a Sun RPC Request/Reply. For SOCK_DGRAM, the work is all |