Commit 0f44bc36 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.samba.org/sfrench/cifs-2.6

Pull cifs fixes from Steve French:
 "A set of cifs fixes (mostly for symlinks, and SMB2 xattrs) and
  cleanups"

* 'for-linus' of git://git.samba.org/sfrench/cifs-2.6:
  cifs: Fix check for regular file in couldbe_mf_symlink()
  [CIFS] Fix SMB2 mounts so they don't try to set or get xattrs via cifs
  CIFS: Cleanup cifs open codepath
  CIFS: Remove extra indentation in cifs_sfu_type
  CIFS: Cleanup cifs_mknod
  CIFS: Cleanup CIFSSMBOpen
  cifs: Add support for follow_link on dfs shares under posix extensions
  cifs: move unix extension call to cifs_query_symlink()
  cifs: Re-order M-F Symlink code
  cifs: Add create MFSymlinks to protocol ops struct
  cifs: use protocol specific call for query_mf_symlink()
  cifs: Rename MF symlink function names
  cifs: Rename and cleanup open_query_close_cifs_symlink()
  cifs: Fix memory leak in cifs_hardlink()
parents efc518eb a9a315d4
...@@ -895,9 +895,10 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, ...@@ -895,9 +895,10 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
int oplock = 0; int oplock = 0;
unsigned int xid; unsigned int xid;
int rc, create_options = 0; int rc, create_options = 0;
__u16 fid;
struct cifs_tcon *tcon; struct cifs_tcon *tcon;
struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
struct cifs_fid fid;
struct cifs_open_parms oparms;
if (IS_ERR(tlink)) if (IS_ERR(tlink))
return ERR_CAST(tlink); return ERR_CAST(tlink);
...@@ -908,12 +909,19 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, ...@@ -908,12 +909,19 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
if (backup_cred(cifs_sb)) if (backup_cred(cifs_sb))
create_options |= CREATE_OPEN_BACKUP_INTENT; create_options |= CREATE_OPEN_BACKUP_INTENT;
rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL, oparms.tcon = tcon;
create_options, &fid, &oplock, NULL, cifs_sb->local_nls, oparms.cifs_sb = cifs_sb;
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); oparms.desired_access = READ_CONTROL;
oparms.create_options = create_options;
oparms.disposition = FILE_OPEN;
oparms.path = path;
oparms.fid = &fid;
oparms.reconnect = false;
rc = CIFS_open(xid, &oparms, &oplock, NULL);
if (!rc) { if (!rc) {
rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen); rc = CIFSSMBGetCIFSACL(xid, tcon, fid.netfid, &pntsd, pacllen);
CIFSSMBClose(xid, tcon, fid); CIFSSMBClose(xid, tcon, fid.netfid);
} }
cifs_put_tlink(tlink); cifs_put_tlink(tlink);
...@@ -950,10 +958,11 @@ int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen, ...@@ -950,10 +958,11 @@ int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
int oplock = 0; int oplock = 0;
unsigned int xid; unsigned int xid;
int rc, access_flags, create_options = 0; int rc, access_flags, create_options = 0;
__u16 fid;
struct cifs_tcon *tcon; struct cifs_tcon *tcon;
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
struct cifs_fid fid;
struct cifs_open_parms oparms;
if (IS_ERR(tlink)) if (IS_ERR(tlink))
return PTR_ERR(tlink); return PTR_ERR(tlink);
...@@ -969,18 +978,25 @@ int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen, ...@@ -969,18 +978,25 @@ int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
else else
access_flags = WRITE_DAC; access_flags = WRITE_DAC;
rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, access_flags, oparms.tcon = tcon;
create_options, &fid, &oplock, NULL, cifs_sb->local_nls, oparms.cifs_sb = cifs_sb;
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); oparms.desired_access = access_flags;
oparms.create_options = create_options;
oparms.disposition = FILE_OPEN;
oparms.path = path;
oparms.fid = &fid;
oparms.reconnect = false;
rc = CIFS_open(xid, &oparms, &oplock, NULL);
if (rc) { if (rc) {
cifs_dbg(VFS, "Unable to open file to set ACL\n"); cifs_dbg(VFS, "Unable to open file to set ACL\n");
goto out; goto out;
} }
rc = CIFSSMBSetCIFSACL(xid, tcon, fid, pnntsd, acllen, aclflag); rc = CIFSSMBSetCIFSACL(xid, tcon, fid.netfid, pnntsd, acllen, aclflag);
cifs_dbg(NOISY, "SetCIFSACL rc = %d\n", rc); cifs_dbg(NOISY, "SetCIFSACL rc = %d\n", rc);
CIFSSMBClose(xid, tcon, fid); CIFSSMBClose(xid, tcon, fid.netfid);
out: out:
free_xid(xid); free_xid(xid);
cifs_put_tlink(tlink); cifs_put_tlink(tlink);
......
...@@ -370,8 +370,12 @@ struct smb_version_operations { ...@@ -370,8 +370,12 @@ struct smb_version_operations {
void (*new_lease_key)(struct cifs_fid *); void (*new_lease_key)(struct cifs_fid *);
int (*generate_signingkey)(struct cifs_ses *); int (*generate_signingkey)(struct cifs_ses *);
int (*calc_signature)(struct smb_rqst *, struct TCP_Server_Info *); int (*calc_signature)(struct smb_rqst *, struct TCP_Server_Info *);
int (*query_mf_symlink)(const unsigned char *, char *, unsigned int *, int (*query_mf_symlink)(unsigned int, struct cifs_tcon *,
struct cifs_sb_info *, unsigned int); struct cifs_sb_info *, const unsigned char *,
char *, unsigned int *);
int (*create_mf_symlink)(unsigned int, struct cifs_tcon *,
struct cifs_sb_info *, const unsigned char *,
char *, unsigned int *);
/* if we can do cache read operations */ /* if we can do cache read operations */
bool (*is_read_op)(__u32); bool (*is_read_op)(__u32);
/* set oplock level for the inode */ /* set oplock level for the inode */
...@@ -385,6 +389,12 @@ struct smb_version_operations { ...@@ -385,6 +389,12 @@ struct smb_version_operations {
struct cifsFileInfo *target_file, u64 src_off, u64 len, struct cifsFileInfo *target_file, u64 src_off, u64 len,
u64 dest_off); u64 dest_off);
int (*validate_negotiate)(const unsigned int, struct cifs_tcon *); int (*validate_negotiate)(const unsigned int, struct cifs_tcon *);
ssize_t (*query_all_EAs)(const unsigned int, struct cifs_tcon *,
const unsigned char *, const unsigned char *, char *,
size_t, const struct nls_table *, int);
int (*set_EA)(const unsigned int, struct cifs_tcon *, const char *,
const char *, const void *, const __u16,
const struct nls_table *, int);
}; };
struct smb_version_values { struct smb_version_values {
......
...@@ -362,11 +362,8 @@ extern int CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -362,11 +362,8 @@ extern int CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
const struct nls_table *nls_codepage); const struct nls_table *nls_codepage);
extern int CIFSSMB_set_compression(const unsigned int xid, extern int CIFSSMB_set_compression(const unsigned int xid,
struct cifs_tcon *tcon, __u16 fid); struct cifs_tcon *tcon, __u16 fid);
extern int CIFSSMBOpen(const unsigned int xid, struct cifs_tcon *tcon, extern int CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms,
const char *fileName, const int disposition, int *oplock, FILE_ALL_INFO *buf);
const int access_flags, const int omode,
__u16 *netfid, int *pOplock, FILE_ALL_INFO *,
const struct nls_table *nls_codepage, int remap);
extern int SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon, extern int SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
const char *fileName, const int disposition, const char *fileName, const int disposition,
const int access_flags, const int omode, const int access_flags, const int omode,
...@@ -476,8 +473,8 @@ extern int CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -476,8 +473,8 @@ extern int CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
extern int CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon, extern int CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
const int netfid, __u64 *pExtAttrBits, __u64 *pMask); const int netfid, __u64 *pExtAttrBits, __u64 *pMask);
extern void cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb); extern void cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb);
extern bool CIFSCouldBeMFSymlink(const struct cifs_fattr *fattr); extern bool couldbe_mf_symlink(const struct cifs_fattr *fattr);
extern int CIFSCheckMFSymlink(unsigned int xid, struct cifs_tcon *tcon, extern int check_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb, struct cifs_sb_info *cifs_sb,
struct cifs_fattr *fattr, struct cifs_fattr *fattr,
const unsigned char *path); const unsigned char *path);
...@@ -496,7 +493,12 @@ void cifs_writev_complete(struct work_struct *work); ...@@ -496,7 +493,12 @@ void cifs_writev_complete(struct work_struct *work);
struct cifs_writedata *cifs_writedata_alloc(unsigned int nr_pages, struct cifs_writedata *cifs_writedata_alloc(unsigned int nr_pages,
work_func_t complete); work_func_t complete);
void cifs_writedata_release(struct kref *refcount); void cifs_writedata_release(struct kref *refcount);
int open_query_close_cifs_symlink(const unsigned char *path, char *pbuf, int cifs_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
unsigned int *pbytes_read, struct cifs_sb_info *cifs_sb, struct cifs_sb_info *cifs_sb,
unsigned int xid); const unsigned char *path, char *pbuf,
unsigned int *pbytes_read);
int cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb,
const unsigned char *path, char *pbuf,
unsigned int *pbytes_written);
#endif /* _CIFSPROTO_H */ #endif /* _CIFSPROTO_H */
...@@ -1273,104 +1273,124 @@ SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -1273,104 +1273,124 @@ SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
} }
int int
CIFSSMBOpen(const unsigned int xid, struct cifs_tcon *tcon, CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock,
const char *fileName, const int openDisposition, FILE_ALL_INFO *buf)
const int access_flags, const int create_options, __u16 *netfid,
int *pOplock, FILE_ALL_INFO *pfile_info,
const struct nls_table *nls_codepage, int remap)
{ {
int rc = -EACCES; int rc = -EACCES;
OPEN_REQ *pSMB = NULL; OPEN_REQ *req = NULL;
OPEN_RSP *pSMBr = NULL; OPEN_RSP *rsp = NULL;
int bytes_returned; int bytes_returned;
int name_len; int name_len;
__u16 count; __u16 count;
struct cifs_sb_info *cifs_sb = oparms->cifs_sb;
struct cifs_tcon *tcon = oparms->tcon;
int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
const struct nls_table *nls = cifs_sb->local_nls;
int create_options = oparms->create_options;
int desired_access = oparms->desired_access;
int disposition = oparms->disposition;
const char *path = oparms->path;
openRetry: openRetry:
rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB, rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **)&req,
(void **) &pSMBr); (void **)&rsp);
if (rc) if (rc)
return rc; return rc;
pSMB->AndXCommand = 0xFF; /* none */ /* no commands go after this */
req->AndXCommand = 0xFF;
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { if (req->hdr.Flags2 & SMBFLG2_UNICODE) {
count = 1; /* account for one byte pad to word boundary */ /* account for one byte pad to word boundary */
name_len = count = 1;
cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1), name_len = cifsConvertToUTF16((__le16 *)(req->fileName + 1),
fileName, PATH_MAX, nls_codepage, remap); path, PATH_MAX, nls, remap);
name_len++; /* trailing null */ /* trailing null */
name_len++;
name_len *= 2; name_len *= 2;
pSMB->NameLength = cpu_to_le16(name_len); req->NameLength = cpu_to_le16(name_len);
} else { /* BB improve check for buffer overruns BB */ } else {
count = 0; /* no pad */ /* BB improve check for buffer overruns BB */
name_len = strnlen(fileName, PATH_MAX); /* no pad */
name_len++; /* trailing null */ count = 0;
pSMB->NameLength = cpu_to_le16(name_len); name_len = strnlen(path, PATH_MAX);
strncpy(pSMB->fileName, fileName, name_len); /* trailing null */
name_len++;
req->NameLength = cpu_to_le16(name_len);
strncpy(req->fileName, path, name_len);
} }
if (*pOplock & REQ_OPLOCK)
pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK); if (*oplock & REQ_OPLOCK)
else if (*pOplock & REQ_BATCHOPLOCK) req->OpenFlags = cpu_to_le32(REQ_OPLOCK);
pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK); else if (*oplock & REQ_BATCHOPLOCK)
pSMB->DesiredAccess = cpu_to_le32(access_flags); req->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
pSMB->AllocationSize = 0;
/* set file as system file if special file such req->DesiredAccess = cpu_to_le32(desired_access);
as fifo and server expecting SFU style and req->AllocationSize = 0;
no Unix extensions */
/*
* Set file as system file if special file such as fifo and server
* expecting SFU style and no Unix extensions.
*/
if (create_options & CREATE_OPTION_SPECIAL) if (create_options & CREATE_OPTION_SPECIAL)
pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM); req->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
else else
pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL); req->FileAttributes = cpu_to_le32(ATTR_NORMAL);
/* XP does not handle ATTR_POSIX_SEMANTICS */ /*
/* but it helps speed up case sensitive checks for other * XP does not handle ATTR_POSIX_SEMANTICS but it helps speed up case
servers such as Samba */ * sensitive checks for other servers such as Samba.
*/
if (tcon->ses->capabilities & CAP_UNIX) if (tcon->ses->capabilities & CAP_UNIX)
pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS); req->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
if (create_options & CREATE_OPTION_READONLY) if (create_options & CREATE_OPTION_READONLY)
pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY); req->FileAttributes |= cpu_to_le32(ATTR_READONLY);
req->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
req->CreateDisposition = cpu_to_le32(disposition);
req->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
pSMB->CreateDisposition = cpu_to_le32(openDisposition);
pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
/* BB Expirement with various impersonation levels and verify */ /* BB Expirement with various impersonation levels and verify */
pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION); req->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
pSMB->SecurityFlags = req->SecurityFlags = SECURITY_CONTEXT_TRACKING|SECURITY_EFFECTIVE_ONLY;
SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
count += name_len; count += name_len;
inc_rfc1001_len(pSMB, count); inc_rfc1001_len(req, count);
pSMB->ByteCount = cpu_to_le16(count); req->ByteCount = cpu_to_le16(count);
/* long_op set to 1 to allow for oplock break timeouts */ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *)req,
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *)rsp, &bytes_returned, 0);
(struct smb_hdr *)pSMBr, &bytes_returned, 0);
cifs_stats_inc(&tcon->stats.cifs_stats.num_opens); cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
if (rc) { if (rc) {
cifs_dbg(FYI, "Error in Open = %d\n", rc); cifs_dbg(FYI, "Error in Open = %d\n", rc);
} else { cifs_buf_release(req);
*pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */ if (rc == -EAGAIN)
*netfid = pSMBr->Fid; /* cifs fid stays in le */ goto openRetry;
/* Let caller know file was created so we can set the mode. */ return rc;
/* Do we care about the CreateAction in any other cases? */
if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
*pOplock |= CIFS_CREATE_ACTION;
if (pfile_info) {
memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
36 /* CreationTime to Attributes */);
/* the file_info buf is endian converted by caller */
pfile_info->AllocationSize = pSMBr->AllocationSize;
pfile_info->EndOfFile = pSMBr->EndOfFile;
pfile_info->NumberOfLinks = cpu_to_le32(1);
pfile_info->DeletePending = 0;
}
} }
cifs_buf_release(pSMB); /* 1 byte no need to le_to_cpu */
if (rc == -EAGAIN) *oplock = rsp->OplockLevel;
goto openRetry; /* cifs fid stays in le */
oparms->fid->netfid = rsp->Fid;
/* Let caller know file was created so we can set the mode. */
/* Do we care about the CreateAction in any other cases? */
if (cpu_to_le32(FILE_CREATE) == rsp->CreateAction)
*oplock |= CIFS_CREATE_ACTION;
if (buf) {
/* copy from CreationTime to Attributes */
memcpy((char *)buf, (char *)&rsp->CreationTime, 36);
/* the file_info buf is endian converted by caller */
buf->AllocationSize = rsp->AllocationSize;
buf->EndOfFile = rsp->EndOfFile;
buf->NumberOfLinks = cpu_to_le32(1);
buf->DeletePending = 0;
}
cifs_buf_release(req);
return rc; return rc;
} }
......
...@@ -565,12 +565,13 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode, ...@@ -565,12 +565,13 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode,
int create_options = CREATE_NOT_DIR | CREATE_OPTION_SPECIAL; int create_options = CREATE_NOT_DIR | CREATE_OPTION_SPECIAL;
struct cifs_sb_info *cifs_sb; struct cifs_sb_info *cifs_sb;
struct tcon_link *tlink; struct tcon_link *tlink;
struct cifs_tcon *pTcon; struct cifs_tcon *tcon;
struct cifs_io_parms io_parms; struct cifs_io_parms io_parms;
char *full_path = NULL; char *full_path = NULL;
struct inode *newinode = NULL; struct inode *newinode = NULL;
int oplock = 0; int oplock = 0;
u16 fileHandle; struct cifs_fid fid;
struct cifs_open_parms oparms;
FILE_ALL_INFO *buf = NULL; FILE_ALL_INFO *buf = NULL;
unsigned int bytes_written; unsigned int bytes_written;
struct win_dev *pdev; struct win_dev *pdev;
...@@ -583,7 +584,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode, ...@@ -583,7 +584,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode,
if (IS_ERR(tlink)) if (IS_ERR(tlink))
return PTR_ERR(tlink); return PTR_ERR(tlink);
pTcon = tlink_tcon(tlink); tcon = tlink_tcon(tlink);
xid = get_xid(); xid = get_xid();
...@@ -593,7 +594,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode, ...@@ -593,7 +594,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode,
goto mknod_out; goto mknod_out;
} }
if (pTcon->unix_ext) { if (tcon->unix_ext) {
struct cifs_unix_set_info_args args = { struct cifs_unix_set_info_args args = {
.mode = mode & ~current_umask(), .mode = mode & ~current_umask(),
.ctime = NO_CHANGE_64, .ctime = NO_CHANGE_64,
...@@ -608,7 +609,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode, ...@@ -608,7 +609,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode,
args.uid = INVALID_UID; /* no change */ args.uid = INVALID_UID; /* no change */
args.gid = INVALID_GID; /* no change */ args.gid = INVALID_GID; /* no change */
} }
rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, &args, rc = CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
cifs_sb->local_nls, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
...@@ -640,42 +641,44 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode, ...@@ -640,42 +641,44 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode,
if (backup_cred(cifs_sb)) if (backup_cred(cifs_sb))
create_options |= CREATE_OPEN_BACKUP_INTENT; create_options |= CREATE_OPEN_BACKUP_INTENT;
rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_CREATE, oparms.tcon = tcon;
GENERIC_WRITE, create_options, oparms.cifs_sb = cifs_sb;
&fileHandle, &oplock, buf, cifs_sb->local_nls, oparms.desired_access = GENERIC_WRITE;
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); oparms.create_options = create_options;
oparms.disposition = FILE_CREATE;
oparms.path = full_path;
oparms.fid = &fid;
oparms.reconnect = false;
rc = CIFS_open(xid, &oparms, &oplock, buf);
if (rc) if (rc)
goto mknod_out; goto mknod_out;
/* BB Do not bother to decode buf since no local inode yet to put /*
* timestamps in, but we can reuse it safely */ * BB Do not bother to decode buf since no local inode yet to put
* timestamps in, but we can reuse it safely.
*/
pdev = (struct win_dev *)buf; pdev = (struct win_dev *)buf;
io_parms.netfid = fileHandle; io_parms.netfid = fid.netfid;
io_parms.pid = current->tgid; io_parms.pid = current->tgid;
io_parms.tcon = pTcon; io_parms.tcon = tcon;
io_parms.offset = 0; io_parms.offset = 0;
io_parms.length = sizeof(struct win_dev); io_parms.length = sizeof(struct win_dev);
if (S_ISCHR(mode)) { if (S_ISCHR(mode)) {
memcpy(pdev->type, "IntxCHR", 8); memcpy(pdev->type, "IntxCHR", 8);
pdev->major = pdev->major = cpu_to_le64(MAJOR(device_number));
cpu_to_le64(MAJOR(device_number)); pdev->minor = cpu_to_le64(MINOR(device_number));
pdev->minor = rc = CIFSSMBWrite(xid, &io_parms, &bytes_written, (char *)pdev,
cpu_to_le64(MINOR(device_number)); NULL, 0);
rc = CIFSSMBWrite(xid, &io_parms,
&bytes_written, (char *)pdev,
NULL, 0);
} else if (S_ISBLK(mode)) { } else if (S_ISBLK(mode)) {
memcpy(pdev->type, "IntxBLK", 8); memcpy(pdev->type, "IntxBLK", 8);
pdev->major = pdev->major = cpu_to_le64(MAJOR(device_number));
cpu_to_le64(MAJOR(device_number)); pdev->minor = cpu_to_le64(MINOR(device_number));
pdev->minor = rc = CIFSSMBWrite(xid, &io_parms, &bytes_written, (char *)pdev,
cpu_to_le64(MINOR(device_number)); NULL, 0);
rc = CIFSSMBWrite(xid, &io_parms,
&bytes_written, (char *)pdev,
NULL, 0);
} /* else if (S_ISFIFO) */ } /* else if (S_ISFIFO) */
CIFSSMBClose(xid, pTcon, fileHandle); CIFSSMBClose(xid, tcon, fid.netfid);
d_drop(direntry); d_drop(direntry);
/* FIXME: add code here to set EAs */ /* FIXME: add code here to set EAs */
......
...@@ -678,7 +678,7 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush) ...@@ -678,7 +678,7 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush)
/* /*
* Can not refresh inode by passing in file_info buf to be returned by * Can not refresh inode by passing in file_info buf to be returned by
* CIFSSMBOpen and then calling get_inode_info with returned buf since * ops->open and then calling get_inode_info with returned buf since
* file might have write behind data that needs to be flushed and server * file might have write behind data that needs to be flushed and server
* version of file size can be stale. If we knew for sure that inode was * version of file size can be stale. If we knew for sure that inode was
* not dirty locally we could do this. * not dirty locally we could do this.
......
...@@ -383,10 +383,10 @@ int cifs_get_inode_info_unix(struct inode **pinode, ...@@ -383,10 +383,10 @@ int cifs_get_inode_info_unix(struct inode **pinode,
/* check for Minshall+French symlinks */ /* check for Minshall+French symlinks */
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) { if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
int tmprc = CIFSCheckMFSymlink(xid, tcon, cifs_sb, &fattr, int tmprc = check_mf_symlink(xid, tcon, cifs_sb, &fattr,
full_path); full_path);
if (tmprc) if (tmprc)
cifs_dbg(FYI, "CIFSCheckMFSymlink: %d\n", tmprc); cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc);
} }
if (*pinode == NULL) { if (*pinode == NULL) {
...@@ -404,18 +404,20 @@ int cifs_get_inode_info_unix(struct inode **pinode, ...@@ -404,18 +404,20 @@ int cifs_get_inode_info_unix(struct inode **pinode,
} }
static int static int
cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path, cifs_sfu_type(struct cifs_fattr *fattr, const char *path,
struct cifs_sb_info *cifs_sb, unsigned int xid) struct cifs_sb_info *cifs_sb, unsigned int xid)
{ {
int rc; int rc;
int oplock = 0; int oplock = 0;
__u16 netfid;
struct tcon_link *tlink; struct tcon_link *tlink;
struct cifs_tcon *tcon; struct cifs_tcon *tcon;
struct cifs_fid fid;
struct cifs_open_parms oparms;
struct cifs_io_parms io_parms; struct cifs_io_parms io_parms;
char buf[24]; char buf[24];
unsigned int bytes_read; unsigned int bytes_read;
char *pbuf; char *pbuf;
int buf_type = CIFS_NO_BUFFER;
pbuf = buf; pbuf = buf;
...@@ -436,62 +438,69 @@ cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path, ...@@ -436,62 +438,69 @@ cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path,
return PTR_ERR(tlink); return PTR_ERR(tlink);
tcon = tlink_tcon(tlink); tcon = tlink_tcon(tlink);
rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, GENERIC_READ, oparms.tcon = tcon;
CREATE_NOT_DIR, &netfid, &oplock, NULL, oparms.cifs_sb = cifs_sb;
cifs_sb->local_nls, oparms.desired_access = GENERIC_READ;
cifs_sb->mnt_cifs_flags & oparms.create_options = CREATE_NOT_DIR;
CIFS_MOUNT_MAP_SPECIAL_CHR); oparms.disposition = FILE_OPEN;
if (rc == 0) { oparms.path = path;
int buf_type = CIFS_NO_BUFFER; oparms.fid = &fid;
/* Read header */ oparms.reconnect = false;
io_parms.netfid = netfid;
io_parms.pid = current->tgid; rc = CIFS_open(xid, &oparms, &oplock, NULL);
io_parms.tcon = tcon; if (rc) {
io_parms.offset = 0; cifs_put_tlink(tlink);
io_parms.length = 24; return rc;
rc = CIFSSMBRead(xid, &io_parms, &bytes_read, &pbuf, }
&buf_type);
if ((rc == 0) && (bytes_read >= 8)) { /* Read header */
if (memcmp("IntxBLK", pbuf, 8) == 0) { io_parms.netfid = fid.netfid;
cifs_dbg(FYI, "Block device\n"); io_parms.pid = current->tgid;
fattr->cf_mode |= S_IFBLK; io_parms.tcon = tcon;
fattr->cf_dtype = DT_BLK; io_parms.offset = 0;
if (bytes_read == 24) { io_parms.length = 24;
/* we have enough to decode dev num */
__u64 mjr; /* major */ rc = CIFSSMBRead(xid, &io_parms, &bytes_read, &pbuf, &buf_type);
__u64 mnr; /* minor */ if ((rc == 0) && (bytes_read >= 8)) {
mjr = le64_to_cpu(*(__le64 *)(pbuf+8)); if (memcmp("IntxBLK", pbuf, 8) == 0) {
mnr = le64_to_cpu(*(__le64 *)(pbuf+16)); cifs_dbg(FYI, "Block device\n");
fattr->cf_rdev = MKDEV(mjr, mnr); fattr->cf_mode |= S_IFBLK;
} fattr->cf_dtype = DT_BLK;
} else if (memcmp("IntxCHR", pbuf, 8) == 0) { if (bytes_read == 24) {
cifs_dbg(FYI, "Char device\n"); /* we have enough to decode dev num */
fattr->cf_mode |= S_IFCHR; __u64 mjr; /* major */
fattr->cf_dtype = DT_CHR; __u64 mnr; /* minor */
if (bytes_read == 24) { mjr = le64_to_cpu(*(__le64 *)(pbuf+8));
/* we have enough to decode dev num */ mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
__u64 mjr; /* major */ fattr->cf_rdev = MKDEV(mjr, mnr);
__u64 mnr; /* minor */
mjr = le64_to_cpu(*(__le64 *)(pbuf+8));
mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
fattr->cf_rdev = MKDEV(mjr, mnr);
}
} else if (memcmp("IntxLNK", pbuf, 7) == 0) {
cifs_dbg(FYI, "Symlink\n");
fattr->cf_mode |= S_IFLNK;
fattr->cf_dtype = DT_LNK;
} else {
fattr->cf_mode |= S_IFREG; /* file? */
fattr->cf_dtype = DT_REG;
rc = -EOPNOTSUPP;
} }
} else if (memcmp("IntxCHR", pbuf, 8) == 0) {
cifs_dbg(FYI, "Char device\n");
fattr->cf_mode |= S_IFCHR;
fattr->cf_dtype = DT_CHR;
if (bytes_read == 24) {
/* we have enough to decode dev num */
__u64 mjr; /* major */
__u64 mnr; /* minor */
mjr = le64_to_cpu(*(__le64 *)(pbuf+8));
mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
fattr->cf_rdev = MKDEV(mjr, mnr);
}
} else if (memcmp("IntxLNK", pbuf, 7) == 0) {
cifs_dbg(FYI, "Symlink\n");
fattr->cf_mode |= S_IFLNK;
fattr->cf_dtype = DT_LNK;
} else { } else {
fattr->cf_mode |= S_IFREG; /* then it is a file */ fattr->cf_mode |= S_IFREG; /* file? */
fattr->cf_dtype = DT_REG; fattr->cf_dtype = DT_REG;
rc = -EOPNOTSUPP; /* or some unknown SFU type */ rc = -EOPNOTSUPP;
} }
CIFSSMBClose(xid, tcon, netfid); } else {
fattr->cf_mode |= S_IFREG; /* then it is a file */
fattr->cf_dtype = DT_REG;
rc = -EOPNOTSUPP; /* or some unknown SFU type */
} }
CIFSSMBClose(xid, tcon, fid.netfid);
cifs_put_tlink(tlink); cifs_put_tlink(tlink);
return rc; return rc;
} }
...@@ -800,10 +809,10 @@ cifs_get_inode_info(struct inode **inode, const char *full_path, ...@@ -800,10 +809,10 @@ cifs_get_inode_info(struct inode **inode, const char *full_path,
/* check for Minshall+French symlinks */ /* check for Minshall+French symlinks */
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) { if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
tmprc = CIFSCheckMFSymlink(xid, tcon, cifs_sb, &fattr, tmprc = check_mf_symlink(xid, tcon, cifs_sb, &fattr,
full_path); full_path);
if (tmprc) if (tmprc)
cifs_dbg(FYI, "CIFSCheckMFSymlink: %d\n", tmprc); cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc);
} }
if (!*inode) { if (!*inode) {
...@@ -1032,7 +1041,8 @@ cifs_rename_pending_delete(const char *full_path, struct dentry *dentry, ...@@ -1032,7 +1041,8 @@ cifs_rename_pending_delete(const char *full_path, struct dentry *dentry,
{ {
int oplock = 0; int oplock = 0;
int rc; int rc;
__u16 netfid; struct cifs_fid fid;
struct cifs_open_parms oparms;
struct inode *inode = dentry->d_inode; struct inode *inode = dentry->d_inode;
struct cifsInodeInfo *cifsInode = CIFS_I(inode); struct cifsInodeInfo *cifsInode = CIFS_I(inode);
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
...@@ -1055,10 +1065,16 @@ cifs_rename_pending_delete(const char *full_path, struct dentry *dentry, ...@@ -1055,10 +1065,16 @@ cifs_rename_pending_delete(const char *full_path, struct dentry *dentry,
goto out; goto out;
} }
rc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN, oparms.tcon = tcon;
DELETE|FILE_WRITE_ATTRIBUTES, CREATE_NOT_DIR, oparms.cifs_sb = cifs_sb;
&netfid, &oplock, NULL, cifs_sb->local_nls, oparms.desired_access = DELETE | FILE_WRITE_ATTRIBUTES;
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); oparms.create_options = CREATE_NOT_DIR;
oparms.disposition = FILE_OPEN;
oparms.path = full_path;
oparms.fid = &fid;
oparms.reconnect = false;
rc = CIFS_open(xid, &oparms, &oplock, NULL);
if (rc != 0) if (rc != 0)
goto out; goto out;
...@@ -1079,7 +1095,7 @@ cifs_rename_pending_delete(const char *full_path, struct dentry *dentry, ...@@ -1079,7 +1095,7 @@ cifs_rename_pending_delete(const char *full_path, struct dentry *dentry,
goto out_close; goto out_close;
} }
info_buf->Attributes = cpu_to_le32(dosattr); info_buf->Attributes = cpu_to_le32(dosattr);
rc = CIFSSMBSetFileInfo(xid, tcon, info_buf, netfid, rc = CIFSSMBSetFileInfo(xid, tcon, info_buf, fid.netfid,
current->tgid); current->tgid);
/* although we would like to mark the file hidden /* although we would like to mark the file hidden
if that fails we will still try to rename it */ if that fails we will still try to rename it */
...@@ -1090,7 +1106,8 @@ cifs_rename_pending_delete(const char *full_path, struct dentry *dentry, ...@@ -1090,7 +1106,8 @@ cifs_rename_pending_delete(const char *full_path, struct dentry *dentry,
} }
/* rename the file */ /* rename the file */
rc = CIFSSMBRenameOpenFile(xid, tcon, netfid, NULL, cifs_sb->local_nls, rc = CIFSSMBRenameOpenFile(xid, tcon, fid.netfid, NULL,
cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc != 0) { if (rc != 0) {
...@@ -1100,7 +1117,7 @@ cifs_rename_pending_delete(const char *full_path, struct dentry *dentry, ...@@ -1100,7 +1117,7 @@ cifs_rename_pending_delete(const char *full_path, struct dentry *dentry,
/* try to set DELETE_ON_CLOSE */ /* try to set DELETE_ON_CLOSE */
if (!cifsInode->delete_pending) { if (!cifsInode->delete_pending) {
rc = CIFSSMBSetFileDisposition(xid, tcon, true, netfid, rc = CIFSSMBSetFileDisposition(xid, tcon, true, fid.netfid,
current->tgid); current->tgid);
/* /*
* some samba versions return -ENOENT when we try to set the * some samba versions return -ENOENT when we try to set the
...@@ -1120,7 +1137,7 @@ cifs_rename_pending_delete(const char *full_path, struct dentry *dentry, ...@@ -1120,7 +1137,7 @@ cifs_rename_pending_delete(const char *full_path, struct dentry *dentry,
} }
out_close: out_close:
CIFSSMBClose(xid, tcon, netfid); CIFSSMBClose(xid, tcon, fid.netfid);
out: out:
kfree(info_buf); kfree(info_buf);
cifs_put_tlink(tlink); cifs_put_tlink(tlink);
...@@ -1132,13 +1149,13 @@ cifs_rename_pending_delete(const char *full_path, struct dentry *dentry, ...@@ -1132,13 +1149,13 @@ cifs_rename_pending_delete(const char *full_path, struct dentry *dentry,
* them anyway. * them anyway.
*/ */
undo_rename: undo_rename:
CIFSSMBRenameOpenFile(xid, tcon, netfid, dentry->d_name.name, CIFSSMBRenameOpenFile(xid, tcon, fid.netfid, dentry->d_name.name,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
undo_setattr: undo_setattr:
if (dosattr != origattr) { if (dosattr != origattr) {
info_buf->Attributes = cpu_to_le32(origattr); info_buf->Attributes = cpu_to_le32(origattr);
if (!CIFSSMBSetFileInfo(xid, tcon, info_buf, netfid, if (!CIFSSMBSetFileInfo(xid, tcon, info_buf, fid.netfid,
current->tgid)) current->tgid))
cifsInode->cifsAttrs = origattr; cifsInode->cifsAttrs = origattr;
} }
...@@ -1549,7 +1566,8 @@ cifs_do_rename(const unsigned int xid, struct dentry *from_dentry, ...@@ -1549,7 +1566,8 @@ cifs_do_rename(const unsigned int xid, struct dentry *from_dentry,
struct tcon_link *tlink; struct tcon_link *tlink;
struct cifs_tcon *tcon; struct cifs_tcon *tcon;
struct TCP_Server_Info *server; struct TCP_Server_Info *server;
__u16 srcfid; struct cifs_fid fid;
struct cifs_open_parms oparms;
int oplock, rc; int oplock, rc;
tlink = cifs_sb_tlink(cifs_sb); tlink = cifs_sb_tlink(cifs_sb);
...@@ -1576,17 +1594,23 @@ cifs_do_rename(const unsigned int xid, struct dentry *from_dentry, ...@@ -1576,17 +1594,23 @@ cifs_do_rename(const unsigned int xid, struct dentry *from_dentry,
if (to_dentry->d_parent != from_dentry->d_parent) if (to_dentry->d_parent != from_dentry->d_parent)
goto do_rename_exit; goto do_rename_exit;
oparms.tcon = tcon;
oparms.cifs_sb = cifs_sb;
/* open the file to be renamed -- we need DELETE perms */ /* open the file to be renamed -- we need DELETE perms */
rc = CIFSSMBOpen(xid, tcon, from_path, FILE_OPEN, DELETE, oparms.desired_access = DELETE;
CREATE_NOT_DIR, &srcfid, &oplock, NULL, oparms.create_options = CREATE_NOT_DIR;
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & oparms.disposition = FILE_OPEN;
CIFS_MOUNT_MAP_SPECIAL_CHR); oparms.path = from_path;
oparms.fid = &fid;
oparms.reconnect = false;
rc = CIFS_open(xid, &oparms, &oplock, NULL);
if (rc == 0) { if (rc == 0) {
rc = CIFSSMBRenameOpenFile(xid, tcon, srcfid, rc = CIFSSMBRenameOpenFile(xid, tcon, fid.netfid,
(const char *) to_dentry->d_name.name, (const char *) to_dentry->d_name.name,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
CIFSSMBClose(xid, tcon, srcfid); CIFSSMBClose(xid, tcon, fid.netfid);
} }
do_rename_exit: do_rename_exit:
cifs_put_tlink(tlink); cifs_put_tlink(tlink);
......
...@@ -29,6 +29,10 @@ ...@@ -29,6 +29,10 @@
#include "cifs_debug.h" #include "cifs_debug.h"
#include "cifs_fs_sb.h" #include "cifs_fs_sb.h"
/*
* M-F Symlink Functions - Begin
*/
#define CIFS_MF_SYMLINK_LEN_OFFSET (4+1) #define CIFS_MF_SYMLINK_LEN_OFFSET (4+1)
#define CIFS_MF_SYMLINK_MD5_OFFSET (CIFS_MF_SYMLINK_LEN_OFFSET+(4+1)) #define CIFS_MF_SYMLINK_MD5_OFFSET (CIFS_MF_SYMLINK_LEN_OFFSET+(4+1))
#define CIFS_MF_SYMLINK_LINK_OFFSET (CIFS_MF_SYMLINK_MD5_OFFSET+(32+1)) #define CIFS_MF_SYMLINK_LINK_OFFSET (CIFS_MF_SYMLINK_MD5_OFFSET+(32+1))
...@@ -91,10 +95,8 @@ symlink_hash(unsigned int link_len, const char *link_str, u8 *md5_hash) ...@@ -91,10 +95,8 @@ symlink_hash(unsigned int link_len, const char *link_str, u8 *md5_hash)
} }
static int static int
CIFSParseMFSymlink(const u8 *buf, parse_mf_symlink(const u8 *buf, unsigned int buf_len, unsigned int *_link_len,
unsigned int buf_len, char **_link_str)
unsigned int *_link_len,
char **_link_str)
{ {
int rc; int rc;
unsigned int link_len; unsigned int link_len;
...@@ -137,7 +139,7 @@ CIFSParseMFSymlink(const u8 *buf, ...@@ -137,7 +139,7 @@ CIFSParseMFSymlink(const u8 *buf,
} }
static int static int
CIFSFormatMFSymlink(u8 *buf, unsigned int buf_len, const char *link_str) format_mf_symlink(u8 *buf, unsigned int buf_len, const char *link_str)
{ {
int rc; int rc;
unsigned int link_len; unsigned int link_len;
...@@ -180,190 +182,94 @@ CIFSFormatMFSymlink(u8 *buf, unsigned int buf_len, const char *link_str) ...@@ -180,190 +182,94 @@ CIFSFormatMFSymlink(u8 *buf, unsigned int buf_len, const char *link_str)
return 0; return 0;
} }
bool
couldbe_mf_symlink(const struct cifs_fattr *fattr)
{
if (!S_ISREG(fattr->cf_mode))
/* it's not a symlink */
return false;
if (fattr->cf_eof != CIFS_MF_SYMLINK_FILE_SIZE)
/* it's not a symlink */
return false;
return true;
}
static int static int
CIFSCreateMFSymLink(const unsigned int xid, struct cifs_tcon *tcon, create_mf_symlink(const unsigned int xid, struct cifs_tcon *tcon,
const char *fromName, const char *toName, struct cifs_sb_info *cifs_sb, const char *fromName,
struct cifs_sb_info *cifs_sb) const char *toName)
{ {
int rc; int rc;
int oplock = 0;
int remap;
int create_options = CREATE_NOT_DIR;
__u16 netfid = 0;
u8 *buf; u8 *buf;
unsigned int bytes_written = 0; unsigned int bytes_written = 0;
struct cifs_io_parms io_parms;
struct nls_table *nls_codepage;
nls_codepage = cifs_sb->local_nls;
remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL); buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL);
if (!buf) if (!buf)
return -ENOMEM; return -ENOMEM;
rc = CIFSFormatMFSymlink(buf, CIFS_MF_SYMLINK_FILE_SIZE, toName); rc = format_mf_symlink(buf, CIFS_MF_SYMLINK_FILE_SIZE, toName);
if (rc != 0) { if (rc)
kfree(buf); goto out;
return rc;
}
if (backup_cred(cifs_sb))
create_options |= CREATE_OPEN_BACKUP_INTENT;
rc = CIFSSMBOpen(xid, tcon, fromName, FILE_CREATE, GENERIC_WRITE,
create_options, &netfid, &oplock, NULL,
nls_codepage, remap);
if (rc != 0) {
kfree(buf);
return rc;
}
io_parms.netfid = netfid;
io_parms.pid = current->tgid;
io_parms.tcon = tcon;
io_parms.offset = 0;
io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE;
rc = CIFSSMBWrite(xid, &io_parms, &bytes_written, buf, NULL, 0); rc = tcon->ses->server->ops->create_mf_symlink(xid, tcon, cifs_sb,
CIFSSMBClose(xid, tcon, netfid); fromName, buf, &bytes_written);
kfree(buf); if (rc)
if (rc != 0) goto out;
return rc;
if (bytes_written != CIFS_MF_SYMLINK_FILE_SIZE) if (bytes_written != CIFS_MF_SYMLINK_FILE_SIZE)
return -EIO; rc = -EIO;
out:
return 0; kfree(buf);
return rc;
} }
static int static int
CIFSQueryMFSymLink(const unsigned int xid, struct cifs_tcon *tcon, query_mf_symlink(const unsigned int xid, struct cifs_tcon *tcon,
const unsigned char *searchName, char **symlinkinfo, struct cifs_sb_info *cifs_sb, const unsigned char *path,
const struct nls_table *nls_codepage, int remap) char **symlinkinfo)
{ {
int rc; int rc;
int oplock = 0; u8 *buf = NULL;
__u16 netfid = 0;
u8 *buf;
char *pbuf;
unsigned int bytes_read = 0;
int buf_type = CIFS_NO_BUFFER;
unsigned int link_len = 0; unsigned int link_len = 0;
struct cifs_io_parms io_parms; unsigned int bytes_read = 0;
FILE_ALL_INFO file_info;
rc = CIFSSMBOpen(xid, tcon, searchName, FILE_OPEN, GENERIC_READ,
CREATE_NOT_DIR, &netfid, &oplock, &file_info,
nls_codepage, remap);
if (rc != 0)
return rc;
if (file_info.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) {
CIFSSMBClose(xid, tcon, netfid);
/* it's not a symlink */
return -EINVAL;
}
buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL); buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL);
if (!buf) if (!buf)
return -ENOMEM; return -ENOMEM;
pbuf = buf;
io_parms.netfid = netfid;
io_parms.pid = current->tgid;
io_parms.tcon = tcon;
io_parms.offset = 0;
io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE;
rc = CIFSSMBRead(xid, &io_parms, &bytes_read, &pbuf, &buf_type);
CIFSSMBClose(xid, tcon, netfid);
if (rc != 0) {
kfree(buf);
return rc;
}
rc = CIFSParseMFSymlink(buf, bytes_read, &link_len, symlinkinfo);
kfree(buf);
if (rc != 0)
return rc;
return 0;
}
bool
CIFSCouldBeMFSymlink(const struct cifs_fattr *fattr)
{
if (!(fattr->cf_mode & S_IFREG))
/* it's not a symlink */
return false;
if (fattr->cf_eof != CIFS_MF_SYMLINK_FILE_SIZE) if (tcon->ses->server->ops->query_mf_symlink)
/* it's not a symlink */ rc = tcon->ses->server->ops->query_mf_symlink(xid, tcon,
return false; cifs_sb, path, buf, &bytes_read);
else
return true; rc = -ENOSYS;
}
int
open_query_close_cifs_symlink(const unsigned char *path, char *pbuf,
unsigned int *pbytes_read, struct cifs_sb_info *cifs_sb,
unsigned int xid)
{
int rc;
int oplock = 0;
__u16 netfid = 0;
struct tcon_link *tlink;
struct cifs_tcon *ptcon;
struct cifs_io_parms io_parms;
int buf_type = CIFS_NO_BUFFER;
FILE_ALL_INFO file_info;
tlink = cifs_sb_tlink(cifs_sb);
if (IS_ERR(tlink))
return PTR_ERR(tlink);
ptcon = tlink_tcon(tlink);
rc = CIFSSMBOpen(xid, ptcon, path, FILE_OPEN, GENERIC_READ, if (rc)
CREATE_NOT_DIR, &netfid, &oplock, &file_info, goto out;
cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc != 0) {
cifs_put_tlink(tlink);
return rc;
}
if (file_info.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) { if (bytes_read == 0) { /* not a symlink */
CIFSSMBClose(xid, ptcon, netfid); rc = -EINVAL;
cifs_put_tlink(tlink); goto out;
/* it's not a symlink */
return rc;
} }
io_parms.netfid = netfid; rc = parse_mf_symlink(buf, bytes_read, &link_len, symlinkinfo);
io_parms.pid = current->tgid; out:
io_parms.tcon = ptcon; kfree(buf);
io_parms.offset = 0;
io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE;
rc = CIFSSMBRead(xid, &io_parms, pbytes_read, &pbuf, &buf_type);
CIFSSMBClose(xid, ptcon, netfid);
cifs_put_tlink(tlink);
return rc; return rc;
} }
int int
CIFSCheckMFSymlink(unsigned int xid, struct cifs_tcon *tcon, check_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
const unsigned char *path) const unsigned char *path)
{ {
int rc; int rc;
u8 *buf = NULL; u8 *buf = NULL;
unsigned int link_len = 0; unsigned int link_len = 0;
unsigned int bytes_read = 0; unsigned int bytes_read = 0;
if (!CIFSCouldBeMFSymlink(fattr)) if (!couldbe_mf_symlink(fattr))
/* it's not a symlink */ /* it's not a symlink */
return 0; return 0;
...@@ -372,8 +278,8 @@ CIFSCheckMFSymlink(unsigned int xid, struct cifs_tcon *tcon, ...@@ -372,8 +278,8 @@ CIFSCheckMFSymlink(unsigned int xid, struct cifs_tcon *tcon,
return -ENOMEM; return -ENOMEM;
if (tcon->ses->server->ops->query_mf_symlink) if (tcon->ses->server->ops->query_mf_symlink)
rc = tcon->ses->server->ops->query_mf_symlink(path, buf, rc = tcon->ses->server->ops->query_mf_symlink(xid, tcon,
&bytes_read, cifs_sb, xid); cifs_sb, path, buf, &bytes_read);
else else
rc = -ENOSYS; rc = -ENOSYS;
...@@ -383,7 +289,7 @@ CIFSCheckMFSymlink(unsigned int xid, struct cifs_tcon *tcon, ...@@ -383,7 +289,7 @@ CIFSCheckMFSymlink(unsigned int xid, struct cifs_tcon *tcon,
if (bytes_read == 0) /* not a symlink */ if (bytes_read == 0) /* not a symlink */
goto out; goto out;
rc = CIFSParseMFSymlink(buf, bytes_read, &link_len, NULL); rc = parse_mf_symlink(buf, bytes_read, &link_len, NULL);
if (rc == -EINVAL) { if (rc == -EINVAL) {
/* it's not a symlink */ /* it's not a symlink */
rc = 0; rc = 0;
...@@ -403,6 +309,95 @@ CIFSCheckMFSymlink(unsigned int xid, struct cifs_tcon *tcon, ...@@ -403,6 +309,95 @@ CIFSCheckMFSymlink(unsigned int xid, struct cifs_tcon *tcon,
return rc; return rc;
} }
/*
* SMB 1.0 Protocol specific functions
*/
int
cifs_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb, const unsigned char *path,
char *pbuf, unsigned int *pbytes_read)
{
int rc;
int oplock = 0;
struct cifs_fid fid;
struct cifs_open_parms oparms;
struct cifs_io_parms io_parms;
int buf_type = CIFS_NO_BUFFER;
FILE_ALL_INFO file_info;
oparms.tcon = tcon;
oparms.cifs_sb = cifs_sb;
oparms.desired_access = GENERIC_READ;
oparms.create_options = CREATE_NOT_DIR;
oparms.disposition = FILE_OPEN;
oparms.path = path;
oparms.fid = &fid;
oparms.reconnect = false;
rc = CIFS_open(xid, &oparms, &oplock, &file_info);
if (rc)
return rc;
if (file_info.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE))
/* it's not a symlink */
goto out;
io_parms.netfid = fid.netfid;
io_parms.pid = current->tgid;
io_parms.tcon = tcon;
io_parms.offset = 0;
io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE;
rc = CIFSSMBRead(xid, &io_parms, pbytes_read, &pbuf, &buf_type);
out:
CIFSSMBClose(xid, tcon, fid.netfid);
return rc;
}
int
cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb, const unsigned char *path,
char *pbuf, unsigned int *pbytes_written)
{
int rc;
int oplock = 0;
struct cifs_fid fid;
struct cifs_open_parms oparms;
struct cifs_io_parms io_parms;
int create_options = CREATE_NOT_DIR;
if (backup_cred(cifs_sb))
create_options |= CREATE_OPEN_BACKUP_INTENT;
oparms.tcon = tcon;
oparms.cifs_sb = cifs_sb;
oparms.desired_access = GENERIC_WRITE;
oparms.create_options = create_options;
oparms.disposition = FILE_OPEN;
oparms.path = path;
oparms.fid = &fid;
oparms.reconnect = false;
rc = CIFS_open(xid, &oparms, &oplock, NULL);
if (rc)
return rc;
io_parms.netfid = fid.netfid;
io_parms.pid = current->tgid;
io_parms.tcon = tcon;
io_parms.offset = 0;
io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE;
rc = CIFSSMBWrite(xid, &io_parms, pbytes_written, pbuf, NULL, 0);
CIFSSMBClose(xid, tcon, fid.netfid);
return rc;
}
/*
* M-F Symlink Functions - End
*/
int int
cifs_hardlink(struct dentry *old_file, struct inode *inode, cifs_hardlink(struct dentry *old_file, struct inode *inode,
struct dentry *direntry) struct dentry *direntry)
...@@ -438,8 +433,10 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode, ...@@ -438,8 +433,10 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
else { else {
server = tcon->ses->server; server = tcon->ses->server;
if (!server->ops->create_hardlink) if (!server->ops->create_hardlink) {
return -ENOSYS; rc = -ENOSYS;
goto cifs_hl_exit;
}
rc = server->ops->create_hardlink(xid, tcon, from_name, to_name, rc = server->ops->create_hardlink(xid, tcon, from_name, to_name,
cifs_sb); cifs_sb);
if ((rc == -EIO) || (rc == -EINVAL)) if ((rc == -EIO) || (rc == -EINVAL))
...@@ -530,15 +527,10 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd) ...@@ -530,15 +527,10 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
* and fallback to UNIX Extensions Symlinks. * and fallback to UNIX Extensions Symlinks.
*/ */
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS)
rc = CIFSQueryMFSymLink(xid, tcon, full_path, &target_path, rc = query_mf_symlink(xid, tcon, cifs_sb, full_path,
cifs_sb->local_nls, &target_path);
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
if ((rc != 0) && cap_unix(tcon->ses)) if (rc != 0 && server->ops->query_symlink)
rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, &target_path,
cifs_sb->local_nls);
else if (rc != 0 && server->ops->query_symlink)
rc = server->ops->query_symlink(xid, tcon, full_path, rc = server->ops->query_symlink(xid, tcon, full_path,
&target_path, cifs_sb); &target_path, cifs_sb);
...@@ -587,8 +579,7 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) ...@@ -587,8 +579,7 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
/* BB what if DFS and this volume is on different share? BB */ /* BB what if DFS and this volume is on different share? BB */
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS)
rc = CIFSCreateMFSymLink(xid, pTcon, full_path, symname, rc = create_mf_symlink(xid, pTcon, cifs_sb, full_path, symname);
cifs_sb);
else if (pTcon->unix_ext) else if (pTcon->unix_ext)
rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname, rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname,
cifs_sb->local_nls); cifs_sb->local_nls);
......
...@@ -749,7 +749,7 @@ static int cifs_filldir(char *find_entry, struct file *file, ...@@ -749,7 +749,7 @@ static int cifs_filldir(char *find_entry, struct file *file,
} }
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) && if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) &&
CIFSCouldBeMFSymlink(&fattr)) couldbe_mf_symlink(&fattr))
/* /*
* trying to get the type and mode can be slow, * trying to get the type and mode can be slow,
* so just call those regular files for now, and mark * so just call those regular files for now, and mark
......
...@@ -560,17 +560,24 @@ cifs_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -560,17 +560,24 @@ cifs_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
if (!rc && (le32_to_cpu(data->Attributes) & ATTR_REPARSE)) { if (!rc && (le32_to_cpu(data->Attributes) & ATTR_REPARSE)) {
int tmprc; int tmprc;
int oplock = 0; int oplock = 0;
__u16 netfid; struct cifs_fid fid;
struct cifs_open_parms oparms;
oparms.tcon = tcon;
oparms.cifs_sb = cifs_sb;
oparms.desired_access = FILE_READ_ATTRIBUTES;
oparms.create_options = 0;
oparms.disposition = FILE_OPEN;
oparms.path = full_path;
oparms.fid = &fid;
oparms.reconnect = false;
/* Need to check if this is a symbolic link or not */ /* Need to check if this is a symbolic link or not */
tmprc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN, tmprc = CIFS_open(xid, &oparms, &oplock, NULL);
FILE_READ_ATTRIBUTES, 0, &netfid, &oplock,
NULL, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
if (tmprc == -EOPNOTSUPP) if (tmprc == -EOPNOTSUPP)
*symlink = true; *symlink = true;
else else
CIFSSMBClose(xid, tcon, netfid); CIFSSMBClose(xid, tcon, fid.netfid);
} }
return rc; return rc;
...@@ -705,12 +712,7 @@ cifs_open_file(const unsigned int xid, struct cifs_open_parms *oparms, ...@@ -705,12 +712,7 @@ cifs_open_file(const unsigned int xid, struct cifs_open_parms *oparms,
oparms->cifs_sb->local_nls, oparms->cifs_sb->local_nls,
oparms->cifs_sb->mnt_cifs_flags oparms->cifs_sb->mnt_cifs_flags
& CIFS_MOUNT_MAP_SPECIAL_CHR); & CIFS_MOUNT_MAP_SPECIAL_CHR);
return CIFSSMBOpen(xid, oparms->tcon, oparms->path, return CIFS_open(xid, oparms, oplock, buf);
oparms->disposition, oparms->desired_access,
oparms->create_options, &oparms->fid->netfid, oplock,
buf, oparms->cifs_sb->local_nls,
oparms->cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
} }
static void static void
...@@ -761,8 +763,9 @@ smb_set_file_info(struct inode *inode, const char *full_path, ...@@ -761,8 +763,9 @@ smb_set_file_info(struct inode *inode, const char *full_path,
{ {
int oplock = 0; int oplock = 0;
int rc; int rc;
__u16 netfid;
__u32 netpid; __u32 netpid;
struct cifs_fid fid;
struct cifs_open_parms oparms;
struct cifsFileInfo *open_file; struct cifsFileInfo *open_file;
struct cifsInodeInfo *cinode = CIFS_I(inode); struct cifsInodeInfo *cinode = CIFS_I(inode);
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
...@@ -772,7 +775,7 @@ smb_set_file_info(struct inode *inode, const char *full_path, ...@@ -772,7 +775,7 @@ smb_set_file_info(struct inode *inode, const char *full_path,
/* if the file is already open for write, just use that fileid */ /* if the file is already open for write, just use that fileid */
open_file = find_writable_file(cinode, true); open_file = find_writable_file(cinode, true);
if (open_file) { if (open_file) {
netfid = open_file->fid.netfid; fid.netfid = open_file->fid.netfid;
netpid = open_file->pid; netpid = open_file->pid;
tcon = tlink_tcon(open_file->tlink); tcon = tlink_tcon(open_file->tlink);
goto set_via_filehandle; goto set_via_filehandle;
...@@ -796,12 +799,17 @@ smb_set_file_info(struct inode *inode, const char *full_path, ...@@ -796,12 +799,17 @@ smb_set_file_info(struct inode *inode, const char *full_path,
goto out; goto out;
} }
cifs_dbg(FYI, "calling SetFileInfo since SetPathInfo for times not supported by this server\n"); oparms.tcon = tcon;
rc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN, oparms.cifs_sb = cifs_sb;
SYNCHRONIZE | FILE_WRITE_ATTRIBUTES, CREATE_NOT_DIR, oparms.desired_access = SYNCHRONIZE | FILE_WRITE_ATTRIBUTES;
&netfid, &oplock, NULL, cifs_sb->local_nls, oparms.create_options = CREATE_NOT_DIR;
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); oparms.disposition = FILE_OPEN;
oparms.path = full_path;
oparms.fid = &fid;
oparms.reconnect = false;
cifs_dbg(FYI, "calling SetFileInfo since SetPathInfo for times not supported by this server\n");
rc = CIFS_open(xid, &oparms, &oplock, NULL);
if (rc != 0) { if (rc != 0) {
if (rc == -EIO) if (rc == -EIO)
rc = -EINVAL; rc = -EINVAL;
...@@ -811,12 +819,12 @@ smb_set_file_info(struct inode *inode, const char *full_path, ...@@ -811,12 +819,12 @@ smb_set_file_info(struct inode *inode, const char *full_path,
netpid = current->tgid; netpid = current->tgid;
set_via_filehandle: set_via_filehandle:
rc = CIFSSMBSetFileInfo(xid, tcon, buf, netfid, netpid); rc = CIFSSMBSetFileInfo(xid, tcon, buf, fid.netfid, netpid);
if (!rc) if (!rc)
cinode->cifsAttrs = le32_to_cpu(buf->Attributes); cinode->cifsAttrs = le32_to_cpu(buf->Attributes);
if (open_file == NULL) if (open_file == NULL)
CIFSSMBClose(xid, tcon, netfid); CIFSSMBClose(xid, tcon, fid.netfid);
else else
cifsFileInfo_put(open_file); cifsFileInfo_put(open_file);
out: out:
...@@ -907,6 +915,33 @@ cifs_mand_lock(const unsigned int xid, struct cifsFileInfo *cfile, __u64 offset, ...@@ -907,6 +915,33 @@ cifs_mand_lock(const unsigned int xid, struct cifsFileInfo *cfile, __u64 offset,
(__u8)type, wait, 0); (__u8)type, wait, 0);
} }
static int
cifs_unix_dfs_readlink(const unsigned int xid, struct cifs_tcon *tcon,
const unsigned char *searchName, char **symlinkinfo,
const struct nls_table *nls_codepage)
{
#ifdef CONFIG_CIFS_DFS_UPCALL
int rc;
unsigned int num_referrals = 0;
struct dfs_info3_param *referrals = NULL;
rc = get_dfs_path(xid, tcon->ses, searchName, nls_codepage,
&num_referrals, &referrals, 0);
if (!rc && num_referrals > 0) {
*symlinkinfo = kstrndup(referrals->node_name,
strlen(referrals->node_name),
GFP_KERNEL);
if (!*symlinkinfo)
rc = -ENOMEM;
free_dfs_info_array(referrals, num_referrals);
}
return rc;
#else /* No DFS support */
return -EREMOTE;
#endif
}
static int static int
cifs_query_symlink(const unsigned int xid, struct cifs_tcon *tcon, cifs_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
const char *full_path, char **target_path, const char *full_path, char **target_path,
...@@ -914,27 +949,47 @@ cifs_query_symlink(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -914,27 +949,47 @@ cifs_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
{ {
int rc; int rc;
int oplock = 0; int oplock = 0;
__u16 netfid; struct cifs_fid fid;
struct cifs_open_parms oparms;
cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path); cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path);
rc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN, /* Check for unix extensions */
FILE_READ_ATTRIBUTES, OPEN_REPARSE_POINT, &netfid, if (cap_unix(tcon->ses)) {
&oplock, NULL, cifs_sb->local_nls, rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, target_path,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); cifs_sb->local_nls);
if (rc == -EREMOTE)
rc = cifs_unix_dfs_readlink(xid, tcon, full_path,
target_path,
cifs_sb->local_nls);
goto out;
}
oparms.tcon = tcon;
oparms.cifs_sb = cifs_sb;
oparms.desired_access = FILE_READ_ATTRIBUTES;
oparms.create_options = OPEN_REPARSE_POINT;
oparms.disposition = FILE_OPEN;
oparms.path = full_path;
oparms.fid = &fid;
oparms.reconnect = false;
rc = CIFS_open(xid, &oparms, &oplock, NULL);
if (rc) if (rc)
return rc; goto out;
rc = CIFSSMBQuerySymLink(xid, tcon, netfid, target_path, rc = CIFSSMBQuerySymLink(xid, tcon, fid.netfid, target_path,
cifs_sb->local_nls); cifs_sb->local_nls);
if (rc) { if (rc)
CIFSSMBClose(xid, tcon, netfid); goto out_close;
return rc;
}
convert_delimiter(*target_path, '/'); convert_delimiter(*target_path, '/');
CIFSSMBClose(xid, tcon, netfid); out_close:
cifs_dbg(FYI, "%s: target path: %s\n", __func__, *target_path); CIFSSMBClose(xid, tcon, fid.netfid);
out:
if (!rc)
cifs_dbg(FYI, "%s: target path: %s\n", __func__, *target_path);
return rc; return rc;
} }
...@@ -1009,7 +1064,8 @@ struct smb_version_operations smb1_operations = { ...@@ -1009,7 +1064,8 @@ struct smb_version_operations smb1_operations = {
.mand_lock = cifs_mand_lock, .mand_lock = cifs_mand_lock,
.mand_unlock_range = cifs_unlock_range, .mand_unlock_range = cifs_unlock_range,
.push_mand_locks = cifs_push_mandatory_locks, .push_mand_locks = cifs_push_mandatory_locks,
.query_mf_symlink = open_query_close_cifs_symlink, .query_mf_symlink = cifs_query_mf_symlink,
.create_mf_symlink = cifs_create_mf_symlink,
.is_read_op = cifs_is_read_op, .is_read_op = cifs_is_read_op,
}; };
......
...@@ -82,9 +82,11 @@ int cifs_removexattr(struct dentry *direntry, const char *ea_name) ...@@ -82,9 +82,11 @@ int cifs_removexattr(struct dentry *direntry, const char *ea_name)
goto remove_ea_exit; goto remove_ea_exit;
ea_name += XATTR_USER_PREFIX_LEN; /* skip past user. prefix */ ea_name += XATTR_USER_PREFIX_LEN; /* skip past user. prefix */
rc = CIFSSMBSetEA(xid, pTcon, full_path, ea_name, NULL, if (pTcon->ses->server->ops->set_EA)
(__u16)0, cifs_sb->local_nls, rc = pTcon->ses->server->ops->set_EA(xid, pTcon,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); full_path, ea_name, NULL, (__u16)0,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
} }
remove_ea_exit: remove_ea_exit:
kfree(full_path); kfree(full_path);
...@@ -149,18 +151,22 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name, ...@@ -149,18 +151,22 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name,
cifs_dbg(FYI, "attempt to set cifs inode metadata\n"); cifs_dbg(FYI, "attempt to set cifs inode metadata\n");
ea_name += XATTR_USER_PREFIX_LEN; /* skip past user. prefix */ ea_name += XATTR_USER_PREFIX_LEN; /* skip past user. prefix */
rc = CIFSSMBSetEA(xid, pTcon, full_path, ea_name, ea_value, if (pTcon->ses->server->ops->set_EA)
(__u16)value_size, cifs_sb->local_nls, rc = pTcon->ses->server->ops->set_EA(xid, pTcon,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); full_path, ea_name, ea_value, (__u16)value_size,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
} else if (strncmp(ea_name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) } else if (strncmp(ea_name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN)
== 0) { == 0) {
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
goto set_ea_exit; goto set_ea_exit;
ea_name += XATTR_OS2_PREFIX_LEN; /* skip past os2. prefix */ ea_name += XATTR_OS2_PREFIX_LEN; /* skip past os2. prefix */
rc = CIFSSMBSetEA(xid, pTcon, full_path, ea_name, ea_value, if (pTcon->ses->server->ops->set_EA)
(__u16)value_size, cifs_sb->local_nls, rc = pTcon->ses->server->ops->set_EA(xid, pTcon,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); full_path, ea_name, ea_value, (__u16)value_size,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
} else if (strncmp(ea_name, CIFS_XATTR_CIFS_ACL, } else if (strncmp(ea_name, CIFS_XATTR_CIFS_ACL,
strlen(CIFS_XATTR_CIFS_ACL)) == 0) { strlen(CIFS_XATTR_CIFS_ACL)) == 0) {
#ifdef CONFIG_CIFS_ACL #ifdef CONFIG_CIFS_ACL
...@@ -272,17 +278,21 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name, ...@@ -272,17 +278,21 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
/* revalidate/getattr then populate from inode */ /* revalidate/getattr then populate from inode */
} /* BB add else when above is implemented */ } /* BB add else when above is implemented */
ea_name += XATTR_USER_PREFIX_LEN; /* skip past user. prefix */ ea_name += XATTR_USER_PREFIX_LEN; /* skip past user. prefix */
rc = CIFSSMBQAllEAs(xid, pTcon, full_path, ea_name, ea_value, if (pTcon->ses->server->ops->query_all_EAs)
buf_size, cifs_sb->local_nls, rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); full_path, ea_name, ea_value, buf_size,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
} else if (strncmp(ea_name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) == 0) { } else if (strncmp(ea_name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) == 0) {
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
goto get_ea_exit; goto get_ea_exit;
ea_name += XATTR_OS2_PREFIX_LEN; /* skip past os2. prefix */ ea_name += XATTR_OS2_PREFIX_LEN; /* skip past os2. prefix */
rc = CIFSSMBQAllEAs(xid, pTcon, full_path, ea_name, ea_value, if (pTcon->ses->server->ops->query_all_EAs)
buf_size, cifs_sb->local_nls, rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); full_path, ea_name, ea_value, buf_size,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
} else if (strncmp(ea_name, POSIX_ACL_XATTR_ACCESS, } else if (strncmp(ea_name, POSIX_ACL_XATTR_ACCESS,
strlen(POSIX_ACL_XATTR_ACCESS)) == 0) { strlen(POSIX_ACL_XATTR_ACCESS)) == 0) {
#ifdef CONFIG_CIFS_POSIX #ifdef CONFIG_CIFS_POSIX
...@@ -400,11 +410,12 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size) ...@@ -400,11 +410,12 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size)
/* if proc/fs/cifs/streamstoxattr is set then /* if proc/fs/cifs/streamstoxattr is set then
search server for EAs or streams to search server for EAs or streams to
returns as xattrs */ returns as xattrs */
rc = CIFSSMBQAllEAs(xid, pTcon, full_path, NULL, data,
buf_size, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
if (pTcon->ses->server->ops->query_all_EAs)
rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon,
full_path, NULL, data, buf_size,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
list_ea_exit: list_ea_exit:
kfree(full_path); kfree(full_path);
free_xid(xid); free_xid(xid);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment