On Mon, 3 Sep 2012 18:06:06 -0500
[email protected] wrote:
> From: Shirish Pargaonkar <[email protected]>
>
>
> Add support of Alternate Data Streams (ads).
> For the support, we need to add additional (desired) access flags
> to the generic ones that cifs client does currently.
> The ads files have a : in the name, so that is used to differentiate
> and add additional desired access.
> One operations that does not work is Rename (0x7).
>
>
> Signed-off-by: Shirish Pargaonkar <[email protected]>
> ---
> fs/cifs/dir.c | 12 ++++++++++--
> fs/cifs/file.c | 45 ++++++++++++++++++++++++++++++++++-----------
> fs/cifs/inode.c | 14 ++++++++++++++
> 3 files changed, 58 insertions(+), 13 deletions(-)
>
> diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
> index cbe709a..8f8d546 100644
> --- a/fs/cifs/dir.c
> +++ b/fs/cifs/dir.c
> @@ -245,10 +245,18 @@ cifs_do_create(struct inode *inode, struct dentry
> *direntry, unsigned int xid,
> }
>
> desiredAccess = 0;
> - if (OPEN_FMODE(oflags) & FMODE_READ)
> + if (OPEN_FMODE(oflags) & FMODE_READ) {
> desiredAccess |= GENERIC_READ; /* is this too little? */
> - if (OPEN_FMODE(oflags) & FMODE_WRITE)
> + if (strstr(full_path, ":"))
> + desiredAccess |= FILE_READ_DATA | FILE_READ_EA |
> + FILE_READ_ATTRIBUTES | READ_CONTROL;
> + }
> + if (OPEN_FMODE(oflags) & FMODE_WRITE) {
> desiredAccess |= GENERIC_WRITE;
> + if (strstr(full_path, ":"))
> + desiredAccess |= FILE_WRITE_DATA | FILE_APPEND_DATA |
> + FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES;
> + }
>
> disposition = FILE_OVERWRITE_IF;
> if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
> diff --git a/fs/cifs/file.c b/fs/cifs/file.c
> index 9154192..80f35f8 100644
> --- a/fs/cifs/file.c
> +++ b/fs/cifs/file.c
> @@ -43,22 +43,41 @@
> #include "cifs_fs_sb.h"
> #include "fscache.h"
>
> -static inline int cifs_convert_flags(unsigned int flags)
> -{
> - if ((flags & O_ACCMODE) == O_RDONLY)
> - return GENERIC_READ;
> - else if ((flags & O_ACCMODE) == O_WRONLY)
> - return GENERIC_WRITE;
> - else if ((flags & O_ACCMODE) == O_RDWR) {
> +static inline int cifs_convert_flags(char *full_path, unsigned int flags)
> +{
> + int daccess = 0;
> +
> + if ((flags & O_ACCMODE) == O_RDONLY) {
> + daccess = GENERIC_READ;
> + if (strstr(full_path, ":"))
> + daccess |= FILE_READ_DATA | FILE_READ_EA |
> + FILE_READ_ATTRIBUTES | READ_CONTROL;
> + return daccess;
> + } else if ((flags & O_ACCMODE) == O_WRONLY) {
> + daccess = GENERIC_WRITE;
> + if (strstr(full_path, ":"))
> + daccess |= FILE_WRITE_DATA | FILE_APPEND_DATA |
> + FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES;
> + return daccess;
> + } else if ((flags & O_ACCMODE) == O_RDWR) {
> /* GENERIC_ALL is too much permission to request
> can cause unnecessary access denied on create */
> /* return GENERIC_ALL; */
> - return (GENERIC_READ | GENERIC_WRITE);
> + daccess = GENERIC_READ | GENERIC_WRITE;
> + if (strstr(full_path, ":"))
> + daccess |= FILE_READ_DATA | FILE_WRITE_DATA |
> + FILE_APPEND_DATA | FILE_READ_EA |
> + FILE_WRITE_EA | FILE_READ_ATTRIBUTES |
> + FILE_WRITE_ATTRIBUTES | READ_CONTROL;
> + return daccess;
So if any component in the pathname happens to have a ':' in it, then
we'll open the file with a different set of access flags? ':' is a
perfectly legitimate character in posix pathnames. That sounds like a
very bad heuristic.
> }
>
> - return (READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES |
> + daccess = READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES |
> FILE_WRITE_EA | FILE_APPEND_DATA | FILE_WRITE_DATA |
> - FILE_READ_DATA);
> + FILE_READ_DATA;
> +
> + return daccess;
> +
> }
>
> static u32 cifs_posix_convert_flags(unsigned int flags)
> @@ -149,6 +168,8 @@ int cifs_posix_open(char *full_path, struct inode
> **pinode,
> goto posix_open_ret; /* caller does not need info */
>
> cifs_unix_basic_to_fattr(&fattr, presp_data, cifs_sb);
> + if (strstr(full_path, ":"))
> + fattr.cf_flags |= S_PRIVATE;
>
> /* get new inode and set it up */
> if (*pinode == NULL) {
> @@ -158,6 +179,8 @@ int cifs_posix_open(char *full_path, struct inode
> **pinode,
> rc = -ENOMEM;
> goto posix_open_ret;
> }
> + if (strstr(full_path, ":"))
> + (*pinode)->i_flags |= S_PRIVATE;
> } else {
> cifs_fattr_to_inode(*pinode, &fattr);
> }
> @@ -178,7 +201,7 @@ cifs_nt_open(char *full_path, struct inode *inode, struct
> cifs_sb_info *cifs_sb,
> int create_options = CREATE_NOT_DIR;
> FILE_ALL_INFO *buf;
>
> - desiredAccess = cifs_convert_flags(f_flags);
> + desiredAccess = cifs_convert_flags(full_path, f_flags);
>
> /*********************************************************************
> * open flag mapping table:
> @@ -538,7 +561,7 @@ static int cifs_reopen_file(struct cifsFileInfo
> *pCifsFile, bool can_flush)
> in the reconnect path it is important to retry hard */
> }
>
> - desiredAccess = cifs_convert_flags(pCifsFile->f_flags);
> + desiredAccess = cifs_convert_flags(full_path, pCifsFile->f_flags);
>
> if (backup_cred(cifs_sb))
> create_options |= CREATE_OPEN_BACKUP_INTENT;
> diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
> index 7354877..0bde128 100644
> --- a/fs/cifs/inode.c
> +++ b/fs/cifs/inode.c
> @@ -351,12 +351,17 @@ int cifs_get_inode_info_unix(struct inode **pinode,
> cFYI(1, "CIFSCheckMFSymlink: %d", tmprc);
> }
>
> + if (strstr(full_path, ":"))
> + fattr.cf_flags |= S_PRIVATE;
> +
> if (*pinode == NULL) {
> /* get new inode */
> cifs_fill_uniqueid(sb, &fattr);
> *pinode = cifs_iget(sb, &fattr);
> if (!*pinode)
> rc = -ENOMEM;
> + if (strstr(full_path, ":"))
> + (*pinode)->i_flags |= S_PRIVATE;
> } else {
> /* we already have inode, update it */
> cifs_fattr_to_inode(*pinode, &fattr);
> @@ -713,10 +718,15 @@ cifs_get_inode_info(struct inode **inode, const char
> *full_path,
> cFYI(1, "CIFSCheckMFSymlink: %d", tmprc);
> }
>
> + if (strstr(full_path, ":"))
> + fattr.cf_flags |= S_PRIVATE;
> +
> if (!*inode) {
> *inode = cifs_iget(sb, &fattr);
> if (!*inode)
> rc = -ENOMEM;
> + if (strstr(full_path, ":"))
> + (*inode)->i_flags |= S_PRIVATE;
> } else {
> cifs_fattr_to_inode(*inode, &fattr);
> }
> @@ -748,6 +758,10 @@ cifs_find_inode(struct inode *inode, void *opaque)
> if ((inode->i_mode & S_IFMT) != (fattr->cf_mode & S_IFMT))
> return 0;
>
> + /* don't match inode with different flags */
> + if ((inode->i_flags & S_PRIVATE) != (fattr->cf_flags & S_PRIVATE))
> + return 0;
> +
> /* if it's not a directory or has no dentries, then flag it */
> if (S_ISDIR(inode->i_mode) && !hlist_empty(&inode->i_dentry))
> fattr->cf_flags |= CIFS_FATTR_INO_COLLISION;
--
Jeff Layton <[email protected]>
--
To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html