Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6: (21 commits)
  [CIFS] Remove debug statement
  Fix possible access to undefined memory region.
  [CIFS] Enable DFS support for Windows query path info
  [CIFS] Enable DFS support for Unix query path info
  [CIFS] add missing seq_printf to cifs_show_options for hard mount option
  [CIFS] add more complete mount options to cifs_show_options
  [CIFS] Add missing defines for DFS
  CIFSGetDFSRefer cleanup + dfs_referral_level_3 fixed to conform REFERRAL_V3 the MS-DFSC spec.
  Fixed DFS code to work with new 'build_path_from_dentry', that returns full path if share in the dfs, now.
  [CIFS] enable parsing for transport encryption mount parm
  [CIFS] Finishup DFS code
  [CIFS] BKL-removal: convert CIFS over to unlocked_ioctl
  [CIFS] suppress duplicate warning
  [CIFS] Fix paths when share is in DFS to include proper prefix
  add function to convert access flags to legacy open mode
  clarify return value of cifs_convert_flags()
  [CIFS] don't explicitly do a FindClose on rewind when directory search has ended
  [CIFS] cleanup old checkpatch warnings
  [CIFS] CIFSSMBPosixLock should return -EINVAL on error
  fix memory leak in CIFSFindNext
  ...
This commit is contained in:
Linus Torvalds 2008-05-20 21:12:14 -07:00
Родитель d40ace0c7b 397d71ddfd
Коммит 5cf11daf9a
22 изменённых файлов: 625 добавлений и 558 удалений

Просмотреть файл

@ -36,6 +36,7 @@ Miklos Szeredi
Kazeon team for various fixes especially for 2.4 version.
Asser Ferno (Change Notify support)
Shaggy (Dave Kleikamp) for inumerable small fs suggestions and some good cleanup
Igor Mammedov (DFS support)
Test case and Bug Report contributors
-------------------------------------

Просмотреть файл

@ -1,5 +1,7 @@
Version 1.53
------------
DFS support added (Microsoft Distributed File System client support needed
for referrals which enable a hierarchical name space among servers).
Version 1.52
------------
@ -12,7 +14,8 @@ Add ability to modify cifs acls for handling chmod (when mounted with
cifsacl flag). Fix prefixpath path separator so we can handle mounts
with prefixpaths longer than one directory (one path component) when
mounted to Windows servers. Fix slow file open when cifsacl
enabled.
enabled. Fix memory leak in FindNext when the SMB call returns -EBADF.
Version 1.51
------------

Просмотреть файл

@ -483,6 +483,11 @@ A partial list of the supported mount options follows:
sign Must use packet signing (helps avoid unwanted data modification
by intermediate systems in the route). Note that signing
does not work with lanman or plaintext authentication.
seal Must seal (encrypt) all data on this mounted share before
sending on the network. Requires support for Unix Extensions.
Note that this differs from the sign mount option in that it
causes encryption of data sent over this mounted share but other
shares mounted to the same server are unaffected.
sec Security mode. Allowed values are:
none attempt to connection as a null user (no name)
krb5 Use Kerberos version 5 authentication

Просмотреть файл

@ -1,4 +1,4 @@
Version 1.52 January 3, 2008
Version 1.53 May 20, 2008
A Partial List of Missing Features
==================================
@ -20,20 +20,21 @@ d) Cleanup now unneeded SessSetup code in
fs/cifs/connect.c and add back in NTLMSSP code if any servers
need it
e) ms-dfs and ms-dfs host name resolution cleanup
f) fix NTLMv2 signing when two mounts with different users to same
e) fix NTLMv2 signing when two mounts with different users to same
server.
g) Directory entry caching relies on a 1 second timer, rather than
f) Directory entry caching relies on a 1 second timer, rather than
using FindNotify or equivalent. - (started)
h) quota support (needs minor kernel change since quota calls
g) quota support (needs minor kernel change since quota calls
to make it to network filesystems or deviceless filesystems)
i) investigate sync behavior (including syncpage) and check
h) investigate sync behavior (including syncpage) and check
for proper behavior of intr/nointr
i) improve support for very old servers (OS/2 and Win9x for example)
Including support for changing the time remotely (utimes command).
j) hook lower into the sockets api (as NFS/SunRPC does) to avoid the
extra copy in/out of the socket buffers in some cases.

Просмотреть файл

@ -219,53 +219,6 @@ static struct vfsmount *cifs_dfs_do_refmount(const struct vfsmount *mnt_parent,
}
static char *build_full_dfs_path_from_dentry(struct dentry *dentry)
{
char *full_path = NULL;
char *search_path;
char *tmp_path;
size_t l_max_len;
struct cifs_sb_info *cifs_sb;
if (dentry->d_inode == NULL)
return NULL;
cifs_sb = CIFS_SB(dentry->d_inode->i_sb);
if (cifs_sb->tcon == NULL)
return NULL;
search_path = build_path_from_dentry(dentry);
if (search_path == NULL)
return NULL;
if (cifs_sb->tcon->Flags & SMB_SHARE_IS_IN_DFS) {
int i;
/* we should use full path name for correct working with DFS */
l_max_len = strnlen(cifs_sb->tcon->treeName, MAX_TREE_SIZE+1) +
strnlen(search_path, MAX_PATHCONF) + 1;
tmp_path = kmalloc(l_max_len, GFP_KERNEL);
if (tmp_path == NULL) {
kfree(search_path);
return NULL;
}
strncpy(tmp_path, cifs_sb->tcon->treeName, l_max_len);
tmp_path[l_max_len-1] = 0;
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
for (i = 0; i < l_max_len; i++) {
if (tmp_path[i] == '\\')
tmp_path[i] = '/';
}
strncat(tmp_path, search_path, l_max_len - strlen(tmp_path));
full_path = tmp_path;
kfree(search_path);
} else {
full_path = search_path;
}
return full_path;
}
static int add_mount_helper(struct vfsmount *newmnt, struct nameidata *nd,
struct list_head *mntlist)
{
@ -333,7 +286,7 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
goto out_err;
}
full_path = build_full_dfs_path_from_dentry(dentry);
full_path = build_path_from_dentry(dentry);
if (full_path == NULL) {
rc = -ENOMEM;
goto out_err;

Просмотреть файл

@ -30,6 +30,7 @@
#define CIFS_MOUNT_CIFS_ACL 0x200 /* send ACL requests to non-POSIX srv */
#define CIFS_MOUNT_OVERR_UID 0x400 /* override uid returned from server */
#define CIFS_MOUNT_OVERR_GID 0x800 /* override gid returned from server */
#define CIFS_MOUNT_DYNPERM 0x1000 /* allow in-memory only mode setting */
struct cifs_sb_info {
struct cifsTconInfo *tcon; /* primary mount */

Просмотреть файл

@ -1,7 +1,7 @@
/*
* fs/cifs/cifsfs.c
*
* Copyright (C) International Business Machines Corp., 2002,2007
* Copyright (C) International Business Machines Corp., 2002,2008
* Author(s): Steve French (sfrench@us.ibm.com)
*
* Common Internet FileSystem (CIFS) client
@ -353,9 +353,41 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m)
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) ||
!(cifs_sb->tcon->unix_ext))
seq_printf(s, ",gid=%d", cifs_sb->mnt_gid);
if (!cifs_sb->tcon->unix_ext) {
seq_printf(s, ",file_mode=0%o,dir_mode=0%o",
cifs_sb->mnt_file_mode,
cifs_sb->mnt_dir_mode);
}
if (cifs_sb->tcon->seal)
seq_printf(s, ",seal");
if (cifs_sb->tcon->nocase)
seq_printf(s, ",nocase");
if (cifs_sb->tcon->retry)
seq_printf(s, ",hard");
}
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
seq_printf(s, ",posixpaths");
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)
seq_printf(s, ",setuids");
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
seq_printf(s, ",serverino");
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO)
seq_printf(s, ",directio");
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
seq_printf(s, ",nouser_xattr");
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR)
seq_printf(s, ",mapchars");
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)
seq_printf(s, ",sfu");
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
seq_printf(s, ",nobrl");
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL)
seq_printf(s, ",cifsacl");
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
seq_printf(s, ",dynperm");
if (m->mnt_sb->s_flags & MS_POSIXACL)
seq_printf(s, ",acl");
seq_printf(s, ",rsize=%d", cifs_sb->rsize);
seq_printf(s, ",wsize=%d", cifs_sb->wsize);
}
@ -657,7 +689,7 @@ const struct file_operations cifs_file_ops = {
.splice_read = generic_file_splice_read,
.llseek = cifs_llseek,
#ifdef CONFIG_CIFS_POSIX
.ioctl = cifs_ioctl,
.unlocked_ioctl = cifs_ioctl,
#endif /* CONFIG_CIFS_POSIX */
#ifdef CONFIG_CIFS_EXPERIMENTAL
@ -677,7 +709,7 @@ const struct file_operations cifs_file_direct_ops = {
.flush = cifs_flush,
.splice_read = generic_file_splice_read,
#ifdef CONFIG_CIFS_POSIX
.ioctl = cifs_ioctl,
.unlocked_ioctl = cifs_ioctl,
#endif /* CONFIG_CIFS_POSIX */
.llseek = cifs_llseek,
#ifdef CONFIG_CIFS_EXPERIMENTAL
@ -697,7 +729,7 @@ const struct file_operations cifs_file_nobrl_ops = {
.splice_read = generic_file_splice_read,
.llseek = cifs_llseek,
#ifdef CONFIG_CIFS_POSIX
.ioctl = cifs_ioctl,
.unlocked_ioctl = cifs_ioctl,
#endif /* CONFIG_CIFS_POSIX */
#ifdef CONFIG_CIFS_EXPERIMENTAL
@ -716,7 +748,7 @@ const struct file_operations cifs_file_direct_nobrl_ops = {
.flush = cifs_flush,
.splice_read = generic_file_splice_read,
#ifdef CONFIG_CIFS_POSIX
.ioctl = cifs_ioctl,
.unlocked_ioctl = cifs_ioctl,
#endif /* CONFIG_CIFS_POSIX */
.llseek = cifs_llseek,
#ifdef CONFIG_CIFS_EXPERIMENTAL
@ -731,7 +763,7 @@ const struct file_operations cifs_dir_ops = {
#ifdef CONFIG_CIFS_EXPERIMENTAL
.dir_notify = cifs_dir_notify,
#endif /* CONFIG_CIFS_EXPERIMENTAL */
.ioctl = cifs_ioctl,
.unlocked_ioctl = cifs_ioctl,
};
static void

Просмотреть файл

@ -95,8 +95,7 @@ extern int cifs_setxattr(struct dentry *, const char *, const void *,
size_t, int);
extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t);
extern ssize_t cifs_listxattr(struct dentry *, char *, size_t);
extern int cifs_ioctl(struct inode *inode, struct file *filep,
unsigned int command, unsigned long arg);
extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
#ifdef CONFIG_CIFS_EXPERIMENTAL
extern const struct export_operations cifs_export_ops;

Просмотреть файл

@ -281,6 +281,7 @@ struct cifsTconInfo {
bool ipc:1; /* set if connection to IPC$ eg for RPC/PIPES */
bool retry:1;
bool nocase:1;
bool seal:1; /* transport encryption for this mounted share */
bool unix_ext:1; /* if false disable Linux extensions to CIFS protocol
for this mount even if server would support */
/* BB add field for back pointer to sb struct(s)? */

Просмотреть файл

@ -1904,19 +1904,26 @@ typedef struct smb_com_transaction2_get_dfs_refer_req {
char RequestFileName[1];
} __attribute__((packed)) TRANSACTION2_GET_DFS_REFER_REQ;
#define DFS_VERSION cpu_to_le16(0x0003)
/* DFS server target type */
#define DFS_TYPE_LINK 0x0000 /* also for sysvol targets */
#define DFS_TYPE_ROOT 0x0001
/* Referral Entry Flags */
#define DFS_NAME_LIST_REF 0x0200
typedef struct dfs_referral_level_3 {
__le16 VersionNumber;
__le16 ReferralSize;
__le16 ServerType; /* 0x0001 = CIFS server */
__le16 ReferralFlags; /* or proximity - not clear which since it is
always set to zero - SNIA spec says 0x01
means strip off PathConsumed chars before
submitting RequestFileName to remote node */
__le16 TimeToLive;
__le16 Proximity;
__le16 Size;
__le16 ServerType; /* 0x0001 = root targets; 0x0000 = link targets */
__le16 ReferralEntryFlags; /* 0x0200 bit set only for domain
or DC referral responce */
__le32 TimeToLive;
__le16 DfsPathOffset;
__le16 DfsAlternatePathOffset;
__le16 NetworkAddressOffset;
__le16 NetworkAddressOffset; /* offset of the link target */
__le16 ServiceSiteGuid;
} __attribute__((packed)) REFERRAL3;
typedef struct smb_com_transaction_get_dfs_refer_rsp {

Просмотреть файл

@ -93,7 +93,7 @@ extern struct timespec cnvrtDosUnixTm(__u16 date, __u16 time);
extern int cifs_get_inode_info(struct inode **pinode,
const unsigned char *search_path,
FILE_ALL_INFO * pfile_info,
FILE_ALL_INFO *pfile_info,
struct super_block *sb, int xid, const __u16 *pfid);
extern int cifs_get_inode_info_unix(struct inode **pinode,
const unsigned char *search_path,
@ -130,7 +130,7 @@ extern int CIFSFindClose(const int, struct cifsTconInfo *tcon,
extern int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
const unsigned char *searchName,
FILE_ALL_INFO * findData,
FILE_ALL_INFO *findData,
int legacy /* whether to use old info level */,
const struct nls_table *nls_codepage, int remap);
extern int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
@ -141,18 +141,15 @@ extern int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
extern int CIFSSMBUnixQPathInfo(const int xid,
struct cifsTconInfo *tcon,
const unsigned char *searchName,
FILE_UNIX_BASIC_INFO * pFindData,
FILE_UNIX_BASIC_INFO *pFindData,
const struct nls_table *nls_codepage, int remap);
extern int CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
const unsigned char *searchName,
unsigned char **targetUNCs,
unsigned int *number_of_UNC_in_array,
struct dfs_info3_param **target_nodes,
unsigned int *number_of_nodes_in_array,
const struct nls_table *nls_codepage, int remap);
extern int connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
const char *old_path,
const struct nls_table *nls_codepage, int remap);
extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
const char *old_path,
const struct nls_table *nls_codepage,

Просмотреть файл

@ -81,6 +81,40 @@ static struct {
#endif /* CONFIG_CIFS_WEAK_PW_HASH */
#endif /* CIFS_POSIX */
/* Allocates buffer into dst and copies smb string from src to it.
* caller is responsible for freeing dst if function returned 0.
* returns:
* on success - 0
* on failure - errno
*/
static int
cifs_strncpy_to_host(char **dst, const char *src, const int maxlen,
const bool is_unicode, const struct nls_table *nls_codepage)
{
int plen;
if (is_unicode) {
plen = UniStrnlen((wchar_t *)src, maxlen);
*dst = kmalloc(plen + 2, GFP_KERNEL);
if (!*dst)
goto cifs_strncpy_to_host_ErrExit;
cifs_strfromUCS_le(*dst, (__le16 *)src, plen, nls_codepage);
} else {
plen = strnlen(src, maxlen);
*dst = kmalloc(plen + 2, GFP_KERNEL);
if (!*dst)
goto cifs_strncpy_to_host_ErrExit;
strncpy(*dst, src, plen);
}
(*dst)[plen] = 0;
(*dst)[plen+1] = 0; /* harmless for ASCII case, needed for Unicode */
return 0;
cifs_strncpy_to_host_ErrExit:
cERROR(1, ("Failed to allocate buffer for string\n"));
return -ENOMEM;
}
/* Mark as invalid, all open files on tree connections since they
were closed when session to server was lost */
@ -1166,6 +1200,20 @@ static __u16 convert_disposition(int disposition)
return ofun;
}
static int
access_flags_to_smbopen_mode(const int access_flags)
{
int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
if (masked_flags == GENERIC_READ)
return SMBOPEN_READ;
else if (masked_flags == GENERIC_WRITE)
return SMBOPEN_WRITE;
/* just go for read/write */
return SMBOPEN_READWRITE;
}
int
SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
const char *fileName, const int openDisposition,
@ -1207,13 +1255,7 @@ OldOpenRetry:
pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
/* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
/* 0 = read
1 = write
2 = rw
3 = execute
*/
pSMB->Mode = cpu_to_le16(2);
pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
/* set file as system file if special file such
as fifo and server expecting SFU style and
@ -1247,7 +1289,7 @@ OldOpenRetry:
} else {
/* BB verify if wct == 15 */
/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
*netfid = pSMBr->Fid; /* cifs fid stays in le */
/* Let caller know file was created so we can set the mode. */
@ -1767,7 +1809,7 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
cFYI(1, ("Posix Lock"));
if (pLockData == NULL)
return EINVAL;
return -EINVAL;
rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
@ -1944,7 +1986,7 @@ renameRetry:
/* protocol requires ASCII signature byte on Unicode string */
pSMB->OldFileName[name_len + 1] = 0x00;
name_len2 =
cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
toName, PATH_MAX, nls_codepage, remap);
name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
name_len2 *= 2; /* convert to bytes */
@ -2925,7 +2967,8 @@ setAclRetry:
}
params = 6 + name_len;
pSMB->MaxParameterCount = cpu_to_le16(2);
pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
/* BB find max SMB size from sess */
pSMB->MaxDataCount = cpu_to_le16(1000);
pSMB->MaxSetupCount = 0;
pSMB->Reserved = 0;
pSMB->Flags = 0;
@ -3322,7 +3365,8 @@ QPathInfoRetry:
params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
pSMB->TotalDataCount = 0;
pSMB->MaxParameterCount = cpu_to_le16(2);
pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
/* BB find exact max SMB PDU from sess structure BB */
pSMB->MaxDataCount = cpu_to_le16(4000);
pSMB->MaxSetupCount = 0;
pSMB->Reserved = 0;
pSMB->Flags = 0;
@ -3388,7 +3432,7 @@ QPathInfoRetry:
int
CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
const unsigned char *searchName,
FILE_UNIX_BASIC_INFO * pFindData,
FILE_UNIX_BASIC_INFO *pFindData,
const struct nls_table *nls_codepage, int remap)
{
/* SMB_QUERY_FILE_UNIX_BASIC */
@ -3679,6 +3723,7 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
if (rc) {
if (rc == -EBADF) {
psrch_inf->endOfSearch = true;
cifs_buf_release(pSMB);
rc = 0; /* search probably was closed at end of search*/
} else
cFYI(1, ("FindNext returned = %d", rc));
@ -3856,25 +3901,112 @@ GetInodeNumOut:
return rc;
}
/* parses DFS refferal V3 structure
* caller is responsible for freeing target_nodes
* returns:
* on success - 0
* on failure - errno
*/
static int
parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
unsigned int *num_of_nodes,
struct dfs_info3_param **target_nodes,
const struct nls_table *nls_codepage)
{
int i, rc = 0;
char *data_end;
bool is_unicode;
struct dfs_referral_level_3 *ref;
is_unicode = pSMBr->hdr.Flags2 & SMBFLG2_UNICODE;
*num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
if (*num_of_nodes < 1) {
cERROR(1, ("num_referrals: must be at least > 0,"
"but we get num_referrals = %d\n", *num_of_nodes));
rc = -EINVAL;
goto parse_DFS_referrals_exit;
}
ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
if (ref->VersionNumber != 3) {
cERROR(1, ("Referrals of V%d version are not supported,"
"should be V3", ref->VersionNumber));
rc = -EINVAL;
goto parse_DFS_referrals_exit;
}
/* get the upper boundary of the resp buffer */
data_end = (char *)(&(pSMBr->PathConsumed)) +
le16_to_cpu(pSMBr->t2.DataCount);
cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n",
*num_of_nodes,
le16_to_cpu(pSMBr->DFSFlags)));
*target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
*num_of_nodes, GFP_KERNEL);
if (*target_nodes == NULL) {
cERROR(1, ("Failed to allocate buffer for target_nodes\n"));
rc = -ENOMEM;
goto parse_DFS_referrals_exit;
}
/* collect neccessary data from referrals */
for (i = 0; i < *num_of_nodes; i++) {
char *temp;
int max_len;
struct dfs_info3_param *node = (*target_nodes)+i;
node->flags = le16_to_cpu(pSMBr->DFSFlags);
node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
node->server_type = le16_to_cpu(ref->ServerType);
node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
/* copy DfsPath */
temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
max_len = data_end - temp;
rc = cifs_strncpy_to_host(&(node->path_name), temp,
max_len, is_unicode, nls_codepage);
if (rc)
goto parse_DFS_referrals_exit;
/* copy link target UNC */
temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
max_len = data_end - temp;
rc = cifs_strncpy_to_host(&(node->node_name), temp,
max_len, is_unicode, nls_codepage);
if (rc)
goto parse_DFS_referrals_exit;
ref += ref->Size;
}
parse_DFS_referrals_exit:
if (rc) {
free_dfs_info_array(*target_nodes, *num_of_nodes);
*target_nodes = NULL;
*num_of_nodes = 0;
}
return rc;
}
int
CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
const unsigned char *searchName,
unsigned char **targetUNCs,
unsigned int *number_of_UNC_in_array,
struct dfs_info3_param **target_nodes,
unsigned int *num_of_nodes,
const struct nls_table *nls_codepage, int remap)
{
/* TRANS2_GET_DFS_REFERRAL */
TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
struct dfs_referral_level_3 *referrals = NULL;
int rc = 0;
int bytes_returned;
int name_len;
unsigned int i;
char *temp;
__u16 params, byte_count;
*number_of_UNC_in_array = 0;
*targetUNCs = NULL;
*num_of_nodes = 0;
*target_nodes = NULL;
cFYI(1, ("In GetDFSRefer the path %s", searchName));
if (ses == NULL)
@ -3921,7 +4053,8 @@ getDFSRetry:
pSMB->DataCount = 0;
pSMB->DataOffset = 0;
pSMB->MaxParameterCount = 0;
pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
/* BB find exact max SMB PDU from sess structure BB */
pSMB->MaxDataCount = cpu_to_le16(4000);
pSMB->MaxSetupCount = 0;
pSMB->Reserved = 0;
pSMB->Flags = 0;
@ -3943,100 +4076,24 @@ getDFSRetry:
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
if (rc) {
cFYI(1, ("Send error in GetDFSRefer = %d", rc));
} else { /* decode response */
/* BB Add logic to parse referrals here */
goto GetDFSRefExit;
}
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
/* BB Also check if enough total bytes returned? */
if (rc || (pSMBr->ByteCount < 17))
if (rc || (pSMBr->ByteCount < 17)) {
rc = -EIO; /* bad smb */
else {
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
__u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
cFYI(1,
("Decoding GetDFSRefer response BCC: %d Offset %d",
pSMBr->ByteCount, data_offset));
referrals =
(struct dfs_referral_level_3 *)
(8 /* sizeof start of data block */ +
data_offset +
(char *) &pSMBr->hdr.Protocol);
cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n"
"for referral one refer size: 0x%x srv "
"type: 0x%x refer flags: 0x%x ttl: 0x%x",
le16_to_cpu(pSMBr->NumberOfReferrals),
le16_to_cpu(pSMBr->DFSFlags),
le16_to_cpu(referrals->ReferralSize),
le16_to_cpu(referrals->ServerType),
le16_to_cpu(referrals->ReferralFlags),
le16_to_cpu(referrals->TimeToLive)));
/* BB This field is actually two bytes in from start of
data block so we could do safety check that DataBlock
begins at address of pSMBr->NumberOfReferrals */
*number_of_UNC_in_array =
le16_to_cpu(pSMBr->NumberOfReferrals);
/* BB Fix below so can return more than one referral */
if (*number_of_UNC_in_array > 1)
*number_of_UNC_in_array = 1;
/* get the length of the strings describing refs */
name_len = 0;
for (i = 0; i < *number_of_UNC_in_array; i++) {
/* make sure that DfsPathOffset not past end */
__u16 offset =
le16_to_cpu(referrals->DfsPathOffset);
if (offset > data_count) {
/* if invalid referral, stop here and do
not try to copy any more */
*number_of_UNC_in_array = i;
break;
}
temp = ((char *)referrals) + offset;
if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len += UniStrnlen((wchar_t *)temp,
data_count);
} else {
name_len += strnlen(temp, data_count);
}
referrals++;
/* BB add check that referral pointer does
not fall off end PDU */
}
/* BB add check for name_len bigger than bcc */
*targetUNCs =
kmalloc(name_len+1+(*number_of_UNC_in_array),
GFP_KERNEL);
if (*targetUNCs == NULL) {
rc = -ENOMEM;
goto GetDFSRefExit;
}
/* copy the ref strings */
referrals = (struct dfs_referral_level_3 *)
(8 /* sizeof data hdr */ + data_offset +
(char *) &pSMBr->hdr.Protocol);
for (i = 0; i < *number_of_UNC_in_array; i++) {
temp = ((char *)referrals) +
le16_to_cpu(referrals->DfsPathOffset);
if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
cifs_strfromUCS_le(*targetUNCs,
(__le16 *) temp,
name_len,
nls_codepage);
} else {
strncpy(*targetUNCs, temp, name_len);
}
/* BB update target_uncs pointers */
referrals++;
}
temp = *targetUNCs;
temp[name_len] = 0;
}
cFYI(1, ("Decoding GetDFSRefer response BCC: %d Offset %d",
pSMBr->ByteCount,
le16_to_cpu(pSMBr->t2.DataOffset)));
/* parse returned result into more usable form */
rc = parse_DFS_referrals(pSMBr, num_of_nodes,
target_nodes, nls_codepage);
}
GetDFSRefExit:
if (pSMB)
cifs_buf_release(pSMB);
@ -4229,7 +4286,8 @@ QFSAttributeRetry:
params = 2; /* level */
pSMB->TotalDataCount = 0;
pSMB->MaxParameterCount = cpu_to_le16(2);
pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
/* BB find exact max SMB PDU from sess structure BB */
pSMB->MaxDataCount = cpu_to_le16(1000);
pSMB->MaxSetupCount = 0;
pSMB->Reserved = 0;
pSMB->Flags = 0;
@ -4298,7 +4356,8 @@ QFSDeviceRetry:
params = 2; /* level */
pSMB->TotalDataCount = 0;
pSMB->MaxParameterCount = cpu_to_le16(2);
pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
/* BB find exact max SMB PDU from sess structure BB */
pSMB->MaxDataCount = cpu_to_le16(1000);
pSMB->MaxSetupCount = 0;
pSMB->Reserved = 0;
pSMB->Flags = 0;
@ -4369,7 +4428,8 @@ QFSUnixRetry:
pSMB->DataCount = 0;
pSMB->DataOffset = 0;
pSMB->MaxParameterCount = cpu_to_le16(2);
pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
/* BB find exact max SMB PDU from sess structure BB */
pSMB->MaxDataCount = cpu_to_le16(100);
pSMB->MaxSetupCount = 0;
pSMB->Reserved = 0;
pSMB->Flags = 0;
@ -4444,7 +4504,8 @@ SETFSUnixRetry:
offset = param_offset + params;
pSMB->MaxParameterCount = cpu_to_le16(4);
pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
/* BB find exact max SMB PDU from sess structure BB */
pSMB->MaxDataCount = cpu_to_le16(100);
pSMB->SetupCount = 1;
pSMB->Reserved3 = 0;
pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
@ -4512,7 +4573,8 @@ QFSPosixRetry:
pSMB->DataCount = 0;
pSMB->DataOffset = 0;
pSMB->MaxParameterCount = cpu_to_le16(2);
pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
/* BB find exact max SMB PDU from sess structure BB */
pSMB->MaxDataCount = cpu_to_le16(100);
pSMB->MaxSetupCount = 0;
pSMB->Reserved = 0;
pSMB->Flags = 0;
@ -4702,7 +4764,8 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
count = sizeof(struct file_end_of_file_info);
pSMB->MaxParameterCount = cpu_to_le16(2);
pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
/* BB find exact max SMB PDU from sess structure BB */
pSMB->MaxDataCount = cpu_to_le16(1000);
pSMB->SetupCount = 1;
pSMB->Reserved3 = 0;
pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
@ -4789,7 +4852,8 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
count = sizeof(FILE_BASIC_INFO);
pSMB->MaxParameterCount = cpu_to_le16(2);
pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
/* BB find max SMB PDU from sess */
pSMB->MaxDataCount = cpu_to_le16(1000);
pSMB->SetupCount = 1;
pSMB->Reserved3 = 0;
pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
@ -4856,7 +4920,8 @@ SetTimesRetry:
params = 6 + name_len;
count = sizeof(FILE_BASIC_INFO);
pSMB->MaxParameterCount = cpu_to_le16(2);
pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
/* BB find max SMB PDU from sess structure BB */
pSMB->MaxDataCount = cpu_to_le16(1000);
pSMB->MaxSetupCount = 0;
pSMB->Reserved = 0;
pSMB->Flags = 0;
@ -4986,7 +5051,8 @@ setPermsRetry:
params = 6 + name_len;
count = sizeof(FILE_UNIX_BASIC_INFO);
pSMB->MaxParameterCount = cpu_to_le16(2);
pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
/* BB find max SMB PDU from sess structure BB */
pSMB->MaxDataCount = cpu_to_le16(1000);
pSMB->MaxSetupCount = 0;
pSMB->Reserved = 0;
pSMB->Flags = 0;
@ -5169,7 +5235,8 @@ QAllEAsRetry:
params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
pSMB->TotalDataCount = 0;
pSMB->MaxParameterCount = cpu_to_le16(2);
pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
/* BB find exact max SMB PDU from sess structure BB */
pSMB->MaxDataCount = cpu_to_le16(4000);
pSMB->MaxSetupCount = 0;
pSMB->Reserved = 0;
pSMB->Flags = 0;
@ -5317,7 +5384,8 @@ QEARetry:
params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
pSMB->TotalDataCount = 0;
pSMB->MaxParameterCount = cpu_to_le16(2);
pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
/* BB find exact max SMB PDU from sess structure BB */
pSMB->MaxDataCount = cpu_to_le16(4000);
pSMB->MaxSetupCount = 0;
pSMB->Reserved = 0;
pSMB->Flags = 0;
@ -5475,7 +5543,8 @@ SetEARetry:
count = sizeof(*parm_data) + ea_value_len + name_len;
pSMB->MaxParameterCount = cpu_to_le16(2);
pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
/* BB find max SMB PDU from sess */
pSMB->MaxDataCount = cpu_to_le16(1000);
pSMB->MaxSetupCount = 0;
pSMB->Reserved = 0;
pSMB->Flags = 0;

Просмотреть файл

@ -75,6 +75,7 @@ struct smb_vol {
bool setuids:1;
bool override_uid:1;
bool override_gid:1;
bool dynperm:1;
bool noperm:1;
bool no_psx_acl:1; /* set if posix acl support should be disabled */
bool cifs_acl:1;
@ -86,8 +87,9 @@ struct smb_vol {
bool no_linux_ext:1;
bool sfu_emul:1;
bool nullauth:1; /* attempt to authenticate with null user */
unsigned nocase; /* request case insensitive filenames */
unsigned nobrl; /* disable sending byte range locks to srv */
bool nocase:1; /* request case insensitive filenames */
bool nobrl:1; /* disable sending byte range locks to srv */
bool seal:1; /* request transport encryption on share */
unsigned int rsize;
unsigned int wsize;
unsigned int sockopt;
@ -1246,6 +1248,10 @@ cifs_parse_mount_options(char *options, const char *devname,
vol->setuids = 1;
} else if (strnicmp(data, "nosetuids", 9) == 0) {
vol->setuids = 0;
} else if (strnicmp(data, "dynperm", 7) == 0) {
vol->dynperm = true;
} else if (strnicmp(data, "nodynperm", 9) == 0) {
vol->dynperm = false;
} else if (strnicmp(data, "nohard", 6) == 0) {
vol->retry = 0;
} else if (strnicmp(data, "nosoft", 6) == 0) {
@ -1268,8 +1274,12 @@ cifs_parse_mount_options(char *options, const char *devname,
vol->no_psx_acl = 1;
} else if (strnicmp(data, "sign", 4) == 0) {
vol->secFlg |= CIFSSEC_MUST_SIGN;
/* } else if (strnicmp(data, "seal",4) == 0) {
vol->secFlg |= CIFSSEC_MUST_SEAL; */
} else if (strnicmp(data, "seal", 4) == 0) {
/* we do not do the following in secFlags because seal
is a per tree connection (mount) not a per socket
or per-smb connection option in the protocol */
/* vol->secFlg |= CIFSSEC_MUST_SEAL; */
vol->seal = 1;
} else if (strnicmp(data, "direct", 6) == 0) {
vol->direct_io = 1;
} else if (strnicmp(data, "forcedirectio", 13) == 0) {
@ -1413,27 +1423,6 @@ find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
return NULL;
}
int
connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
const char *old_path, const struct nls_table *nls_codepage,
int remap)
{
struct dfs_info3_param *referrals = NULL;
unsigned int num_referrals;
int rc = 0;
rc = get_dfs_path(xid, pSesInfo, old_path, nls_codepage,
&num_referrals, &referrals, remap);
/* BB Add in code to: if valid refrl, if not ip address contact
the helper that resolves tcp names, mount to it, try to
tcon to it unmount it if fail */
kfree(referrals);
return rc;
}
int
get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
@ -1441,7 +1430,6 @@ get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
{
char *temp_unc;
int rc = 0;
unsigned char *targetUNCs;
*pnum_referrals = 0;
*preferrals = NULL;
@ -1464,7 +1452,7 @@ get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
kfree(temp_unc);
}
if (rc == 0)
rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, &targetUNCs,
rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
pnum_referrals, nls_codepage, remap);
/* BB map targetUNCs to dfs_info3 structures, here or
in CIFSGetDFSRefer BB */
@ -2125,6 +2113,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
if (volume_info.override_gid)
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
if (volume_info.dynperm)
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM;
if (volume_info.direct_io) {
cFYI(1, ("mounting share using direct i/o"));
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
@ -2141,6 +2131,9 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
for the retry flag is used */
tcon->retry = volume_info.retry;
tcon->nocase = volume_info.nocase;
if (tcon->seal != volume_info.seal)
cERROR(1, ("transport encryption setting "
"conflicts with existing tid"));
} else {
tcon = tconInfoAlloc();
if (tcon == NULL)
@ -2154,10 +2147,11 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
if ((strchr(volume_info.UNC + 3, '\\') == NULL)
&& (strchr(volume_info.UNC + 3, '/') ==
NULL)) {
rc = connect_to_dfs_path(xid, pSesInfo,
/* rc = connect_to_dfs_path(xid, pSesInfo,
"", cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
CIFS_MOUNT_MAP_SPECIAL_CHR);*/
cFYI(1, ("DFS root not supported"));
rc = -ENODEV;
goto out;
} else {
@ -2173,6 +2167,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
atomic_inc(&pSesInfo->inUse);
tcon->retry = volume_info.retry;
tcon->nocase = volume_info.nocase;
tcon->seal = volume_info.seal;
}
}
}
@ -2314,9 +2309,10 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
user = ses->userName;
domain = ses->domainName;
smb_buffer = cifs_buf_get();
if (smb_buffer == NULL) {
if (smb_buffer == NULL)
return -ENOMEM;
}
smb_buffer_response = smb_buffer;
pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;

Просмотреть файл

@ -49,18 +49,25 @@ build_path_from_dentry(struct dentry *direntry)
struct dentry *temp;
int namelen;
int pplen;
int dfsplen;
char *full_path;
char dirsep;
struct cifs_sb_info *cifs_sb;
if (direntry == NULL)
return NULL; /* not much we can do if dentry is freed and
we need to reopen the file after it was closed implicitly
when the server crashed */
dirsep = CIFS_DIR_SEP(CIFS_SB(direntry->d_sb));
pplen = CIFS_SB(direntry->d_sb)->prepathlen;
cifs_sb = CIFS_SB(direntry->d_sb);
dirsep = CIFS_DIR_SEP(cifs_sb);
pplen = cifs_sb->prepathlen;
if (cifs_sb->tcon && (cifs_sb->tcon->Flags & SMB_SHARE_IS_IN_DFS))
dfsplen = strnlen(cifs_sb->tcon->treeName, MAX_TREE_SIZE + 1);
else
dfsplen = 0;
cifs_bp_rename_retry:
namelen = pplen;
namelen = pplen + dfsplen;
for (temp = direntry; !IS_ROOT(temp);) {
namelen += (1 + temp->d_name.len);
temp = temp->d_parent;
@ -91,7 +98,7 @@ cifs_bp_rename_retry:
return NULL;
}
}
if (namelen != pplen) {
if (namelen != pplen + dfsplen) {
cERROR(1,
("did not end path lookup where expected namelen is %d",
namelen));
@ -107,7 +114,18 @@ cifs_bp_rename_retry:
since the '\' is a valid posix character so we can not switch
those safely to '/' if any are found in the middle of the prepath */
/* BB test paths to Windows with '/' in the midst of prepath */
strncpy(full_path, CIFS_SB(direntry->d_sb)->prepath, pplen);
if (dfsplen) {
strncpy(full_path, cifs_sb->tcon->treeName, dfsplen);
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
int i;
for (i = 0; i < dfsplen; i++) {
if (full_path[i] == '\\')
full_path[i] = '/';
}
}
}
strncpy(full_path + dfsplen, CIFS_SB(direntry->d_sb)->prepath, pplen);
return full_path;
}
@ -590,7 +608,7 @@ static int cifs_ci_compare(struct dentry *dentry, struct qstr *a,
* case take precedence. If a is not a negative dentry, this
* should have no side effects
*/
memcpy(a->name, b->name, a->len);
memcpy((void *)a->name, b->name, a->len);
return 0;
}
return 1;

Просмотреть файл

@ -134,10 +134,6 @@ dns_resolve_server_name_to_ip(const char *unc, char **ip_addr)
rkey = request_key(&key_type_dns_resolver, name, "");
if (!IS_ERR(rkey)) {
data = rkey->payload.data;
cFYI(1, ("%s: resolved: %s to %s", __func__,
rkey->description,
*ip_addr
));
} else {
cERROR(1, ("%s: unable to resolve: %s", __func__, name));
goto out;
@ -150,6 +146,11 @@ skip_upcall:
if (*ip_addr) {
memcpy(*ip_addr, data, len);
(*ip_addr)[len] = '\0';
if (!IS_ERR(rkey))
cFYI(1, ("%s: resolved: %s to %s", __func__,
name,
*ip_addr
));
rc = 0;
} else {
rc = -ENOMEM;

Просмотреть файл

@ -75,7 +75,11 @@ static inline int cifs_convert_flags(unsigned int flags)
return (GENERIC_READ | GENERIC_WRITE);
}
return 0x20197;
return (READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES |
FILE_WRITE_EA | FILE_APPEND_DATA | FILE_WRITE_DATA |
FILE_READ_DATA);
}
static inline int cifs_get_disposition(unsigned int flags)

Просмотреть файл

@ -161,74 +161,75 @@ static void cifs_unix_info_to_inode(struct inode *inode,
spin_unlock(&inode->i_lock);
}
static const unsigned char *cifs_get_search_path(struct cifs_sb_info *cifs_sb,
const char *search_path)
/*
* Needed to setup inode data for the directory which is the
* junction to the new submount (ie to setup the fake directory
* which represents a DFS referral)
*/
static void fill_fake_finddataunix(FILE_UNIX_BASIC_INFO *pfnd_dat,
struct super_block *sb)
{
int tree_len;
int path_len;
int i;
char *tmp_path;
struct cifsTconInfo *pTcon = cifs_sb->tcon;
struct inode *pinode = NULL;
if (!(pTcon->Flags & SMB_SHARE_IS_IN_DFS))
return search_path;
memset(pfnd_dat, sizeof(FILE_UNIX_BASIC_INFO), 0);
/* use full path name for working with DFS */
tree_len = strnlen(pTcon->treeName, MAX_TREE_SIZE + 1);
path_len = strnlen(search_path, MAX_PATHCONF);
/* __le64 pfnd_dat->EndOfFile = cpu_to_le64(0);
__le64 pfnd_dat->NumOfBytes = cpu_to_le64(0);
__u64 UniqueId = 0; */
pfnd_dat->LastStatusChange =
cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
pfnd_dat->LastAccessTime =
cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
pfnd_dat->LastModificationTime =
cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
pfnd_dat->Type = cpu_to_le32(UNIX_DIR);
pfnd_dat->Permissions = cpu_to_le64(S_IXUGO | S_IRWXU);
pfnd_dat->Nlinks = cpu_to_le64(2);
if (sb->s_root)
pinode = sb->s_root->d_inode;
if (pinode == NULL)
return;
tmp_path = kmalloc(tree_len+path_len+1, GFP_KERNEL);
if (tmp_path == NULL)
return search_path;
strncpy(tmp_path, pTcon->treeName, tree_len);
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
for (i = 0; i < tree_len; i++) {
if (tmp_path[i] == '\\')
tmp_path[i] = '/';
}
strncpy(tmp_path+tree_len, search_path, path_len);
tmp_path[tree_len+path_len] = 0;
return tmp_path;
/* fill in default values for the remaining based on root
inode since we can not query the server for this inode info */
pfnd_dat->DevMajor = cpu_to_le64(MAJOR(pinode->i_rdev));
pfnd_dat->DevMinor = cpu_to_le64(MINOR(pinode->i_rdev));
pfnd_dat->Uid = cpu_to_le64(pinode->i_uid);
pfnd_dat->Gid = cpu_to_le64(pinode->i_gid);
}
int cifs_get_inode_info_unix(struct inode **pinode,
const unsigned char *search_path, struct super_block *sb, int xid)
const unsigned char *full_path, struct super_block *sb, int xid)
{
int rc = 0;
FILE_UNIX_BASIC_INFO findData;
FILE_UNIX_BASIC_INFO find_data;
struct cifsTconInfo *pTcon;
struct inode *inode;
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
const unsigned char *full_path;
bool is_dfs_referral = false;
struct cifsInodeInfo *cifsInfo;
__u64 num_of_bytes;
__u64 end_of_file;
pTcon = cifs_sb->tcon;
cFYI(1, ("Getting info on %s", search_path));
cFYI(1, ("Getting info on %s", full_path));
full_path = cifs_get_search_path(cifs_sb, search_path);
try_again_CIFSSMBUnixQPathInfo:
/* could have done a find first instead but this returns more info */
rc = CIFSSMBUnixQPathInfo(xid, pTcon, full_path, &findData,
rc = CIFSSMBUnixQPathInfo(xid, pTcon, full_path, &find_data,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
/* dump_mem("\nUnixQPathInfo return data", &findData,
sizeof(findData)); */
if (rc) {
if (rc == -EREMOTE && !is_dfs_referral) {
is_dfs_referral = true;
if (full_path != search_path) {
kfree(full_path);
full_path = search_path;
cFYI(DBG2, ("DFS ref"));
/* for DFS, server does not give us real inode data */
fill_fake_finddataunix(&find_data, sb);
rc = 0;
}
goto try_again_CIFSSMBUnixQPathInfo;
}
goto cgiiu_exit;
} else {
struct cifsInodeInfo *cifsInfo;
__u64 num_of_bytes = le64_to_cpu(findData.NumOfBytes);
__u64 end_of_file = le64_to_cpu(findData.EndOfFile);
num_of_bytes = le64_to_cpu(find_data.NumOfBytes);
end_of_file = le64_to_cpu(find_data.EndOfFile);
/* get new inode */
if (*pinode == NULL) {
@ -238,12 +239,12 @@ try_again_CIFSSMBUnixQPathInfo:
goto cgiiu_exit;
}
/* Is an i_ino of zero legal? */
/* note ino incremented to unique num in new_inode */
/* Are there sanity checks we can use to ensure that
the server is really filling in that field? */
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
(*pinode)->i_ino =
(unsigned long)findData.UniqueId;
} /* note ino incremented to unique num in new_inode */
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
(*pinode)->i_ino = (unsigned long)find_data.UniqueId;
if (sb->s_flags & MS_NOATIME)
(*pinode)->i_flags |= S_NOATIME | S_NOCMTIME;
@ -259,8 +260,7 @@ try_again_CIFSSMBUnixQPathInfo:
/* this is ok to set on every inode revalidate */
atomic_set(&cifsInfo->inUse, 1);
cifs_unix_info_to_inode(inode, &findData, 0);
cifs_unix_info_to_inode(inode, &find_data, 0);
if (num_of_bytes < end_of_file)
cFYI(1, ("allocation size less than end of file"));
@ -269,10 +269,7 @@ try_again_CIFSSMBUnixQPathInfo:
(unsigned long long)inode->i_blocks));
cifs_set_ops(inode, is_dfs_referral);
}
cgiiu_exit:
if (full_path != search_path)
kfree(full_path);
return rc;
}
@ -379,21 +376,51 @@ static int get_sfu_mode(struct inode *inode,
#endif
}
/*
* Needed to setup inode data for the directory which is the
* junction to the new submount (ie to setup the fake directory
* which represents a DFS referral)
*/
static void fill_fake_finddata(FILE_ALL_INFO *pfnd_dat,
struct super_block *sb)
{
memset(pfnd_dat, sizeof(FILE_ALL_INFO), 0);
/* __le64 pfnd_dat->AllocationSize = cpu_to_le64(0);
__le64 pfnd_dat->EndOfFile = cpu_to_le64(0);
__u8 pfnd_dat->DeletePending = 0;
__u8 pfnd_data->Directory = 0;
__le32 pfnd_dat->EASize = 0;
__u64 pfnd_dat->IndexNumber = 0;
__u64 pfnd_dat->IndexNumber1 = 0; */
pfnd_dat->CreationTime =
cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
pfnd_dat->LastAccessTime =
cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
pfnd_dat->LastWriteTime =
cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
pfnd_dat->ChangeTime =
cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
pfnd_dat->Attributes = cpu_to_le32(ATTR_DIRECTORY);
pfnd_dat->NumberOfLinks = cpu_to_le32(2);
}
int cifs_get_inode_info(struct inode **pinode,
const unsigned char *search_path, FILE_ALL_INFO *pfindData,
const unsigned char *full_path, FILE_ALL_INFO *pfindData,
struct super_block *sb, int xid, const __u16 *pfid)
{
int rc = 0;
__u32 attr;
struct cifsInodeInfo *cifsInfo;
struct cifsTconInfo *pTcon;
struct inode *inode;
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
const unsigned char *full_path = NULL;
char *buf = NULL;
bool adjustTZ = false;
bool is_dfs_referral = false;
pTcon = cifs_sb->tcon;
cFYI(1, ("Getting info on %s", search_path));
cFYI(1, ("Getting info on %s", full_path));
if ((pfindData == NULL) && (*pinode != NULL)) {
if (CIFS_I(*pinode)->clientCanCacheRead) {
@ -409,9 +436,6 @@ int cifs_get_inode_info(struct inode **pinode,
return -ENOMEM;
pfindData = (FILE_ALL_INFO *)buf;
full_path = cifs_get_search_path(cifs_sb, search_path);
try_again_CIFSSMBQPathInfo:
/* could do find first instead but this returns more info */
rc = CIFSSMBQPathInfo(xid, pTcon, full_path, pfindData,
0 /* not legacy */,
@ -429,19 +453,14 @@ try_again_CIFSSMBQPathInfo:
}
}
/* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */
if (rc) {
if (rc == -EREMOTE && !is_dfs_referral) {
if (rc == -EREMOTE) {
is_dfs_referral = true;
if (full_path != search_path) {
kfree(full_path);
full_path = search_path;
}
goto try_again_CIFSSMBQPathInfo;
}
fill_fake_finddata(pfindData, sb);
rc = 0;
} else if (rc)
goto cgii_exit;
} else {
struct cifsInodeInfo *cifsInfo;
__u32 attr = le32_to_cpu(pfindData->Attributes);
attr = le32_to_cpu(pfindData->Attributes);
/* get new inode */
if (*pinode == NULL) {
@ -458,8 +477,7 @@ try_again_CIFSSMBQPathInfo:
/* We can not use the IndexNumber field by default from
Windows or Samba (in ALL_INFO buf) but we can request
it explicitly. It may not be unique presumably if
the server has multiple devices mounted under one
share */
the server has multiple devices mounted under one share */
/* There may be higher info levels that work but are
there Windows server or network appliances for which
@ -470,7 +488,7 @@ try_again_CIFSSMBQPathInfo:
__u64 inode_num;
rc1 = CIFSGetSrvInodeNumber(xid, pTcon,
search_path, &inode_num,
full_path, &inode_num,
cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
@ -506,7 +524,7 @@ try_again_CIFSSMBQPathInfo:
cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
inode->i_ctime =
cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
cFYI(0, ("Attributes came in as 0x%x", attr));
cFYI(DBG2, ("Attributes came in as 0x%x", attr));
if (adjustTZ && (pTcon->ses) && (pTcon->ses->server)) {
inode->i_ctime.tv_sec += pTcon->ses->server->timeAdj;
inode->i_mtime.tv_sec += pTcon->ses->server->timeAdj;
@ -537,27 +555,22 @@ try_again_CIFSSMBQPathInfo:
/* BB Finish for SFU style symlinks and devices */
} else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) &&
(cifsInfo->cifsAttrs & ATTR_SYSTEM)) {
if (decode_sfu_inode(inode,
le64_to_cpu(pfindData->EndOfFile),
search_path,
cifs_sb, xid))
if (decode_sfu_inode(inode, le64_to_cpu(pfindData->EndOfFile),
full_path, cifs_sb, xid))
cFYI(1, ("Unrecognized sfu inode type"));
cFYI(1, ("sfu mode 0%o", inode->i_mode));
} else {
inode->i_mode |= S_IFREG;
/* treat the dos attribute of read-only as read-only
mode e.g. 555 */
/* treat dos attribute of read-only as read-only mode eg 555 */
if (cifsInfo->cifsAttrs & ATTR_READONLY)
inode->i_mode &= ~(S_IWUGO);
else if ((inode->i_mode & S_IWUGO) == 0)
/* the ATTR_READONLY flag may have been */
/* changed on server -- set any w bits */
/* allowed by mnt_file_mode */
inode->i_mode |= (S_IWUGO &
cifs_sb->mnt_file_mode);
/* BB add code here -
validate if device or weird share or device type? */
inode->i_mode |= (S_IWUGO & cifs_sb->mnt_file_mode);
/* BB add code to validate if device or weird share or device type? */
}
spin_lock(&inode->i_lock);
@ -582,12 +595,12 @@ try_again_CIFSSMBQPathInfo:
/* fill in 0777 bits from ACL */
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
cFYI(1, ("Getting mode bits from ACL"));
acl_to_uid_mode(inode, search_path, pfid);
acl_to_uid_mode(inode, full_path, pfid);
}
#endif
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
/* fill in remaining high mode bits e.g. SUID, VTX */
get_sfu_mode(inode, search_path, cifs_sb, xid);
get_sfu_mode(inode, full_path, cifs_sb, xid);
} else if (atomic_read(&cifsInfo->inUse) == 0) {
inode->i_uid = cifs_sb->mnt_uid;
inode->i_gid = cifs_sb->mnt_gid;
@ -597,10 +610,11 @@ try_again_CIFSSMBQPathInfo:
}
cifs_set_ops(inode, is_dfs_referral);
}
cgii_exit:
if (full_path != search_path)
kfree(full_path);
kfree(buf);
return rc;
}
@ -1502,8 +1516,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
int oplock = 0;
rc = SMBLegacyOpen(xid, pTcon, full_path,
FILE_OPEN,
SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
FILE_OPEN, GENERIC_WRITE,
CREATE_NOT_DIR, &netfid, &oplock,
NULL, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &

Просмотреть файл

@ -30,9 +30,9 @@
#define CIFS_IOC_CHECKUMOUNT _IO(0xCF, 2)
int cifs_ioctl(struct inode *inode, struct file *filep,
unsigned int command, unsigned long arg)
long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
{
struct inode *inode = filep->f_dentry->d_inode;
int rc = -ENOTTY; /* strange error - but the precedent */
int xid;
struct cifs_sb_info *cifs_sb;

Просмотреть файл

@ -234,7 +234,6 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon;
char *full_path = NULL;
char *tmp_path = NULL;
char *tmpbuffer;
int len;
__u16 fid;
@ -295,45 +294,9 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
cFYI(1, ("Error closing junction point "
"(open for ioctl)"));
}
/* BB unwind this long, nested function, or remove BB */
if (rc == -EIO) {
/* Query if DFS Junction */
unsigned int num_referrals = 0;
struct dfs_info3_param *refs = NULL;
tmp_path =
kmalloc(MAX_TREE_SIZE + MAX_PATHCONF + 1,
GFP_KERNEL);
if (tmp_path) {
strncpy(tmp_path, pTcon->treeName,
MAX_TREE_SIZE);
strncat(tmp_path, full_path,
MAX_PATHCONF);
rc = get_dfs_path(xid, pTcon->ses,
tmp_path,
cifs_sb->local_nls,
&num_referrals, &refs,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
cFYI(1, ("Get DFS for %s rc = %d ",
tmp_path, rc));
if ((num_referrals == 0) && (rc == 0))
rc = -EACCES;
else {
cFYI(1, ("num referral: %d",
num_referrals));
if (refs && refs->path_name) {
strncpy(tmpbuffer,
refs->path_name,
len-1);
}
}
kfree(refs);
kfree(tmp_path);
}
/* BB add code like else decode referrals
then memcpy to tmpbuffer and free referrals
string array BB */
}
/* If it is a DFS junction earlier we would have gotten
PATH_NOT_COVERED returned from server so we do
not need to request the DFS info here */
}
}
/* BB Anything else to do to handle recursive links? */

Просмотреть файл

@ -141,11 +141,11 @@ cifs_inet_pton(const int address_family, const char *cp, void *dst)
int ret = 0;
/* calculate length by finding first slash or NULL */
if (address_family == AF_INET) {
if (address_family == AF_INET)
ret = in4_pton(cp, -1 /* len */, dst, '\\', NULL);
} else if (address_family == AF_INET6) {
else if (address_family == AF_INET6)
ret = in6_pton(cp, -1 /* len */, dst , '\\', NULL);
}
cFYI(DBG2, ("address conversion returned %d for %s", ret, cp));
if (ret > 0)
ret = 1;

Просмотреть файл

@ -64,7 +64,7 @@ typedef struct _SECURITY_BUFFER {
} __attribute__((packed)) SECURITY_BUFFER;
typedef struct _NEGOTIATE_MESSAGE {
__u8 Signature[sizeof (NTLMSSP_SIGNATURE)];
__u8 Signature[sizeof(NTLMSSP_SIGNATURE)];
__le32 MessageType; /* 1 */
__le32 NegotiateFlags;
SECURITY_BUFFER DomainName; /* RFC 1001 style and ASCII */
@ -74,7 +74,7 @@ typedef struct _NEGOTIATE_MESSAGE {
} __attribute__((packed)) NEGOTIATE_MESSAGE, *PNEGOTIATE_MESSAGE;
typedef struct _CHALLENGE_MESSAGE {
__u8 Signature[sizeof (NTLMSSP_SIGNATURE)];
__u8 Signature[sizeof(NTLMSSP_SIGNATURE)];
__le32 MessageType; /* 2 */
SECURITY_BUFFER TargetName;
__le32 NegotiateFlags;

Просмотреть файл

@ -670,8 +670,11 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
(index_to_find < first_entry_in_buffer)) {
/* close and restart search */
cFYI(1, ("search backing up - close and restart search"));
if (!cifsFile->srch_inf.endOfSearch &&
!cifsFile->invalidHandle) {
cifsFile->invalidHandle = true;
CIFSFindClose(xid, pTcon, cifsFile->netfid);
}
kfree(cifsFile->search_resume_name);
cifsFile->search_resume_name = NULL;
if (cifsFile->srch_inf.ntwrk_buf_start) {