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()
This commit is contained in:
commit
0f44bc36ba
@ -895,9 +895,10 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
|
||||
int oplock = 0;
|
||||
unsigned int xid;
|
||||
int rc, create_options = 0;
|
||||
__u16 fid;
|
||||
struct cifs_tcon *tcon;
|
||||
struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
|
||||
struct cifs_fid fid;
|
||||
struct cifs_open_parms oparms;
|
||||
|
||||
if (IS_ERR(tlink))
|
||||
return ERR_CAST(tlink);
|
||||
@ -908,12 +909,19 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
|
||||
if (backup_cred(cifs_sb))
|
||||
create_options |= CREATE_OPEN_BACKUP_INTENT;
|
||||
|
||||
rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL,
|
||||
create_options, &fid, &oplock, NULL, cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
oparms.tcon = tcon;
|
||||
oparms.cifs_sb = cifs_sb;
|
||||
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) {
|
||||
rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen);
|
||||
CIFSSMBClose(xid, tcon, fid);
|
||||
rc = CIFSSMBGetCIFSACL(xid, tcon, fid.netfid, &pntsd, pacllen);
|
||||
CIFSSMBClose(xid, tcon, fid.netfid);
|
||||
}
|
||||
|
||||
cifs_put_tlink(tlink);
|
||||
@ -950,10 +958,11 @@ int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
|
||||
int oplock = 0;
|
||||
unsigned int xid;
|
||||
int rc, access_flags, create_options = 0;
|
||||
__u16 fid;
|
||||
struct cifs_tcon *tcon;
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
|
||||
struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
|
||||
struct cifs_fid fid;
|
||||
struct cifs_open_parms oparms;
|
||||
|
||||
if (IS_ERR(tlink))
|
||||
return PTR_ERR(tlink);
|
||||
@ -969,18 +978,25 @@ int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
|
||||
else
|
||||
access_flags = WRITE_DAC;
|
||||
|
||||
rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, access_flags,
|
||||
create_options, &fid, &oplock, NULL, cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
oparms.tcon = tcon;
|
||||
oparms.cifs_sb = cifs_sb;
|
||||
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) {
|
||||
cifs_dbg(VFS, "Unable to open file to set ACL\n");
|
||||
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);
|
||||
|
||||
CIFSSMBClose(xid, tcon, fid);
|
||||
CIFSSMBClose(xid, tcon, fid.netfid);
|
||||
out:
|
||||
free_xid(xid);
|
||||
cifs_put_tlink(tlink);
|
||||
|
@ -370,8 +370,12 @@ struct smb_version_operations {
|
||||
void (*new_lease_key)(struct cifs_fid *);
|
||||
int (*generate_signingkey)(struct cifs_ses *);
|
||||
int (*calc_signature)(struct smb_rqst *, struct TCP_Server_Info *);
|
||||
int (*query_mf_symlink)(const unsigned char *, char *, unsigned int *,
|
||||
struct cifs_sb_info *, unsigned int);
|
||||
int (*query_mf_symlink)(unsigned int, struct cifs_tcon *,
|
||||
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 */
|
||||
bool (*is_read_op)(__u32);
|
||||
/* set oplock level for the inode */
|
||||
@ -385,6 +389,12 @@ struct smb_version_operations {
|
||||
struct cifsFileInfo *target_file, u64 src_off, u64 len,
|
||||
u64 dest_off);
|
||||
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 {
|
||||
|
@ -362,11 +362,8 @@ extern int CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
const struct nls_table *nls_codepage);
|
||||
extern int CIFSSMB_set_compression(const unsigned int xid,
|
||||
struct cifs_tcon *tcon, __u16 fid);
|
||||
extern int CIFSSMBOpen(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
const char *fileName, const int disposition,
|
||||
const int access_flags, const int omode,
|
||||
__u16 *netfid, int *pOplock, FILE_ALL_INFO *,
|
||||
const struct nls_table *nls_codepage, int remap);
|
||||
extern int CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms,
|
||||
int *oplock, FILE_ALL_INFO *buf);
|
||||
extern int SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
const char *fileName, const int disposition,
|
||||
const int access_flags, const int omode,
|
||||
@ -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,
|
||||
const int netfid, __u64 *pExtAttrBits, __u64 *pMask);
|
||||
extern void cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb);
|
||||
extern bool CIFSCouldBeMFSymlink(const struct cifs_fattr *fattr);
|
||||
extern int CIFSCheckMFSymlink(unsigned int xid, struct cifs_tcon *tcon,
|
||||
extern bool couldbe_mf_symlink(const struct cifs_fattr *fattr);
|
||||
extern int check_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb,
|
||||
struct cifs_fattr *fattr,
|
||||
const unsigned char *path);
|
||||
@ -496,7 +493,12 @@ void cifs_writev_complete(struct work_struct *work);
|
||||
struct cifs_writedata *cifs_writedata_alloc(unsigned int nr_pages,
|
||||
work_func_t complete);
|
||||
void cifs_writedata_release(struct kref *refcount);
|
||||
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 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 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 */
|
||||
|
@ -1273,104 +1273,124 @@ OldOpenRetry:
|
||||
}
|
||||
|
||||
int
|
||||
CIFSSMBOpen(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
const char *fileName, const int openDisposition,
|
||||
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)
|
||||
CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock,
|
||||
FILE_ALL_INFO *buf)
|
||||
{
|
||||
int rc = -EACCES;
|
||||
OPEN_REQ *pSMB = NULL;
|
||||
OPEN_RSP *pSMBr = NULL;
|
||||
OPEN_REQ *req = NULL;
|
||||
OPEN_RSP *rsp = NULL;
|
||||
int bytes_returned;
|
||||
int name_len;
|
||||
__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:
|
||||
rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
|
||||
(void **) &pSMBr);
|
||||
rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **)&req,
|
||||
(void **)&rsp);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
pSMB->AndXCommand = 0xFF; /* none */
|
||||
/* no commands go after this */
|
||||
req->AndXCommand = 0xFF;
|
||||
|
||||
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
|
||||
count = 1; /* account for one byte pad to word boundary */
|
||||
name_len =
|
||||
cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
|
||||
fileName, PATH_MAX, nls_codepage, remap);
|
||||
name_len++; /* trailing null */
|
||||
if (req->hdr.Flags2 & SMBFLG2_UNICODE) {
|
||||
/* account for one byte pad to word boundary */
|
||||
count = 1;
|
||||
name_len = cifsConvertToUTF16((__le16 *)(req->fileName + 1),
|
||||
path, PATH_MAX, nls, remap);
|
||||
/* trailing null */
|
||||
name_len++;
|
||||
name_len *= 2;
|
||||
pSMB->NameLength = cpu_to_le16(name_len);
|
||||
} else { /* BB improve check for buffer overruns BB */
|
||||
count = 0; /* no pad */
|
||||
name_len = strnlen(fileName, PATH_MAX);
|
||||
name_len++; /* trailing null */
|
||||
pSMB->NameLength = cpu_to_le16(name_len);
|
||||
strncpy(pSMB->fileName, fileName, name_len);
|
||||
req->NameLength = cpu_to_le16(name_len);
|
||||
} else {
|
||||
/* BB improve check for buffer overruns BB */
|
||||
/* no pad */
|
||||
count = 0;
|
||||
name_len = strnlen(path, PATH_MAX);
|
||||
/* 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);
|
||||
else if (*pOplock & REQ_BATCHOPLOCK)
|
||||
pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
|
||||
pSMB->DesiredAccess = cpu_to_le32(access_flags);
|
||||
pSMB->AllocationSize = 0;
|
||||
/* 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)
|
||||
pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
|
||||
else
|
||||
pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
|
||||
|
||||
/* XP does not handle ATTR_POSIX_SEMANTICS */
|
||||
/* but it helps speed up case sensitive checks for other
|
||||
servers such as Samba */
|
||||
if (*oplock & REQ_OPLOCK)
|
||||
req->OpenFlags = cpu_to_le32(REQ_OPLOCK);
|
||||
else if (*oplock & REQ_BATCHOPLOCK)
|
||||
req->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
|
||||
|
||||
req->DesiredAccess = cpu_to_le32(desired_access);
|
||||
req->AllocationSize = 0;
|
||||
|
||||
/*
|
||||
* 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)
|
||||
req->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
|
||||
else
|
||||
req->FileAttributes = cpu_to_le32(ATTR_NORMAL);
|
||||
|
||||
/*
|
||||
* XP does not handle ATTR_POSIX_SEMANTICS but it helps speed up case
|
||||
* sensitive checks for other servers such as Samba.
|
||||
*/
|
||||
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)
|
||||
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 */
|
||||
pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
|
||||
pSMB->SecurityFlags =
|
||||
SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
|
||||
req->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
|
||||
req->SecurityFlags = SECURITY_CONTEXT_TRACKING|SECURITY_EFFECTIVE_ONLY;
|
||||
|
||||
count += name_len;
|
||||
inc_rfc1001_len(pSMB, count);
|
||||
inc_rfc1001_len(req, count);
|
||||
|
||||
pSMB->ByteCount = cpu_to_le16(count);
|
||||
/* long_op set to 1 to allow for oplock break timeouts */
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
(struct smb_hdr *)pSMBr, &bytes_returned, 0);
|
||||
req->ByteCount = cpu_to_le16(count);
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *)req,
|
||||
(struct smb_hdr *)rsp, &bytes_returned, 0);
|
||||
cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
|
||||
if (rc) {
|
||||
cifs_dbg(FYI, "Error in Open = %d\n", rc);
|
||||
} else {
|
||||
*pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
|
||||
*netfid = pSMBr->Fid; /* cifs fid stays in le */
|
||||
/* 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) == 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(req);
|
||||
if (rc == -EAGAIN)
|
||||
goto openRetry;
|
||||
return rc;
|
||||
}
|
||||
|
||||
cifs_buf_release(pSMB);
|
||||
if (rc == -EAGAIN)
|
||||
goto openRetry;
|
||||
/* 1 byte no need to le_to_cpu */
|
||||
*oplock = rsp->OplockLevel;
|
||||
/* 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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
struct cifs_sb_info *cifs_sb;
|
||||
struct tcon_link *tlink;
|
||||
struct cifs_tcon *pTcon;
|
||||
struct cifs_tcon *tcon;
|
||||
struct cifs_io_parms io_parms;
|
||||
char *full_path = NULL;
|
||||
struct inode *newinode = NULL;
|
||||
int oplock = 0;
|
||||
u16 fileHandle;
|
||||
struct cifs_fid fid;
|
||||
struct cifs_open_parms oparms;
|
||||
FILE_ALL_INFO *buf = NULL;
|
||||
unsigned int bytes_written;
|
||||
struct win_dev *pdev;
|
||||
@ -583,7 +584,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode,
|
||||
if (IS_ERR(tlink))
|
||||
return PTR_ERR(tlink);
|
||||
|
||||
pTcon = tlink_tcon(tlink);
|
||||
tcon = tlink_tcon(tlink);
|
||||
|
||||
xid = get_xid();
|
||||
|
||||
@ -593,7 +594,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode,
|
||||
goto mknod_out;
|
||||
}
|
||||
|
||||
if (pTcon->unix_ext) {
|
||||
if (tcon->unix_ext) {
|
||||
struct cifs_unix_set_info_args args = {
|
||||
.mode = mode & ~current_umask(),
|
||||
.ctime = NO_CHANGE_64,
|
||||
@ -608,7 +609,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode,
|
||||
args.uid = INVALID_UID; /* 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->mnt_cifs_flags &
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
@ -640,42 +641,44 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode,
|
||||
if (backup_cred(cifs_sb))
|
||||
create_options |= CREATE_OPEN_BACKUP_INTENT;
|
||||
|
||||
rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_CREATE,
|
||||
GENERIC_WRITE, create_options,
|
||||
&fileHandle, &oplock, buf, cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
oparms.tcon = tcon;
|
||||
oparms.cifs_sb = cifs_sb;
|
||||
oparms.desired_access = GENERIC_WRITE;
|
||||
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)
|
||||
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;
|
||||
io_parms.netfid = fileHandle;
|
||||
io_parms.netfid = fid.netfid;
|
||||
io_parms.pid = current->tgid;
|
||||
io_parms.tcon = pTcon;
|
||||
io_parms.tcon = tcon;
|
||||
io_parms.offset = 0;
|
||||
io_parms.length = sizeof(struct win_dev);
|
||||
if (S_ISCHR(mode)) {
|
||||
memcpy(pdev->type, "IntxCHR", 8);
|
||||
pdev->major =
|
||||
cpu_to_le64(MAJOR(device_number));
|
||||
pdev->minor =
|
||||
cpu_to_le64(MINOR(device_number));
|
||||
rc = CIFSSMBWrite(xid, &io_parms,
|
||||
&bytes_written, (char *)pdev,
|
||||
NULL, 0);
|
||||
pdev->major = cpu_to_le64(MAJOR(device_number));
|
||||
pdev->minor = cpu_to_le64(MINOR(device_number));
|
||||
rc = CIFSSMBWrite(xid, &io_parms, &bytes_written, (char *)pdev,
|
||||
NULL, 0);
|
||||
} else if (S_ISBLK(mode)) {
|
||||
memcpy(pdev->type, "IntxBLK", 8);
|
||||
pdev->major =
|
||||
cpu_to_le64(MAJOR(device_number));
|
||||
pdev->minor =
|
||||
cpu_to_le64(MINOR(device_number));
|
||||
rc = CIFSSMBWrite(xid, &io_parms,
|
||||
&bytes_written, (char *)pdev,
|
||||
NULL, 0);
|
||||
pdev->major = cpu_to_le64(MAJOR(device_number));
|
||||
pdev->minor = cpu_to_le64(MINOR(device_number));
|
||||
rc = CIFSSMBWrite(xid, &io_parms, &bytes_written, (char *)pdev,
|
||||
NULL, 0);
|
||||
} /* else if (S_ISFIFO) */
|
||||
CIFSSMBClose(xid, pTcon, fileHandle);
|
||||
CIFSSMBClose(xid, tcon, fid.netfid);
|
||||
d_drop(direntry);
|
||||
|
||||
/* FIXME: add code here to set EAs */
|
||||
|
@ -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
|
||||
* 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
|
||||
* version of file size can be stale. If we knew for sure that inode was
|
||||
* not dirty locally we could do this.
|
||||
|
186
fs/cifs/inode.c
186
fs/cifs/inode.c
@ -383,10 +383,10 @@ int cifs_get_inode_info_unix(struct inode **pinode,
|
||||
|
||||
/* check for Minshall+French symlinks */
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
|
||||
int tmprc = CIFSCheckMFSymlink(xid, tcon, cifs_sb, &fattr,
|
||||
full_path);
|
||||
int tmprc = check_mf_symlink(xid, tcon, cifs_sb, &fattr,
|
||||
full_path);
|
||||
if (tmprc)
|
||||
cifs_dbg(FYI, "CIFSCheckMFSymlink: %d\n", tmprc);
|
||||
cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc);
|
||||
}
|
||||
|
||||
if (*pinode == NULL) {
|
||||
@ -404,18 +404,20 @@ int cifs_get_inode_info_unix(struct inode **pinode,
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
int rc;
|
||||
int oplock = 0;
|
||||
__u16 netfid;
|
||||
struct tcon_link *tlink;
|
||||
struct cifs_tcon *tcon;
|
||||
struct cifs_fid fid;
|
||||
struct cifs_open_parms oparms;
|
||||
struct cifs_io_parms io_parms;
|
||||
char buf[24];
|
||||
unsigned int bytes_read;
|
||||
char *pbuf;
|
||||
int buf_type = CIFS_NO_BUFFER;
|
||||
|
||||
pbuf = buf;
|
||||
|
||||
@ -436,62 +438,69 @@ cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path,
|
||||
return PTR_ERR(tlink);
|
||||
tcon = tlink_tcon(tlink);
|
||||
|
||||
rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, GENERIC_READ,
|
||||
CREATE_NOT_DIR, &netfid, &oplock, NULL,
|
||||
cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags &
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
if (rc == 0) {
|
||||
int buf_type = CIFS_NO_BUFFER;
|
||||
/* Read header */
|
||||
io_parms.netfid = netfid;
|
||||
io_parms.pid = current->tgid;
|
||||
io_parms.tcon = tcon;
|
||||
io_parms.offset = 0;
|
||||
io_parms.length = 24;
|
||||
rc = CIFSSMBRead(xid, &io_parms, &bytes_read, &pbuf,
|
||||
&buf_type);
|
||||
if ((rc == 0) && (bytes_read >= 8)) {
|
||||
if (memcmp("IntxBLK", pbuf, 8) == 0) {
|
||||
cifs_dbg(FYI, "Block device\n");
|
||||
fattr->cf_mode |= S_IFBLK;
|
||||
fattr->cf_dtype = DT_BLK;
|
||||
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("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 {
|
||||
fattr->cf_mode |= S_IFREG; /* file? */
|
||||
fattr->cf_dtype = DT_REG;
|
||||
rc = -EOPNOTSUPP;
|
||||
}
|
||||
} 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, netfid);
|
||||
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, NULL);
|
||||
if (rc) {
|
||||
cifs_put_tlink(tlink);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Read header */
|
||||
io_parms.netfid = fid.netfid;
|
||||
io_parms.pid = current->tgid;
|
||||
io_parms.tcon = tcon;
|
||||
io_parms.offset = 0;
|
||||
io_parms.length = 24;
|
||||
|
||||
rc = CIFSSMBRead(xid, &io_parms, &bytes_read, &pbuf, &buf_type);
|
||||
if ((rc == 0) && (bytes_read >= 8)) {
|
||||
if (memcmp("IntxBLK", pbuf, 8) == 0) {
|
||||
cifs_dbg(FYI, "Block device\n");
|
||||
fattr->cf_mode |= S_IFBLK;
|
||||
fattr->cf_dtype = DT_BLK;
|
||||
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("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 {
|
||||
fattr->cf_mode |= S_IFREG; /* file? */
|
||||
fattr->cf_dtype = DT_REG;
|
||||
rc = -EOPNOTSUPP;
|
||||
}
|
||||
} 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);
|
||||
return rc;
|
||||
}
|
||||
@ -800,10 +809,10 @@ cifs_get_inode_info(struct inode **inode, const char *full_path,
|
||||
|
||||
/* check for Minshall+French symlinks */
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
|
||||
tmprc = CIFSCheckMFSymlink(xid, tcon, cifs_sb, &fattr,
|
||||
full_path);
|
||||
tmprc = check_mf_symlink(xid, tcon, cifs_sb, &fattr,
|
||||
full_path);
|
||||
if (tmprc)
|
||||
cifs_dbg(FYI, "CIFSCheckMFSymlink: %d\n", tmprc);
|
||||
cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc);
|
||||
}
|
||||
|
||||
if (!*inode) {
|
||||
@ -1032,7 +1041,8 @@ cifs_rename_pending_delete(const char *full_path, struct dentry *dentry,
|
||||
{
|
||||
int oplock = 0;
|
||||
int rc;
|
||||
__u16 netfid;
|
||||
struct cifs_fid fid;
|
||||
struct cifs_open_parms oparms;
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct cifsInodeInfo *cifsInode = CIFS_I(inode);
|
||||
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,
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN,
|
||||
DELETE|FILE_WRITE_ATTRIBUTES, CREATE_NOT_DIR,
|
||||
&netfid, &oplock, NULL, cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
oparms.tcon = tcon;
|
||||
oparms.cifs_sb = cifs_sb;
|
||||
oparms.desired_access = DELETE | FILE_WRITE_ATTRIBUTES;
|
||||
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)
|
||||
goto out;
|
||||
|
||||
@ -1079,7 +1095,7 @@ cifs_rename_pending_delete(const char *full_path, struct dentry *dentry,
|
||||
goto out_close;
|
||||
}
|
||||
info_buf->Attributes = cpu_to_le32(dosattr);
|
||||
rc = CIFSSMBSetFileInfo(xid, tcon, info_buf, netfid,
|
||||
rc = CIFSSMBSetFileInfo(xid, tcon, info_buf, fid.netfid,
|
||||
current->tgid);
|
||||
/* although we would like to mark the file hidden
|
||||
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,
|
||||
}
|
||||
|
||||
/* 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_MOUNT_MAP_SPECIAL_CHR);
|
||||
if (rc != 0) {
|
||||
@ -1100,7 +1117,7 @@ cifs_rename_pending_delete(const char *full_path, struct dentry *dentry,
|
||||
|
||||
/* try to set DELETE_ON_CLOSE */
|
||||
if (!cifsInode->delete_pending) {
|
||||
rc = CIFSSMBSetFileDisposition(xid, tcon, true, netfid,
|
||||
rc = CIFSSMBSetFileDisposition(xid, tcon, true, fid.netfid,
|
||||
current->tgid);
|
||||
/*
|
||||
* 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,
|
||||
}
|
||||
|
||||
out_close:
|
||||
CIFSSMBClose(xid, tcon, netfid);
|
||||
CIFSSMBClose(xid, tcon, fid.netfid);
|
||||
out:
|
||||
kfree(info_buf);
|
||||
cifs_put_tlink(tlink);
|
||||
@ -1132,13 +1149,13 @@ out:
|
||||
* them anyway.
|
||||
*/
|
||||
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_MOUNT_MAP_SPECIAL_CHR);
|
||||
undo_setattr:
|
||||
if (dosattr != 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))
|
||||
cifsInode->cifsAttrs = origattr;
|
||||
}
|
||||
@ -1549,7 +1566,8 @@ cifs_do_rename(const unsigned int xid, struct dentry *from_dentry,
|
||||
struct tcon_link *tlink;
|
||||
struct cifs_tcon *tcon;
|
||||
struct TCP_Server_Info *server;
|
||||
__u16 srcfid;
|
||||
struct cifs_fid fid;
|
||||
struct cifs_open_parms oparms;
|
||||
int oplock, rc;
|
||||
|
||||
tlink = cifs_sb_tlink(cifs_sb);
|
||||
@ -1576,17 +1594,23 @@ cifs_do_rename(const unsigned int xid, struct dentry *from_dentry,
|
||||
if (to_dentry->d_parent != from_dentry->d_parent)
|
||||
goto do_rename_exit;
|
||||
|
||||
oparms.tcon = tcon;
|
||||
oparms.cifs_sb = cifs_sb;
|
||||
/* open the file to be renamed -- we need DELETE perms */
|
||||
rc = CIFSSMBOpen(xid, tcon, from_path, FILE_OPEN, DELETE,
|
||||
CREATE_NOT_DIR, &srcfid, &oplock, NULL,
|
||||
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
oparms.desired_access = DELETE;
|
||||
oparms.create_options = CREATE_NOT_DIR;
|
||||
oparms.disposition = FILE_OPEN;
|
||||
oparms.path = from_path;
|
||||
oparms.fid = &fid;
|
||||
oparms.reconnect = false;
|
||||
|
||||
rc = CIFS_open(xid, &oparms, &oplock, NULL);
|
||||
if (rc == 0) {
|
||||
rc = CIFSSMBRenameOpenFile(xid, tcon, srcfid,
|
||||
rc = CIFSSMBRenameOpenFile(xid, tcon, fid.netfid,
|
||||
(const char *) to_dentry->d_name.name,
|
||||
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
CIFSSMBClose(xid, tcon, srcfid);
|
||||
CIFSSMBClose(xid, tcon, fid.netfid);
|
||||
}
|
||||
do_rename_exit:
|
||||
cifs_put_tlink(tlink);
|
||||
|
345
fs/cifs/link.c
345
fs/cifs/link.c
@ -29,6 +29,10 @@
|
||||
#include "cifs_debug.h"
|
||||
#include "cifs_fs_sb.h"
|
||||
|
||||
/*
|
||||
* M-F Symlink Functions - Begin
|
||||
*/
|
||||
|
||||
#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_LINK_OFFSET (CIFS_MF_SYMLINK_MD5_OFFSET+(32+1))
|
||||
@ -91,10 +95,8 @@ symlink_hash_err:
|
||||
}
|
||||
|
||||
static int
|
||||
CIFSParseMFSymlink(const u8 *buf,
|
||||
unsigned int buf_len,
|
||||
unsigned int *_link_len,
|
||||
char **_link_str)
|
||||
parse_mf_symlink(const u8 *buf, unsigned int buf_len, unsigned int *_link_len,
|
||||
char **_link_str)
|
||||
{
|
||||
int rc;
|
||||
unsigned int link_len;
|
||||
@ -137,7 +139,7 @@ CIFSParseMFSymlink(const u8 *buf,
|
||||
}
|
||||
|
||||
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;
|
||||
unsigned int link_len;
|
||||
@ -180,120 +182,10 @@ CIFSFormatMFSymlink(u8 *buf, unsigned int buf_len, const char *link_str)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
CIFSCreateMFSymLink(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
const char *fromName, const char *toName,
|
||||
struct cifs_sb_info *cifs_sb)
|
||||
{
|
||||
int rc;
|
||||
int oplock = 0;
|
||||
int remap;
|
||||
int create_options = CREATE_NOT_DIR;
|
||||
__u16 netfid = 0;
|
||||
u8 *buf;
|
||||
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);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
rc = CIFSFormatMFSymlink(buf, CIFS_MF_SYMLINK_FILE_SIZE, toName);
|
||||
if (rc != 0) {
|
||||
kfree(buf);
|
||||
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);
|
||||
CIFSSMBClose(xid, tcon, netfid);
|
||||
kfree(buf);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
if (bytes_written != CIFS_MF_SYMLINK_FILE_SIZE)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
CIFSQueryMFSymLink(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
const unsigned char *searchName, char **symlinkinfo,
|
||||
const struct nls_table *nls_codepage, int remap)
|
||||
{
|
||||
int rc;
|
||||
int oplock = 0;
|
||||
__u16 netfid = 0;
|
||||
u8 *buf;
|
||||
char *pbuf;
|
||||
unsigned int bytes_read = 0;
|
||||
int buf_type = CIFS_NO_BUFFER;
|
||||
unsigned int link_len = 0;
|
||||
struct cifs_io_parms io_parms;
|
||||
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);
|
||||
if (!buf)
|
||||
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)
|
||||
couldbe_mf_symlink(const struct cifs_fattr *fattr)
|
||||
{
|
||||
if (!(fattr->cf_mode & S_IFREG))
|
||||
if (!S_ISREG(fattr->cf_mode))
|
||||
/* it's not a symlink */
|
||||
return false;
|
||||
|
||||
@ -304,66 +196,80 @@ CIFSCouldBeMFSymlink(const struct cifs_fattr *fattr)
|
||||
return true;
|
||||
}
|
||||
|
||||
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)
|
||||
static int
|
||||
create_mf_symlink(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb, const char *fromName,
|
||||
const char *toName)
|
||||
{
|
||||
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;
|
||||
u8 *buf;
|
||||
unsigned int bytes_written = 0;
|
||||
|
||||
tlink = cifs_sb_tlink(cifs_sb);
|
||||
if (IS_ERR(tlink))
|
||||
return PTR_ERR(tlink);
|
||||
ptcon = tlink_tcon(tlink);
|
||||
buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
rc = CIFSSMBOpen(xid, ptcon, path, FILE_OPEN, GENERIC_READ,
|
||||
CREATE_NOT_DIR, &netfid, &oplock, &file_info,
|
||||
cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags &
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
if (rc != 0) {
|
||||
cifs_put_tlink(tlink);
|
||||
return rc;
|
||||
}
|
||||
rc = format_mf_symlink(buf, CIFS_MF_SYMLINK_FILE_SIZE, toName);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
if (file_info.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) {
|
||||
CIFSSMBClose(xid, ptcon, netfid);
|
||||
cifs_put_tlink(tlink);
|
||||
/* it's not a symlink */
|
||||
return rc;
|
||||
}
|
||||
rc = tcon->ses->server->ops->create_mf_symlink(xid, tcon, cifs_sb,
|
||||
fromName, buf, &bytes_written);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
io_parms.netfid = netfid;
|
||||
io_parms.pid = current->tgid;
|
||||
io_parms.tcon = ptcon;
|
||||
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);
|
||||
if (bytes_written != CIFS_MF_SYMLINK_FILE_SIZE)
|
||||
rc = -EIO;
|
||||
out:
|
||||
kfree(buf);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
CIFSCheckMFSymlink(unsigned int xid, struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
|
||||
const unsigned char *path)
|
||||
static int
|
||||
query_mf_symlink(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb, const unsigned char *path,
|
||||
char **symlinkinfo)
|
||||
{
|
||||
int rc;
|
||||
u8 *buf = NULL;
|
||||
unsigned int link_len = 0;
|
||||
unsigned int bytes_read = 0;
|
||||
|
||||
if (!CIFSCouldBeMFSymlink(fattr))
|
||||
buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
if (tcon->ses->server->ops->query_mf_symlink)
|
||||
rc = tcon->ses->server->ops->query_mf_symlink(xid, tcon,
|
||||
cifs_sb, path, buf, &bytes_read);
|
||||
else
|
||||
rc = -ENOSYS;
|
||||
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
if (bytes_read == 0) { /* not a symlink */
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = parse_mf_symlink(buf, bytes_read, &link_len, symlinkinfo);
|
||||
out:
|
||||
kfree(buf);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
check_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
|
||||
const unsigned char *path)
|
||||
{
|
||||
int rc;
|
||||
u8 *buf = NULL;
|
||||
unsigned int link_len = 0;
|
||||
unsigned int bytes_read = 0;
|
||||
|
||||
if (!couldbe_mf_symlink(fattr))
|
||||
/* it's not a symlink */
|
||||
return 0;
|
||||
|
||||
@ -372,8 +278,8 @@ CIFSCheckMFSymlink(unsigned int xid, struct cifs_tcon *tcon,
|
||||
return -ENOMEM;
|
||||
|
||||
if (tcon->ses->server->ops->query_mf_symlink)
|
||||
rc = tcon->ses->server->ops->query_mf_symlink(path, buf,
|
||||
&bytes_read, cifs_sb, xid);
|
||||
rc = tcon->ses->server->ops->query_mf_symlink(xid, tcon,
|
||||
cifs_sb, path, buf, &bytes_read);
|
||||
else
|
||||
rc = -ENOSYS;
|
||||
|
||||
@ -383,7 +289,7 @@ CIFSCheckMFSymlink(unsigned int xid, struct cifs_tcon *tcon,
|
||||
if (bytes_read == 0) /* not a symlink */
|
||||
goto out;
|
||||
|
||||
rc = CIFSParseMFSymlink(buf, bytes_read, &link_len, NULL);
|
||||
rc = parse_mf_symlink(buf, bytes_read, &link_len, NULL);
|
||||
if (rc == -EINVAL) {
|
||||
/* it's not a symlink */
|
||||
rc = 0;
|
||||
@ -403,6 +309,95 @@ out:
|
||||
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
|
||||
cifs_hardlink(struct dentry *old_file, struct inode *inode,
|
||||
struct dentry *direntry)
|
||||
@ -438,8 +433,10 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
else {
|
||||
server = tcon->ses->server;
|
||||
if (!server->ops->create_hardlink)
|
||||
return -ENOSYS;
|
||||
if (!server->ops->create_hardlink) {
|
||||
rc = -ENOSYS;
|
||||
goto cifs_hl_exit;
|
||||
}
|
||||
rc = server->ops->create_hardlink(xid, tcon, from_name, to_name,
|
||||
cifs_sb);
|
||||
if ((rc == -EIO) || (rc == -EINVAL))
|
||||
@ -530,15 +527,10 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
|
||||
* and fallback to UNIX Extensions Symlinks.
|
||||
*/
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS)
|
||||
rc = CIFSQueryMFSymLink(xid, tcon, full_path, &target_path,
|
||||
cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags &
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
rc = query_mf_symlink(xid, tcon, cifs_sb, full_path,
|
||||
&target_path);
|
||||
|
||||
if ((rc != 0) && cap_unix(tcon->ses))
|
||||
rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, &target_path,
|
||||
cifs_sb->local_nls);
|
||||
else if (rc != 0 && server->ops->query_symlink)
|
||||
if (rc != 0 && server->ops->query_symlink)
|
||||
rc = server->ops->query_symlink(xid, tcon, full_path,
|
||||
&target_path, cifs_sb);
|
||||
|
||||
@ -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 */
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS)
|
||||
rc = CIFSCreateMFSymLink(xid, pTcon, full_path, symname,
|
||||
cifs_sb);
|
||||
rc = create_mf_symlink(xid, pTcon, cifs_sb, full_path, symname);
|
||||
else if (pTcon->unix_ext)
|
||||
rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname,
|
||||
cifs_sb->local_nls);
|
||||
|
@ -749,7 +749,7 @@ static int cifs_filldir(char *find_entry, struct file *file,
|
||||
}
|
||||
|
||||
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,
|
||||
* 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,
|
||||
if (!rc && (le32_to_cpu(data->Attributes) & ATTR_REPARSE)) {
|
||||
int tmprc;
|
||||
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 */
|
||||
tmprc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN,
|
||||
FILE_READ_ATTRIBUTES, 0, &netfid, &oplock,
|
||||
NULL, cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
tmprc = CIFS_open(xid, &oparms, &oplock, NULL);
|
||||
if (tmprc == -EOPNOTSUPP)
|
||||
*symlink = true;
|
||||
else
|
||||
CIFSSMBClose(xid, tcon, netfid);
|
||||
CIFSSMBClose(xid, tcon, fid.netfid);
|
||||
}
|
||||
|
||||
return rc;
|
||||
@ -705,12 +712,7 @@ cifs_open_file(const unsigned int xid, struct cifs_open_parms *oparms,
|
||||
oparms->cifs_sb->local_nls,
|
||||
oparms->cifs_sb->mnt_cifs_flags
|
||||
& CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
return CIFSSMBOpen(xid, oparms->tcon, oparms->path,
|
||||
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);
|
||||
return CIFS_open(xid, oparms, oplock, buf);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -761,8 +763,9 @@ smb_set_file_info(struct inode *inode, const char *full_path,
|
||||
{
|
||||
int oplock = 0;
|
||||
int rc;
|
||||
__u16 netfid;
|
||||
__u32 netpid;
|
||||
struct cifs_fid fid;
|
||||
struct cifs_open_parms oparms;
|
||||
struct cifsFileInfo *open_file;
|
||||
struct cifsInodeInfo *cinode = CIFS_I(inode);
|
||||
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,
|
||||
/* if the file is already open for write, just use that fileid */
|
||||
open_file = find_writable_file(cinode, true);
|
||||
if (open_file) {
|
||||
netfid = open_file->fid.netfid;
|
||||
fid.netfid = open_file->fid.netfid;
|
||||
netpid = open_file->pid;
|
||||
tcon = tlink_tcon(open_file->tlink);
|
||||
goto set_via_filehandle;
|
||||
@ -796,12 +799,17 @@ smb_set_file_info(struct inode *inode, const char *full_path,
|
||||
goto out;
|
||||
}
|
||||
|
||||
cifs_dbg(FYI, "calling SetFileInfo since SetPathInfo for times not supported by this server\n");
|
||||
rc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN,
|
||||
SYNCHRONIZE | FILE_WRITE_ATTRIBUTES, CREATE_NOT_DIR,
|
||||
&netfid, &oplock, NULL, cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
oparms.tcon = tcon;
|
||||
oparms.cifs_sb = cifs_sb;
|
||||
oparms.desired_access = SYNCHRONIZE | FILE_WRITE_ATTRIBUTES;
|
||||
oparms.create_options = CREATE_NOT_DIR;
|
||||
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 == -EIO)
|
||||
rc = -EINVAL;
|
||||
@ -811,12 +819,12 @@ smb_set_file_info(struct inode *inode, const char *full_path,
|
||||
netpid = current->tgid;
|
||||
|
||||
set_via_filehandle:
|
||||
rc = CIFSSMBSetFileInfo(xid, tcon, buf, netfid, netpid);
|
||||
rc = CIFSSMBSetFileInfo(xid, tcon, buf, fid.netfid, netpid);
|
||||
if (!rc)
|
||||
cinode->cifsAttrs = le32_to_cpu(buf->Attributes);
|
||||
|
||||
if (open_file == NULL)
|
||||
CIFSSMBClose(xid, tcon, netfid);
|
||||
CIFSSMBClose(xid, tcon, fid.netfid);
|
||||
else
|
||||
cifsFileInfo_put(open_file);
|
||||
out:
|
||||
@ -907,6 +915,33 @@ cifs_mand_lock(const unsigned int xid, struct cifsFileInfo *cfile, __u64 offset,
|
||||
(__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
|
||||
cifs_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
const char *full_path, char **target_path,
|
||||
@ -914,27 +949,47 @@ cifs_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
{
|
||||
int rc;
|
||||
int oplock = 0;
|
||||
__u16 netfid;
|
||||
struct cifs_fid fid;
|
||||
struct cifs_open_parms oparms;
|
||||
|
||||
cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path);
|
||||
|
||||
rc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN,
|
||||
FILE_READ_ATTRIBUTES, OPEN_REPARSE_POINT, &netfid,
|
||||
&oplock, NULL, cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
if (rc)
|
||||
return rc;
|
||||
/* Check for unix extensions */
|
||||
if (cap_unix(tcon->ses)) {
|
||||
rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, target_path,
|
||||
cifs_sb->local_nls);
|
||||
if (rc == -EREMOTE)
|
||||
rc = cifs_unix_dfs_readlink(xid, tcon, full_path,
|
||||
target_path,
|
||||
cifs_sb->local_nls);
|
||||
|
||||
rc = CIFSSMBQuerySymLink(xid, tcon, netfid, target_path,
|
||||
cifs_sb->local_nls);
|
||||
if (rc) {
|
||||
CIFSSMBClose(xid, tcon, netfid);
|
||||
return rc;
|
||||
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)
|
||||
goto out;
|
||||
|
||||
rc = CIFSSMBQuerySymLink(xid, tcon, fid.netfid, target_path,
|
||||
cifs_sb->local_nls);
|
||||
if (rc)
|
||||
goto out_close;
|
||||
|
||||
convert_delimiter(*target_path, '/');
|
||||
CIFSSMBClose(xid, tcon, netfid);
|
||||
cifs_dbg(FYI, "%s: target path: %s\n", __func__, *target_path);
|
||||
out_close:
|
||||
CIFSSMBClose(xid, tcon, fid.netfid);
|
||||
out:
|
||||
if (!rc)
|
||||
cifs_dbg(FYI, "%s: target path: %s\n", __func__, *target_path);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -1009,7 +1064,8 @@ struct smb_version_operations smb1_operations = {
|
||||
.mand_lock = cifs_mand_lock,
|
||||
.mand_unlock_range = cifs_unlock_range,
|
||||
.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,
|
||||
};
|
||||
|
||||
|
@ -82,9 +82,11 @@ int cifs_removexattr(struct dentry *direntry, const char *ea_name)
|
||||
goto remove_ea_exit;
|
||||
|
||||
ea_name += XATTR_USER_PREFIX_LEN; /* skip past user. prefix */
|
||||
rc = CIFSSMBSetEA(xid, pTcon, full_path, ea_name, NULL,
|
||||
(__u16)0, cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
if (pTcon->ses->server->ops->set_EA)
|
||||
rc = pTcon->ses->server->ops->set_EA(xid, pTcon,
|
||||
full_path, ea_name, NULL, (__u16)0,
|
||||
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
}
|
||||
remove_ea_exit:
|
||||
kfree(full_path);
|
||||
@ -149,18 +151,22 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name,
|
||||
cifs_dbg(FYI, "attempt to set cifs inode metadata\n");
|
||||
|
||||
ea_name += XATTR_USER_PREFIX_LEN; /* skip past user. prefix */
|
||||
rc = CIFSSMBSetEA(xid, pTcon, full_path, ea_name, ea_value,
|
||||
(__u16)value_size, cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
if (pTcon->ses->server->ops->set_EA)
|
||||
rc = pTcon->ses->server->ops->set_EA(xid, pTcon,
|
||||
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)
|
||||
== 0) {
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
|
||||
goto set_ea_exit;
|
||||
|
||||
ea_name += XATTR_OS2_PREFIX_LEN; /* skip past os2. prefix */
|
||||
rc = CIFSSMBSetEA(xid, pTcon, full_path, ea_name, ea_value,
|
||||
(__u16)value_size, cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
if (pTcon->ses->server->ops->set_EA)
|
||||
rc = pTcon->ses->server->ops->set_EA(xid, pTcon,
|
||||
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,
|
||||
strlen(CIFS_XATTR_CIFS_ACL)) == 0) {
|
||||
#ifdef CONFIG_CIFS_ACL
|
||||
@ -272,17 +278,21 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
|
||||
/* revalidate/getattr then populate from inode */
|
||||
} /* BB add else when above is implemented */
|
||||
ea_name += XATTR_USER_PREFIX_LEN; /* skip past user. prefix */
|
||||
rc = CIFSSMBQAllEAs(xid, pTcon, full_path, ea_name, ea_value,
|
||||
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, 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) {
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
|
||||
goto get_ea_exit;
|
||||
|
||||
ea_name += XATTR_OS2_PREFIX_LEN; /* skip past os2. prefix */
|
||||
rc = CIFSSMBQAllEAs(xid, pTcon, full_path, ea_name, ea_value,
|
||||
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, 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,
|
||||
strlen(POSIX_ACL_XATTR_ACCESS)) == 0) {
|
||||
#ifdef CONFIG_CIFS_POSIX
|
||||
@ -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
|
||||
search server for EAs or streams to
|
||||
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:
|
||||
kfree(full_path);
|
||||
free_xid(xid);
|
||||
|
Loading…
Reference in New Issue
Block a user