From ac67055ef2378ea95c34b593ddf9d0a0737a240a Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 22 Jun 2005 17:26:35 -0700 Subject: [CIFS] POSIX extensions, SetFSInfo added Signed-off-by: Steve French@sfrench@us.ibm.com Signed-off-by: Jeremy Allison (jra@samba.org) --- fs/cifs/dir.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'fs/cifs/dir.c') diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 3f3538d4a1f..9360d8fb9ef 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -43,7 +43,7 @@ renew_parental_timestamps(struct dentry *direntry) /* Note: caller must free return buffer */ char * -build_path_from_dentry(struct dentry *direntry) +build_path_from_dentry(struct dentry *direntry, const struct cifs_sb_info *cifs_sb) { struct dentry *temp; int namelen = 0; @@ -74,7 +74,7 @@ cifs_bp_rename_retry: if (namelen < 0) { break; } else { - full_path[namelen] = '\\'; + full_path[namelen] = CIFS_DIR_SEP(cifs_sb); strncpy(full_path + namelen + 1, temp->d_name.name, temp->d_name.len); cFYI(0, (" name: %s ", full_path + namelen)); @@ -138,7 +138,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, pTcon = cifs_sb->tcon; down(&direntry->d_sb->s_vfs_rename_sem); - full_path = build_path_from_dentry(direntry); + full_path = build_path_from_dentry(direntry, cifs_sb); up(&direntry->d_sb->s_vfs_rename_sem); if(full_path == NULL) { FreeXid(xid); @@ -299,7 +299,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev pTcon = cifs_sb->tcon; down(&direntry->d_sb->s_vfs_rename_sem); - full_path = build_path_from_dentry(direntry); + full_path = build_path_from_dentry(direntry, cifs_sb); up(&direntry->d_sb->s_vfs_rename_sem); if(full_path == NULL) rc = -ENOMEM; @@ -360,7 +360,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct name /* can not grab the rename sem here since it would deadlock in the cases (beginning of sys_rename itself) in which we already have the sb rename sem */ - full_path = build_path_from_dentry(direntry); + full_path = build_path_from_dentry(direntry, cifs_sb); if(full_path == NULL) { FreeXid(xid); return ERR_PTR(-ENOMEM); -- cgit v1.2.3 From d7245c2ccf14cde2023273c1ec246732d96e2c27 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 14 Jul 2005 18:25:12 -0500 Subject: [CIFS] Add compat with SFU (part 1) This should help the case of creating fifos and other special files to servers which do not support the Unix extensions. Signed-off-by: Steve French (sfrench@us.ibm.com) Thanks to Martin Koeppe for his suggestions and good analysis --- fs/cifs/dir.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'fs/cifs/dir.c') diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 9360d8fb9ef..0d5e27fec92 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -209,7 +209,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, CIFS_MOUNT_MAP_SPECIAL_CHR); } else { - /* BB implement via Windows security descriptors */ + /* BB implement mode setting via Windows security descriptors */ /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/ /* could set r/o dos attribute if mode & 0222 == 0 */ } @@ -326,6 +326,16 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev if(rc == 0) d_instantiate(direntry, newinode); } + } else { + if((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && + (special_file(mode))) { + + cFYI(1,("sfu compat create special file")); + /* Attributes = cpu_to_le32(ATTR_SYSTEM); + rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, ...); */ + + /* add code here to set EAs */ + } } kfree(full_path); -- cgit v1.2.3 From eda3c029899cbf435d76fea43b7e1404439ccec9 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 21 Jul 2005 15:20:28 -0700 Subject: [CIFS] Add compat with SFU (part 2) Creating FIFOs to non-Unix servers (with cifs mounts for which sfu option was specified) now works. Signed-off-by: Steve French (sfrench@us.ibm.com) Thanks to Martin Koeppe for his assistance --- fs/cifs/dir.c | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) (limited to 'fs/cifs/dir.c') diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 0d5e27fec92..c0f20fc0929 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -327,13 +327,39 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev d_instantiate(direntry, newinode); } } else { - if((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && - (special_file(mode))) { + if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { + int oplock = 0; + u16 fileHandle; + FILE_ALL_INFO * buf; cFYI(1,("sfu compat create special file")); - /* Attributes = cpu_to_le32(ATTR_SYSTEM); - rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, ...); */ + buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL); + if(buf == NULL) { + kfree(full_path); + FreeXid(xid); + return -ENOMEM; + } + + rc = CIFSSMBOpen(xid, pTcon, full_path, + FILE_CREATE, /* fail if exists */ + GENERIC_WRITE /* BB would + WRITE_OWNER | WRITE_DAC be better? */, + /* Create a file and set the + file attribute to SYSTEM */ + CREATE_NOT_DIR | CREATE_OPTION_SPECIAL, + &fileHandle, &oplock, buf, + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); + + if(!rc) { + /* BB Do not bother to decode buf since no + local inode yet to put timestamps in */ + CIFSSMBClose(xid, pTcon, fileHandle); + d_drop(direntry); + } + kfree(buf); /* add code here to set EAs */ } } -- cgit v1.2.3 From 4a6d87f1db06c9670251d6c72a89319e7d1cbaee Mon Sep 17 00:00:00 2001 From: Steve French Date: Sat, 13 Aug 2005 08:15:54 -0700 Subject: [CIFS] Add missing check for path name allocation failure. Remove four redundant null pointer checks before cifs_buf_release. Found by coverity analyzer. Signed-off-by: Steve French (sfrench@us.ibm.com) --- fs/cifs/dir.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'fs/cifs/dir.c') diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index c0f20fc0929..c619d45060c 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -226,7 +226,8 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, } if (rc != 0) { - cFYI(1,("Create worked but get_inode_info failed with rc = %d", + cFYI(1, + ("Create worked but get_inode_info failed rc = %d", rc)); } else { direntry->d_op = &cifs_dentry_ops; @@ -303,8 +304,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev up(&direntry->d_sb->s_vfs_rename_sem); if(full_path == NULL) rc = -ENOMEM; - - if (full_path && (pTcon->ses->capabilities & CAP_UNIX)) { + else if (pTcon->ses->capabilities & CAP_UNIX) { if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,(__u64)current->euid,(__u64)current->egid, -- cgit v1.2.3 From b92327fe6b25d60004b79df9e3c19091c03118ba Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 22 Aug 2005 20:09:43 -0700 Subject: [CIFS] Finish up of case-insensitive dentry handling for cifs. This will eventually (or should eventually) be common code for jfs, smbfs, etc. but in the meantime is small enough and necessary when mounting case insensitive to Windows (nocase). Signed-off-by: Shaggy (shaggy@austin.ibm.com) Signed-off-by: Steve French (sfrench@us.ibm.com) --- fs/cifs/dir.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 3 deletions(-) (limited to 'fs/cifs/dir.c') diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index c619d45060c..5311c50734b 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -230,7 +230,10 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, ("Create worked but get_inode_info failed rc = %d", rc)); } else { - direntry->d_op = &cifs_dentry_ops; + if (pTcon->nocase) + direntry->d_op = &cifs_ci_dentry_ops; + else + direntry->d_op = &cifs_dentry_ops; d_instantiate(direntry, newinode); } if((nd->flags & LOOKUP_OPEN) == FALSE) { @@ -322,7 +325,10 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev if(!rc) { rc = cifs_get_inode_info_unix(&newinode, full_path, inode->i_sb,xid); - direntry->d_op = &cifs_dentry_ops; + if (pTcon->nocase) + direntry->d_op = &cifs_ci_dentry_ops; + else + direntry->d_op = &cifs_dentry_ops; if(rc == 0) d_instantiate(direntry, newinode); } @@ -418,7 +424,10 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct name parent_dir_inode->i_sb,xid); if ((rc == 0) && (newInode != NULL)) { - direntry->d_op = &cifs_dentry_ops; + if (pTcon->nocase) + direntry->d_op = &cifs_ci_dentry_ops; + else + direntry->d_op = &cifs_dentry_ops; d_add(direntry, newInode); /* since paths are not looked up by component - the parent directories are presumed to be good here */ @@ -477,3 +486,42 @@ struct dentry_operations cifs_dentry_ops = { /* d_delete: cifs_d_delete, *//* not needed except for debugging */ /* no need for d_hash, d_compare, d_release, d_iput ... yet. BB confirm this BB */ }; + +static int cifs_ci_hash(struct dentry *dentry, struct qstr *q) +{ + struct nls_table *codepage = CIFS_SB(dentry->d_inode->i_sb)->local_nls; + unsigned long hash; + int i; + + hash = init_name_hash(); + for (i = 0; i < q->len; i++) + hash = partial_name_hash(nls_tolower(codepage, q->name[i]), + hash); + q->hash = end_name_hash(hash); + + return 0; +} + +static int cifs_ci_compare(struct dentry *dentry, struct qstr *a, + struct qstr *b) +{ + struct nls_table *codepage = CIFS_SB(dentry->d_inode->i_sb)->local_nls; + + if ((a->len == b->len) && + (nls_strnicmp(codepage, a->name, b->name, a->len) == 0)) { + /* + * To preserve case, don't let an existing negative dentry's + * case take precedence. If a is not a negative dentry, this + * should have no side effects + */ + memcpy((unsigned char *)a->name, b->name, a->len); + return 0; + } + return 1; +} + +struct dentry_operations cifs_ci_dentry_ops = { + .d_revalidate = cifs_d_revalidate, + .d_hash = cifs_ci_hash, + .d_compare = cifs_ci_compare, +}; -- cgit v1.2.3 From a9d02ad49013c8fc527f06ca66417103cdbb08b6 Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 24 Aug 2005 23:06:05 -0700 Subject: [CIFS] Support for legacy servers part 3 - Add support for Open and most of Read support. Signed-off-by: Steve French --- fs/cifs/dir.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'fs/cifs/dir.c') diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 5311c50734b..248ddebd67f 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -184,6 +184,13 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, desiredAccess, CREATE_NOT_DIR, &fileHandle, &oplock, buf, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + if(rc == -EIO) { + /* old server, retry the open legacy style */ + rc = SMBLegacyOpen(xid, pTcon, full_path, disposition, + desiredAccess, CREATE_NOT_DIR, + &fileHandle, &oplock, buf, cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + } if (rc) { cFYI(1, ("cifs_create returned 0x%x ", rc)); } else { -- cgit v1.2.3 From 7f57356b70dda014ef269135942426e4a852023e Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 30 Aug 2005 11:32:14 -0700 Subject: [CIFS] Remove cifs_sb argument from *build_path_from_dentry This argument was added in a recent patch, but is unnecessary, since the superblock is easily obtained from the dentry. Signed-off-by: Dave Kleikamp Signed-off-by: Steve French --- fs/cifs/dir.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'fs/cifs/dir.c') diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 248ddebd67f..cf90c9ad2c8 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -43,11 +43,12 @@ renew_parental_timestamps(struct dentry *direntry) /* Note: caller must free return buffer */ char * -build_path_from_dentry(struct dentry *direntry, const struct cifs_sb_info *cifs_sb) +build_path_from_dentry(struct dentry *direntry) { struct dentry *temp; int namelen = 0; char *full_path; + char dirsep = CIFS_DIR_SEP(CIFS_SB(direntry->d_sb)); if(direntry == NULL) return NULL; /* not much we can do if dentry is freed and @@ -74,7 +75,7 @@ cifs_bp_rename_retry: if (namelen < 0) { break; } else { - full_path[namelen] = CIFS_DIR_SEP(cifs_sb); + full_path[namelen] = dirsep; strncpy(full_path + namelen + 1, temp->d_name.name, temp->d_name.len); cFYI(0, (" name: %s ", full_path + namelen)); @@ -138,7 +139,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, pTcon = cifs_sb->tcon; down(&direntry->d_sb->s_vfs_rename_sem); - full_path = build_path_from_dentry(direntry, cifs_sb); + full_path = build_path_from_dentry(direntry); up(&direntry->d_sb->s_vfs_rename_sem); if(full_path == NULL) { FreeXid(xid); @@ -310,7 +311,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev pTcon = cifs_sb->tcon; down(&direntry->d_sb->s_vfs_rename_sem); - full_path = build_path_from_dentry(direntry, cifs_sb); + full_path = build_path_from_dentry(direntry); up(&direntry->d_sb->s_vfs_rename_sem); if(full_path == NULL) rc = -ENOMEM; @@ -409,7 +410,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct name /* can not grab the rename sem here since it would deadlock in the cases (beginning of sys_rename itself) in which we already have the sb rename sem */ - full_path = build_path_from_dentry(direntry, cifs_sb); + full_path = build_path_from_dentry(direntry); if(full_path == NULL) { FreeXid(xid); return ERR_PTR(-ENOMEM); -- cgit v1.2.3