Commit 9272f2dc authored by Linus Torvalds's avatar Linus Torvalds

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

Pull cifs/smb3 updates from Steve French:
 "Improved SMB3 support (symlink and device emulation, and remapping by
  default the 7 reserved posix characters) and a workaround for cifs
  mounts to Mac (working around a commonly encountered Mac server bug)"

* 'for-linus' of git://git.samba.org/sfrench/cifs-2.6:
  [CIFS] Remove obsolete comment
  Check minimum response length on query_network_interface
  Workaround Mac server problem
  Remap reserved posix characters by default (part 3/3)
  Allow conversion of characters in Mac remap range (part 2)
  Allow conversion of characters in Mac remap range. Part 1
  mfsymlinks support for SMB2.1/SMB3. Part 2 query symlink
  Add mfsymlinks support for SMB2.1/SMB3. Part 1 create symlink
  Allow mknod and mkfifo on SMB2/SMB3 mounts
  add defines for two new file attributes
parents e83e4323 ff273cb8
...@@ -45,6 +45,7 @@ ...@@ -45,6 +45,7 @@
#define CIFS_MOUNT_POSIXACL 0x100000 /* mirror of MS_POSIXACL in mnt_cifs_flags */ #define CIFS_MOUNT_POSIXACL 0x100000 /* mirror of MS_POSIXACL in mnt_cifs_flags */
#define CIFS_MOUNT_CIFS_BACKUPUID 0x200000 /* backup intent bit for a user */ #define CIFS_MOUNT_CIFS_BACKUPUID 0x200000 /* backup intent bit for a user */
#define CIFS_MOUNT_CIFS_BACKUPGID 0x400000 /* backup intent bit for a group */ #define CIFS_MOUNT_CIFS_BACKUPGID 0x400000 /* backup intent bit for a group */
#define CIFS_MOUNT_MAP_SFM_CHR 0x800000 /* SFM/MAC mapping for illegal chars */
struct cifs_sb_info { struct cifs_sb_info {
struct rb_root tlink_tree; struct rb_root tlink_tree;
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
*/ */
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/slab.h> #include <linux/slab.h>
#include "cifs_fs_sb.h"
#include "cifs_unicode.h" #include "cifs_unicode.h"
#include "cifs_uniupr.h" #include "cifs_uniupr.h"
#include "cifspdu.h" #include "cifspdu.h"
...@@ -61,26 +62,24 @@ cifs_utf16_bytes(const __le16 *from, int maxbytes, ...@@ -61,26 +62,24 @@ cifs_utf16_bytes(const __le16 *from, int maxbytes,
return outlen; return outlen;
} }
/* int cifs_remap(struct cifs_sb_info *cifs_sb)
* cifs_mapchar - convert a host-endian char to proper char in codepage
* @target - where converted character should be copied
* @src_char - 2 byte host-endian source character
* @cp - codepage to which character should be converted
* @mapchar - should character be mapped according to mapchars mount option?
*
* This function handles the conversion of a single character. It is the
* responsibility of the caller to ensure that the target buffer is large
* enough to hold the result of the conversion (at least NLS_MAX_CHARSET_SIZE).
*/
static int
cifs_mapchar(char *target, const __u16 src_char, const struct nls_table *cp,
bool mapchar)
{ {
int len = 1; int map_type;
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SFM_CHR)
map_type = SFM_MAP_UNI_RSVD;
else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR)
map_type = SFU_MAP_UNI_RSVD;
else
map_type = NO_MAP_UNI_RSVD;
if (!mapchar) return map_type;
goto cp_convert; }
/* Convert character using the SFU - "Services for Unix" remapping range */
static bool
convert_sfu_char(const __u16 src_char, char *target)
{
/* /*
* BB: Cannot handle remapping UNI_SLASH until all the calls to * BB: Cannot handle remapping UNI_SLASH until all the calls to
* build_path_from_dentry are modified, as they use slash as * build_path_from_dentry are modified, as they use slash as
...@@ -106,19 +105,74 @@ cifs_mapchar(char *target, const __u16 src_char, const struct nls_table *cp, ...@@ -106,19 +105,74 @@ cifs_mapchar(char *target, const __u16 src_char, const struct nls_table *cp,
*target = '<'; *target = '<';
break; break;
default: default:
goto cp_convert; return false;
}
return true;
}
/* Convert character using the SFM - "Services for Mac" remapping range */
static bool
convert_sfm_char(const __u16 src_char, char *target)
{
switch (src_char) {
case SFM_COLON:
*target = ':';
break;
case SFM_ASTERISK:
*target = '*';
break;
case SFM_QUESTION:
*target = '?';
break;
case SFM_PIPE:
*target = '|';
break;
case SFM_GRTRTHAN:
*target = '>';
break;
case SFM_LESSTHAN:
*target = '<';
break;
case SFM_SLASH:
*target = '\\';
break;
default:
return false;
} }
return true;
}
/*
* cifs_mapchar - convert a host-endian char to proper char in codepage
* @target - where converted character should be copied
* @src_char - 2 byte host-endian source character
* @cp - codepage to which character should be converted
* @map_type - How should the 7 NTFS/SMB reserved characters be mapped to UCS2?
*
* This function handles the conversion of a single character. It is the
* responsibility of the caller to ensure that the target buffer is large
* enough to hold the result of the conversion (at least NLS_MAX_CHARSET_SIZE).
*/
static int
cifs_mapchar(char *target, const __u16 src_char, const struct nls_table *cp,
int maptype)
{
int len = 1;
out: if ((maptype == SFM_MAP_UNI_RSVD) && convert_sfm_char(src_char, target))
return len;
else if ((maptype == SFU_MAP_UNI_RSVD) &&
convert_sfu_char(src_char, target))
return len; return len;
cp_convert: /* if character not one of seven in special remap set */
len = cp->uni2char(src_char, target, NLS_MAX_CHARSET_SIZE); len = cp->uni2char(src_char, target, NLS_MAX_CHARSET_SIZE);
if (len <= 0) { if (len <= 0) {
*target = '?'; *target = '?';
len = 1; len = 1;
} }
goto out; return len;
} }
/* /*
...@@ -145,7 +199,7 @@ cifs_mapchar(char *target, const __u16 src_char, const struct nls_table *cp, ...@@ -145,7 +199,7 @@ cifs_mapchar(char *target, const __u16 src_char, const struct nls_table *cp,
*/ */
int int
cifs_from_utf16(char *to, const __le16 *from, int tolen, int fromlen, cifs_from_utf16(char *to, const __le16 *from, int tolen, int fromlen,
const struct nls_table *codepage, bool mapchar) const struct nls_table *codepage, int map_type)
{ {
int i, charlen, safelen; int i, charlen, safelen;
int outlen = 0; int outlen = 0;
...@@ -172,13 +226,13 @@ cifs_from_utf16(char *to, const __le16 *from, int tolen, int fromlen, ...@@ -172,13 +226,13 @@ cifs_from_utf16(char *to, const __le16 *from, int tolen, int fromlen,
* conversion bleed into the null terminator * conversion bleed into the null terminator
*/ */
if (outlen >= safelen) { if (outlen >= safelen) {
charlen = cifs_mapchar(tmp, ftmp, codepage, mapchar); charlen = cifs_mapchar(tmp, ftmp, codepage, map_type);
if ((outlen + charlen) > (tolen - nullsize)) if ((outlen + charlen) > (tolen - nullsize))
break; break;
} }
/* put converted char into 'to' buffer */ /* put converted char into 'to' buffer */
charlen = cifs_mapchar(&to[outlen], ftmp, codepage, mapchar); charlen = cifs_mapchar(&to[outlen], ftmp, codepage, map_type);
outlen += charlen; outlen += charlen;
} }
...@@ -267,7 +321,7 @@ cifs_strndup_from_utf16(const char *src, const int maxlen, ...@@ -267,7 +321,7 @@ cifs_strndup_from_utf16(const char *src, const int maxlen,
if (!dst) if (!dst)
return NULL; return NULL;
cifs_from_utf16(dst, (__le16 *) src, len, maxlen, codepage, cifs_from_utf16(dst, (__le16 *) src, len, maxlen, codepage,
false); NO_MAP_UNI_RSVD);
} else { } else {
len = strnlen(src, maxlen); len = strnlen(src, maxlen);
len++; len++;
...@@ -280,6 +334,66 @@ cifs_strndup_from_utf16(const char *src, const int maxlen, ...@@ -280,6 +334,66 @@ cifs_strndup_from_utf16(const char *src, const int maxlen,
return dst; return dst;
} }
static __le16 convert_to_sfu_char(char src_char)
{
__le16 dest_char;
switch (src_char) {
case ':':
dest_char = cpu_to_le16(UNI_COLON);
break;
case '*':
dest_char = cpu_to_le16(UNI_ASTERISK);
break;
case '?':
dest_char = cpu_to_le16(UNI_QUESTION);
break;
case '<':
dest_char = cpu_to_le16(UNI_LESSTHAN);
break;
case '>':
dest_char = cpu_to_le16(UNI_GRTRTHAN);
break;
case '|':
dest_char = cpu_to_le16(UNI_PIPE);
break;
default:
dest_char = 0;
}
return dest_char;
}
static __le16 convert_to_sfm_char(char src_char)
{
__le16 dest_char;
switch (src_char) {
case ':':
dest_char = cpu_to_le16(SFM_COLON);
break;
case '*':
dest_char = cpu_to_le16(SFM_ASTERISK);
break;
case '?':
dest_char = cpu_to_le16(SFM_QUESTION);
break;
case '<':
dest_char = cpu_to_le16(SFM_LESSTHAN);
break;
case '>':
dest_char = cpu_to_le16(SFM_GRTRTHAN);
break;
case '|':
dest_char = cpu_to_le16(SFM_PIPE);
break;
default:
dest_char = 0;
}
return dest_char;
}
/* /*
* Convert 16 bit Unicode pathname to wire format from string in current code * Convert 16 bit Unicode pathname to wire format from string in current code
* page. Conversion may involve remapping up the six characters that are * page. Conversion may involve remapping up the six characters that are
...@@ -288,7 +402,7 @@ cifs_strndup_from_utf16(const char *src, const int maxlen, ...@@ -288,7 +402,7 @@ cifs_strndup_from_utf16(const char *src, const int maxlen,
*/ */
int int
cifsConvertToUTF16(__le16 *target, const char *source, int srclen, cifsConvertToUTF16(__le16 *target, const char *source, int srclen,
const struct nls_table *cp, int mapChars) const struct nls_table *cp, int map_chars)
{ {
int i, charlen; int i, charlen;
int j = 0; int j = 0;
...@@ -296,39 +410,30 @@ cifsConvertToUTF16(__le16 *target, const char *source, int srclen, ...@@ -296,39 +410,30 @@ cifsConvertToUTF16(__le16 *target, const char *source, int srclen,
__le16 dst_char; __le16 dst_char;
wchar_t tmp; wchar_t tmp;
if (!mapChars) if (map_chars == NO_MAP_UNI_RSVD)
return cifs_strtoUTF16(target, source, PATH_MAX, cp); return cifs_strtoUTF16(target, source, PATH_MAX, cp);
for (i = 0; i < srclen; j++) { for (i = 0; i < srclen; j++) {
src_char = source[i]; src_char = source[i];
charlen = 1; charlen = 1;
switch (src_char) {
case 0: /* check if end of string */
if (src_char == 0)
goto ctoUTF16_out; goto ctoUTF16_out;
case ':':
dst_char = cpu_to_le16(UNI_COLON); /* see if we must remap this char */
break; if (map_chars == SFU_MAP_UNI_RSVD)
case '*': dst_char = convert_to_sfu_char(src_char);
dst_char = cpu_to_le16(UNI_ASTERISK); else if (map_chars == SFM_MAP_UNI_RSVD)
break; dst_char = convert_to_sfm_char(src_char);
case '?': else
dst_char = cpu_to_le16(UNI_QUESTION); dst_char = 0;
break;
case '<':
dst_char = cpu_to_le16(UNI_LESSTHAN);
break;
case '>':
dst_char = cpu_to_le16(UNI_GRTRTHAN);
break;
case '|':
dst_char = cpu_to_le16(UNI_PIPE);
break;
/* /*
* FIXME: We can not handle remapping backslash (UNI_SLASH) * FIXME: We can not handle remapping backslash (UNI_SLASH)
* until all the calls to build_path_from_dentry are modified, * until all the calls to build_path_from_dentry are modified,
* as they use backslash as separator. * as they use backslash as separator.
*/ */
default: if (dst_char == 0) {
charlen = cp->char2uni(source + i, srclen - i, &tmp); charlen = cp->char2uni(source + i, srclen - i, &tmp);
dst_char = cpu_to_le16(tmp); dst_char = cpu_to_le16(tmp);
......
...@@ -52,6 +52,34 @@ ...@@ -52,6 +52,34 @@
#define UNI_PIPE (__u16) ('|' + 0xF000) #define UNI_PIPE (__u16) ('|' + 0xF000)
#define UNI_SLASH (__u16) ('\\' + 0xF000) #define UNI_SLASH (__u16) ('\\' + 0xF000)
/*
* Macs use an older "SFM" mapping of the symbols above. Fortunately it does
* not conflict (although almost does) with the mapping above.
*/
#define SFM_ASTERISK ((__u16) 0xF021)
#define SFM_QUESTION ((__u16) 0xF025)
#define SFM_COLON ((__u16) 0xF022)
#define SFM_GRTRTHAN ((__u16) 0xF024)
#define SFM_LESSTHAN ((__u16) 0xF023)
#define SFM_PIPE ((__u16) 0xF027)
#define SFM_SLASH ((__u16) 0xF026)
/*
* Mapping mechanism to use when one of the seven reserved characters is
* encountered. We can only map using one of the mechanisms at a time
* since otherwise readdir could return directory entries which we would
* not be able to open
*
* NO_MAP_UNI_RSVD = do not perform any remapping of the character
* SFM_MAP_UNI_RSVD = map reserved characters using SFM scheme (MAC compatible)
* SFU_MAP_UNI_RSVD = map reserved characters ala SFU ("mapchars" option)
*
*/
#define NO_MAP_UNI_RSVD 0
#define SFM_MAP_UNI_RSVD 1
#define SFU_MAP_UNI_RSVD 2
/* Just define what we want from uniupr.h. We don't want to define the tables /* Just define what we want from uniupr.h. We don't want to define the tables
* in each source file. * in each source file.
*/ */
...@@ -75,7 +103,7 @@ extern const struct UniCaseRange CifsUniLowerRange[]; ...@@ -75,7 +103,7 @@ extern const struct UniCaseRange CifsUniLowerRange[];
#ifdef __KERNEL__ #ifdef __KERNEL__
int cifs_from_utf16(char *to, const __le16 *from, int tolen, int fromlen, int cifs_from_utf16(char *to, const __le16 *from, int tolen, int fromlen,
const struct nls_table *codepage, bool mapchar); const struct nls_table *cp, int map_type);
int cifs_utf16_bytes(const __le16 *from, int maxbytes, int cifs_utf16_bytes(const __le16 *from, int maxbytes,
const struct nls_table *codepage); const struct nls_table *codepage);
int cifs_strtoUTF16(__le16 *, const char *, int, const struct nls_table *); int cifs_strtoUTF16(__le16 *, const char *, int, const struct nls_table *);
...@@ -84,6 +112,7 @@ char *cifs_strndup_from_utf16(const char *src, const int maxlen, ...@@ -84,6 +112,7 @@ char *cifs_strndup_from_utf16(const char *src, const int maxlen,
const struct nls_table *codepage); const struct nls_table *codepage);
extern int cifsConvertToUTF16(__le16 *target, const char *source, int maxlen, extern int cifsConvertToUTF16(__le16 *target, const char *source, int maxlen,
const struct nls_table *cp, int mapChars); const struct nls_table *cp, int mapChars);
extern int cifs_remap(struct cifs_sb_info *cifs_sb);
#ifdef CONFIG_CIFS_SMB2 #ifdef CONFIG_CIFS_SMB2
extern __le16 *cifs_strndup_to_utf16(const char *src, const int maxlen, extern __le16 *cifs_strndup_to_utf16(const char *src, const int maxlen,
int *utf16_len, const struct nls_table *cp, int *utf16_len, const struct nls_table *cp,
......
...@@ -431,7 +431,7 @@ find_domain_name(struct cifs_ses *ses, const struct nls_table *nls_cp) ...@@ -431,7 +431,7 @@ find_domain_name(struct cifs_ses *ses, const struct nls_table *nls_cp)
return -ENOMEM; return -ENOMEM;
cifs_from_utf16(ses->domainName, cifs_from_utf16(ses->domainName,
(__le16 *)blobptr, attrsize, attrsize, (__le16 *)blobptr, attrsize, attrsize,
nls_cp, false); nls_cp, NO_MAP_UNI_RSVD);
break; break;
} }
} }
......
...@@ -323,11 +323,11 @@ struct smb_version_operations { ...@@ -323,11 +323,11 @@ struct smb_version_operations {
int (*async_writev)(struct cifs_writedata *, int (*async_writev)(struct cifs_writedata *,
void (*release)(struct kref *)); void (*release)(struct kref *));
/* sync read from the server */ /* sync read from the server */
int (*sync_read)(const unsigned int, struct cifsFileInfo *, int (*sync_read)(const unsigned int, struct cifs_fid *,
struct cifs_io_parms *, unsigned int *, char **, struct cifs_io_parms *, unsigned int *, char **,
int *); int *);
/* sync write to the server */ /* sync write to the server */
int (*sync_write)(const unsigned int, struct cifsFileInfo *, int (*sync_write)(const unsigned int, struct cifs_fid *,
struct cifs_io_parms *, unsigned int *, struct kvec *, struct cifs_io_parms *, unsigned int *, struct kvec *,
unsigned long); unsigned long);
/* open dir, start readdir */ /* open dir, start readdir */
...@@ -466,6 +466,7 @@ struct smb_vol { ...@@ -466,6 +466,7 @@ struct smb_vol {
bool direct_io:1; bool direct_io:1;
bool strict_io:1; /* strict cache behavior */ bool strict_io:1; /* strict cache behavior */
bool remap:1; /* set to remap seven reserved chars in filenames */ bool remap:1; /* set to remap seven reserved chars in filenames */
bool sfu_remap:1; /* remap seven reserved chars ala SFU */
bool posix_paths:1; /* unset to not ask for posix pathnames. */ bool posix_paths:1; /* unset to not ask for posix pathnames. */
bool no_linux_ext:1; bool no_linux_ext:1;
bool sfu_emul:1; bool sfu_emul:1;
...@@ -499,6 +500,7 @@ struct smb_vol { ...@@ -499,6 +500,7 @@ struct smb_vol {
#define CIFS_MOUNT_MASK (CIFS_MOUNT_NO_PERM | CIFS_MOUNT_SET_UID | \ #define CIFS_MOUNT_MASK (CIFS_MOUNT_NO_PERM | CIFS_MOUNT_SET_UID | \
CIFS_MOUNT_SERVER_INUM | CIFS_MOUNT_DIRECT_IO | \ CIFS_MOUNT_SERVER_INUM | CIFS_MOUNT_DIRECT_IO | \
CIFS_MOUNT_NO_XATTR | CIFS_MOUNT_MAP_SPECIAL_CHR | \ CIFS_MOUNT_NO_XATTR | CIFS_MOUNT_MAP_SPECIAL_CHR | \
CIFS_MOUNT_MAP_SFM_CHR | \
CIFS_MOUNT_UNX_EMUL | CIFS_MOUNT_NO_BRL | \ CIFS_MOUNT_UNX_EMUL | CIFS_MOUNT_NO_BRL | \
CIFS_MOUNT_CIFS_ACL | CIFS_MOUNT_OVERR_UID | \ CIFS_MOUNT_CIFS_ACL | CIFS_MOUNT_OVERR_UID | \
CIFS_MOUNT_OVERR_GID | CIFS_MOUNT_DYNPERM | \ CIFS_MOUNT_OVERR_GID | CIFS_MOUNT_DYNPERM | \
......
...@@ -867,7 +867,7 @@ CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name, ...@@ -867,7 +867,7 @@ CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
int rc = 0; int rc = 0;
int bytes_returned; int bytes_returned;
int name_len; int name_len;
int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR; int remap = cifs_remap(cifs_sb);
DelFileRetry: DelFileRetry:
rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB, rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
...@@ -913,7 +913,7 @@ CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name, ...@@ -913,7 +913,7 @@ CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
int rc = 0; int rc = 0;
int bytes_returned; int bytes_returned;
int name_len; int name_len;
int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR; int remap = cifs_remap(cifs_sb);
cifs_dbg(FYI, "In CIFSSMBRmDir\n"); cifs_dbg(FYI, "In CIFSSMBRmDir\n");
RmDirRetry: RmDirRetry:
...@@ -958,7 +958,7 @@ CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name, ...@@ -958,7 +958,7 @@ CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
CREATE_DIRECTORY_RSP *pSMBr = NULL; CREATE_DIRECTORY_RSP *pSMBr = NULL;
int bytes_returned; int bytes_returned;
int name_len; int name_len;
int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR; int remap = cifs_remap(cifs_sb);
cifs_dbg(FYI, "In CIFSSMBMkDir\n"); cifs_dbg(FYI, "In CIFSSMBMkDir\n");
MkDirRetry: MkDirRetry:
...@@ -1280,7 +1280,7 @@ CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock, ...@@ -1280,7 +1280,7 @@ CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock,
__u16 count; __u16 count;
struct cifs_sb_info *cifs_sb = oparms->cifs_sb; struct cifs_sb_info *cifs_sb = oparms->cifs_sb;
struct cifs_tcon *tcon = oparms->tcon; struct cifs_tcon *tcon = oparms->tcon;
int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR; int remap = cifs_remap(cifs_sb);
const struct nls_table *nls = cifs_sb->local_nls; const struct nls_table *nls = cifs_sb->local_nls;
int create_options = oparms->create_options; int create_options = oparms->create_options;
int desired_access = oparms->desired_access; int desired_access = oparms->desired_access;
...@@ -2572,7 +2572,7 @@ CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -2572,7 +2572,7 @@ CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
int bytes_returned; int bytes_returned;
int name_len, name_len2; int name_len, name_len2;
__u16 count; __u16 count;
int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR; int remap = cifs_remap(cifs_sb);
cifs_dbg(FYI, "In CIFSSMBRename\n"); cifs_dbg(FYI, "In CIFSSMBRename\n");
renameRetry: renameRetry:
...@@ -2968,7 +2968,7 @@ CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -2968,7 +2968,7 @@ CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
int bytes_returned; int bytes_returned;
int name_len, name_len2; int name_len, name_len2;
__u16 count; __u16 count;
int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR; int remap = cifs_remap(cifs_sb);
cifs_dbg(FYI, "In CIFSCreateHardLink\n"); cifs_dbg(FYI, "In CIFSCreateHardLink\n");
winCreateHardLinkRetry: winCreateHardLinkRetry:
...@@ -4367,7 +4367,7 @@ CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -4367,7 +4367,7 @@ CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
return rc; return rc;
nls_codepage = cifs_sb->local_nls; nls_codepage = cifs_sb->local_nls;
remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR; remap = cifs_remap(cifs_sb);
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len = name_len =
...@@ -5527,7 +5527,7 @@ CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -5527,7 +5527,7 @@ CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
int name_len; int name_len;
int rc = 0; int rc = 0;
int bytes_returned = 0; int bytes_returned = 0;
int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR; int remap = cifs_remap(cifs_sb);
__u16 params, byte_count, data_count, param_offset, offset; __u16 params, byte_count, data_count, param_offset, offset;
......
...@@ -70,6 +70,7 @@ enum { ...@@ -70,6 +70,7 @@ enum {
Opt_forcegid, Opt_noforcegid, Opt_forcegid, Opt_noforcegid,
Opt_noblocksend, Opt_noautotune, Opt_noblocksend, Opt_noautotune,
Opt_hard, Opt_soft, Opt_perm, Opt_noperm, Opt_hard, Opt_soft, Opt_perm, Opt_noperm,
Opt_mapposix, Opt_nomapposix,
Opt_mapchars, Opt_nomapchars, Opt_sfu, Opt_mapchars, Opt_nomapchars, Opt_sfu,
Opt_nosfu, Opt_nodfs, Opt_posixpaths, Opt_nosfu, Opt_nodfs, Opt_posixpaths,
Opt_noposixpaths, Opt_nounix, Opt_noposixpaths, Opt_nounix,
...@@ -124,8 +125,10 @@ static const match_table_t cifs_mount_option_tokens = { ...@@ -124,8 +125,10 @@ static const match_table_t cifs_mount_option_tokens = {
{ Opt_soft, "soft" }, { Opt_soft, "soft" },
{ Opt_perm, "perm" }, { Opt_perm, "perm" },
{ Opt_noperm, "noperm" }, { Opt_noperm, "noperm" },
{ Opt_mapchars, "mapchars" }, { Opt_mapchars, "mapchars" }, /* SFU style */
{ Opt_nomapchars, "nomapchars" }, { Opt_nomapchars, "nomapchars" },
{ Opt_mapposix, "mapposix" }, /* SFM style */
{ Opt_nomapposix, "nomapposix" },
{ Opt_sfu, "sfu" }, { Opt_sfu, "sfu" },
{ Opt_nosfu, "nosfu" }, { Opt_nosfu, "nosfu" },
{ Opt_nodfs, "nodfs" }, { Opt_nodfs, "nodfs" },
...@@ -1231,6 +1234,14 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, ...@@ -1231,6 +1234,14 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
vol->linux_uid = current_uid(); vol->linux_uid = current_uid();
vol->linux_gid = current_gid(); vol->linux_gid = current_gid();
/*
* default to SFM style remapping of seven reserved characters
* unless user overrides it or we negotiate CIFS POSIX where
* it is unnecessary. Can not simultaneously use more than one mapping
* since then readdir could list files that open could not open
*/
vol->remap = true;
/* default to only allowing write access to owner of the mount */ /* default to only allowing write access to owner of the mount */
vol->dir_mode = vol->file_mode = S_IRUGO | S_IXUGO | S_IWUSR; vol->dir_mode = vol->file_mode = S_IRUGO | S_IXUGO | S_IWUSR;
...@@ -1338,10 +1349,18 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, ...@@ -1338,10 +1349,18 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
vol->noperm = 1; vol->noperm = 1;
break; break;
case Opt_mapchars: case Opt_mapchars:
vol->remap = 1; vol->sfu_remap = true;
vol->remap = false; /* disable SFM mapping */
break; break;
case Opt_nomapchars: case Opt_nomapchars:
vol->remap = 0; vol->sfu_remap = false;
break;
case Opt_mapposix:
vol->remap = true;
vol->sfu_remap = false; /* disable SFU mapping */
break;
case Opt_nomapposix:
vol->remap = false;
break; break;
case Opt_sfu: case Opt_sfu:
vol->sfu_emul = 1; vol->sfu_emul = 1;
...@@ -3197,6 +3216,8 @@ void cifs_setup_cifs_sb(struct smb_vol *pvolume_info, ...@@ -3197,6 +3216,8 @@ void cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
if (pvolume_info->server_ino) if (pvolume_info->server_ino)
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM; cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
if (pvolume_info->remap) if (pvolume_info->remap)
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SFM_CHR;
if (pvolume_info->sfu_remap)
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR; cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
if (pvolume_info->no_xattr) if (pvolume_info->no_xattr)
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR; cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
...@@ -3239,10 +3260,20 @@ void cifs_setup_cifs_sb(struct smb_vol *pvolume_info, ...@@ -3239,10 +3260,20 @@ void cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
} }
if (pvolume_info->mfsymlinks) { if (pvolume_info->mfsymlinks) {
if (pvolume_info->sfu_emul) { if (pvolume_info->sfu_emul) {
cifs_dbg(VFS, "mount option mfsymlinks ignored if sfu mount option is used\n"); /*
} else { * Our SFU ("Services for Unix" emulation does not allow
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MF_SYMLINKS; * creating symlinks but does allow reading existing SFU
* symlinks (it does allow both creating and reading SFU
* style mknod and FIFOs though). When "mfsymlinks" and
* "sfu" are both enabled at the same time, it allows
* reading both types of symlinks, but will only create
* them with mfsymlinks format. This allows better
* Apple compatibility (probably better for Samba too)
* while still recognizing old Windows style symlinks.
*/
cifs_dbg(VFS, "mount options mfsymlinks and sfu both enabled\n");
} }
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MF_SYMLINKS;
} }
if ((pvolume_info->cifs_acl) && (pvolume_info->dynperm)) if ((pvolume_info->cifs_acl) && (pvolume_info->dynperm))
...@@ -3330,8 +3361,7 @@ expand_dfs_referral(const unsigned int xid, struct cifs_ses *ses, ...@@ -3330,8 +3361,7 @@ expand_dfs_referral(const unsigned int xid, struct cifs_ses *ses,
ref_path = check_prefix ? full_path + 1 : volume_info->UNC + 1; ref_path = check_prefix ? full_path + 1 : volume_info->UNC + 1;
rc = get_dfs_path(xid, ses, ref_path, cifs_sb->local_nls, rc = get_dfs_path(xid, ses, ref_path, cifs_sb->local_nls,
&num_referrals, &referrals, &num_referrals, &referrals, cifs_remap(cifs_sb));
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
if (!rc && num_referrals > 0) { if (!rc && num_referrals > 0) {
char *fake_devname = NULL; char *fake_devname = NULL;
......
...@@ -577,12 +577,13 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode, ...@@ -577,12 +577,13 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode,
struct cifs_io_parms io_parms; struct cifs_io_parms io_parms;
char *full_path = NULL; char *full_path = NULL;
struct inode *newinode = NULL; struct inode *newinode = NULL;
int oplock = 0; __u32 oplock = 0;
struct cifs_fid fid; struct cifs_fid fid;
struct cifs_open_parms oparms; struct cifs_open_parms oparms;
FILE_ALL_INFO *buf = NULL; FILE_ALL_INFO *buf = NULL;
unsigned int bytes_written; unsigned int bytes_written;
struct win_dev *pdev; struct win_dev *pdev;
struct kvec iov[2];
if (!old_valid_dev(device_number)) if (!old_valid_dev(device_number))
return -EINVAL; return -EINVAL;
...@@ -658,7 +659,11 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode, ...@@ -658,7 +659,11 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode,
oparms.fid = &fid; oparms.fid = &fid;
oparms.reconnect = false; oparms.reconnect = false;
rc = CIFS_open(xid, &oparms, &oplock, buf); if (tcon->ses->server->oplocks)
oplock = REQ_OPLOCK;
else
oplock = 0;
rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, buf);
if (rc) if (rc)
goto mknod_out; goto mknod_out;
...@@ -668,25 +673,26 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode, ...@@ -668,25 +673,26 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode,
*/ */
pdev = (struct win_dev *)buf; pdev = (struct win_dev *)buf;
io_parms.netfid = fid.netfid;
io_parms.pid = current->tgid; io_parms.pid = current->tgid;
io_parms.tcon = tcon; io_parms.tcon = tcon;
io_parms.offset = 0; io_parms.offset = 0;
io_parms.length = sizeof(struct win_dev); io_parms.length = sizeof(struct win_dev);
iov[1].iov_base = buf;
iov[1].iov_len = sizeof(struct win_dev);
if (S_ISCHR(mode)) { if (S_ISCHR(mode)) {
memcpy(pdev->type, "IntxCHR", 8); memcpy(pdev->type, "IntxCHR", 8);
pdev->major = cpu_to_le64(MAJOR(device_number)); pdev->major = cpu_to_le64(MAJOR(device_number));
pdev->minor = cpu_to_le64(MINOR(device_number)); pdev->minor = cpu_to_le64(MINOR(device_number));
rc = CIFSSMBWrite(xid, &io_parms, &bytes_written, (char *)pdev, rc = tcon->ses->server->ops->sync_write(xid, &fid, &io_parms,
NULL, 0); &bytes_written, iov, 1);
} else if (S_ISBLK(mode)) { } else if (S_ISBLK(mode)) {
memcpy(pdev->type, "IntxBLK", 8); memcpy(pdev->type, "IntxBLK", 8);
pdev->major = cpu_to_le64(MAJOR(device_number)); pdev->major = cpu_to_le64(MAJOR(device_number));
pdev->minor = cpu_to_le64(MINOR(device_number)); pdev->minor = cpu_to_le64(MINOR(device_number));
rc = CIFSSMBWrite(xid, &io_parms, &bytes_written, (char *)pdev, rc = tcon->ses->server->ops->sync_write(xid, &fid, &io_parms,
NULL, 0); &bytes_written, iov, 1);
} /* else if (S_ISFIFO) */ } /* else if (S_ISFIFO) */
CIFSSMBClose(xid, tcon, fid.netfid); tcon->ses->server->ops->close(xid, tcon, &fid);
d_drop(direntry); d_drop(direntry);
/* FIXME: add code here to set EAs */ /* FIXME: add code here to set EAs */
......
...@@ -1687,8 +1687,8 @@ cifs_write(struct cifsFileInfo *open_file, __u32 pid, const char *write_data, ...@@ -1687,8 +1687,8 @@ cifs_write(struct cifsFileInfo *open_file, __u32 pid, const char *write_data,
io_parms.tcon = tcon; io_parms.tcon = tcon;
io_parms.offset = *offset; io_parms.offset = *offset;
io_parms.length = len; io_parms.length = len;
rc = server->ops->sync_write(xid, open_file, &io_parms, rc = server->ops->sync_write(xid, &open_file->fid,
&bytes_written, iov, 1); &io_parms, &bytes_written, iov, 1);
} }
if (rc || (bytes_written == 0)) { if (rc || (bytes_written == 0)) {
if (total_written) if (total_written)
...@@ -3206,7 +3206,7 @@ cifs_read(struct file *file, char *read_data, size_t read_size, loff_t *offset) ...@@ -3206,7 +3206,7 @@ cifs_read(struct file *file, char *read_data, size_t read_size, loff_t *offset)
io_parms.tcon = tcon; io_parms.tcon = tcon;
io_parms.offset = *offset; io_parms.offset = *offset;
io_parms.length = current_read_size; io_parms.length = current_read_size;
rc = server->ops->sync_read(xid, open_file, &io_parms, rc = server->ops->sync_read(xid, &open_file->fid, &io_parms,
&bytes_read, &cur_offset, &bytes_read, &cur_offset,
&buf_type); &buf_type);
} while (rc == -EAGAIN); } while (rc == -EAGAIN);
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include "cifsproto.h" #include "cifsproto.h"
#include "cifs_debug.h" #include "cifs_debug.h"
#include "cifs_fs_sb.h" #include "cifs_fs_sb.h"
#include "cifs_unicode.h"
#include "fscache.h" #include "fscache.h"
...@@ -412,7 +413,7 @@ cifs_sfu_type(struct cifs_fattr *fattr, const char *path, ...@@ -412,7 +413,7 @@ cifs_sfu_type(struct cifs_fattr *fattr, const char *path,
struct cifs_sb_info *cifs_sb, unsigned int xid) struct cifs_sb_info *cifs_sb, unsigned int xid)
{ {
int rc; int rc;
int oplock = 0; __u32 oplock;
struct tcon_link *tlink; struct tcon_link *tlink;
struct cifs_tcon *tcon; struct cifs_tcon *tcon;
struct cifs_fid fid; struct cifs_fid fid;
...@@ -451,8 +452,13 @@ cifs_sfu_type(struct cifs_fattr *fattr, const char *path, ...@@ -451,8 +452,13 @@ cifs_sfu_type(struct cifs_fattr *fattr, const char *path,
oparms.fid = &fid; oparms.fid = &fid;
oparms.reconnect = false; oparms.reconnect = false;
rc = CIFS_open(xid, &oparms, &oplock, NULL); if (tcon->ses->server->oplocks)
oplock = REQ_OPLOCK;
else
oplock = 0;
rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, NULL);
if (rc) { if (rc) {
cifs_dbg(FYI, "check sfu type of %s, open rc = %d\n", path, rc);
cifs_put_tlink(tlink); cifs_put_tlink(tlink);
return rc; return rc;
} }
...@@ -464,7 +470,8 @@ cifs_sfu_type(struct cifs_fattr *fattr, const char *path, ...@@ -464,7 +470,8 @@ cifs_sfu_type(struct cifs_fattr *fattr, const char *path,
io_parms.offset = 0; io_parms.offset = 0;
io_parms.length = 24; io_parms.length = 24;
rc = CIFSSMBRead(xid, &io_parms, &bytes_read, &pbuf, &buf_type); rc = tcon->ses->server->ops->sync_read(xid, &fid, &io_parms,
&bytes_read, &pbuf, &buf_type);
if ((rc == 0) && (bytes_read >= 8)) { if ((rc == 0) && (bytes_read >= 8)) {
if (memcmp("IntxBLK", pbuf, 8) == 0) { if (memcmp("IntxBLK", pbuf, 8) == 0) {
cifs_dbg(FYI, "Block device\n"); cifs_dbg(FYI, "Block device\n");
...@@ -504,7 +511,8 @@ cifs_sfu_type(struct cifs_fattr *fattr, const char *path, ...@@ -504,7 +511,8 @@ cifs_sfu_type(struct cifs_fattr *fattr, const char *path,
fattr->cf_dtype = DT_REG; fattr->cf_dtype = DT_REG;
rc = -EOPNOTSUPP; /* or some unknown SFU type */ rc = -EOPNOTSUPP; /* or some unknown SFU type */
} }
CIFSSMBClose(xid, tcon, fid.netfid);
tcon->ses->server->ops->close(xid, tcon, &fid);
cifs_put_tlink(tlink); cifs_put_tlink(tlink);
return rc; return rc;
} }
...@@ -539,7 +547,7 @@ static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path, ...@@ -539,7 +547,7 @@ static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path,
rc = tcon->ses->server->ops->query_all_EAs(xid, tcon, path, rc = tcon->ses->server->ops->query_all_EAs(xid, tcon, path,
"SETFILEBITS", ea_value, 4 /* size of buf */, "SETFILEBITS", ea_value, 4 /* size of buf */,
cifs_sb->local_nls, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); cifs_remap(cifs_sb));
cifs_put_tlink(tlink); cifs_put_tlink(tlink);
if (rc < 0) if (rc < 0)
return (int)rc; return (int)rc;
...@@ -952,11 +960,18 @@ struct inode *cifs_root_iget(struct super_block *sb) ...@@ -952,11 +960,18 @@ struct inode *cifs_root_iget(struct super_block *sb)
struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
xid = get_xid(); xid = get_xid();
if (tcon->unix_ext) if (tcon->unix_ext) {
rc = cifs_get_inode_info_unix(&inode, "", sb, xid); rc = cifs_get_inode_info_unix(&inode, "", sb, xid);
else /* some servers mistakenly claim POSIX support */
if (rc != -EOPNOTSUPP)
goto iget_no_retry;
cifs_dbg(VFS, "server does not support POSIX extensions");
tcon->unix_ext = false;
}
rc = cifs_get_inode_info(&inode, "", NULL, sb, xid, NULL); rc = cifs_get_inode_info(&inode, "", NULL, sb, xid, NULL);
iget_no_retry:
if (!inode) { if (!inode) {
inode = ERR_PTR(rc); inode = ERR_PTR(rc);
goto out; goto out;
...@@ -1117,8 +1132,7 @@ cifs_rename_pending_delete(const char *full_path, struct dentry *dentry, ...@@ -1117,8 +1132,7 @@ cifs_rename_pending_delete(const char *full_path, struct dentry *dentry,
/* rename the file */ /* rename the file */
rc = CIFSSMBRenameOpenFile(xid, tcon, fid.netfid, NULL, rc = CIFSSMBRenameOpenFile(xid, tcon, fid.netfid, NULL,
cifs_sb->local_nls, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & cifs_remap(cifs_sb));
CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc != 0) { if (rc != 0) {
rc = -EBUSY; rc = -EBUSY;
goto undo_setattr; goto undo_setattr;
...@@ -1159,8 +1173,7 @@ cifs_rename_pending_delete(const char *full_path, struct dentry *dentry, ...@@ -1159,8 +1173,7 @@ cifs_rename_pending_delete(const char *full_path, struct dentry *dentry,
*/ */
undo_rename: undo_rename:
CIFSSMBRenameOpenFile(xid, tcon, fid.netfid, dentry->d_name.name, CIFSSMBRenameOpenFile(xid, tcon, fid.netfid, dentry->d_name.name,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & cifs_sb->local_nls, cifs_remap(cifs_sb));
CIFS_MOUNT_MAP_SPECIAL_CHR);
undo_setattr: undo_setattr:
if (dosattr != origattr) { if (dosattr != origattr) {
info_buf->Attributes = cpu_to_le32(origattr); info_buf->Attributes = cpu_to_le32(origattr);
...@@ -1226,7 +1239,7 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry) ...@@ -1226,7 +1239,7 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
le64_to_cpu(tcon->fsUnixInfo.Capability))) { le64_to_cpu(tcon->fsUnixInfo.Capability))) {
rc = CIFSPOSIXDelFile(xid, tcon, full_path, rc = CIFSPOSIXDelFile(xid, tcon, full_path,
SMB_POSIX_UNLINK_FILE_TARGET, cifs_sb->local_nls, SMB_POSIX_UNLINK_FILE_TARGET, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); cifs_remap(cifs_sb));
cifs_dbg(FYI, "posix del rc %d\n", rc); cifs_dbg(FYI, "posix del rc %d\n", rc);
if ((rc == 0) || (rc == -ENOENT)) if ((rc == 0) || (rc == -ENOENT))
goto psx_del_no_retry; goto psx_del_no_retry;
...@@ -1349,8 +1362,7 @@ cifs_mkdir_qinfo(struct inode *parent, struct dentry *dentry, umode_t mode, ...@@ -1349,8 +1362,7 @@ cifs_mkdir_qinfo(struct inode *parent, struct dentry *dentry, umode_t mode,
} }
CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args, CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
cifs_sb->local_nls, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & cifs_remap(cifs_sb));
CIFS_MOUNT_MAP_SPECIAL_CHR);
} else { } else {
struct TCP_Server_Info *server = tcon->ses->server; struct TCP_Server_Info *server = tcon->ses->server;
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) && if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
...@@ -1392,8 +1404,7 @@ cifs_posix_mkdir(struct inode *inode, struct dentry *dentry, umode_t mode, ...@@ -1392,8 +1404,7 @@ cifs_posix_mkdir(struct inode *inode, struct dentry *dentry, umode_t mode,
mode &= ~current_umask(); mode &= ~current_umask();
rc = CIFSPOSIXCreate(xid, tcon, SMB_O_DIRECTORY | SMB_O_CREAT, mode, rc = CIFSPOSIXCreate(xid, tcon, SMB_O_DIRECTORY | SMB_O_CREAT, mode,
NULL /* netfid */, info, &oplock, full_path, NULL /* netfid */, info, &oplock, full_path,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & cifs_sb->local_nls, cifs_remap(cifs_sb));
CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc == -EOPNOTSUPP) if (rc == -EOPNOTSUPP)
goto posix_mkdir_out; goto posix_mkdir_out;
else if (rc) { else if (rc) {
...@@ -1617,8 +1628,7 @@ cifs_do_rename(const unsigned int xid, struct dentry *from_dentry, ...@@ -1617,8 +1628,7 @@ cifs_do_rename(const unsigned int xid, struct dentry *from_dentry,
if (rc == 0) { if (rc == 0) {
rc = CIFSSMBRenameOpenFile(xid, tcon, fid.netfid, rc = CIFSSMBRenameOpenFile(xid, tcon, fid.netfid,
(const char *) to_dentry->d_name.name, (const char *) to_dentry->d_name.name,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & cifs_sb->local_nls, cifs_remap(cifs_sb));
CIFS_MOUNT_MAP_SPECIAL_CHR);
CIFSSMBClose(xid, tcon, fid.netfid); CIFSSMBClose(xid, tcon, fid.netfid);
} }
do_rename_exit: do_rename_exit:
...@@ -1694,16 +1704,14 @@ cifs_rename2(struct inode *source_dir, struct dentry *source_dentry, ...@@ -1694,16 +1704,14 @@ cifs_rename2(struct inode *source_dir, struct dentry *source_dentry,
tmprc = CIFSSMBUnixQPathInfo(xid, tcon, from_name, tmprc = CIFSSMBUnixQPathInfo(xid, tcon, from_name,
info_buf_source, info_buf_source,
cifs_sb->local_nls, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & cifs_remap(cifs_sb));
CIFS_MOUNT_MAP_SPECIAL_CHR);
if (tmprc != 0) if (tmprc != 0)
goto unlink_target; goto unlink_target;
tmprc = CIFSSMBUnixQPathInfo(xid, tcon, to_name, tmprc = CIFSSMBUnixQPathInfo(xid, tcon, to_name,
info_buf_target, info_buf_target,
cifs_sb->local_nls, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & cifs_remap(cifs_sb));
CIFS_MOUNT_MAP_SPECIAL_CHR);
if (tmprc == 0 && (info_buf_source->UniqueId == if (tmprc == 0 && (info_buf_source->UniqueId ==
info_buf_target->UniqueId)) { info_buf_target->UniqueId)) {
...@@ -2068,8 +2076,7 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs, ...@@ -2068,8 +2076,7 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
rc = SMBLegacyOpen(xid, tcon, full_path, FILE_OPEN, rc = SMBLegacyOpen(xid, tcon, full_path, FILE_OPEN,
GENERIC_WRITE, CREATE_NOT_DIR, &netfid, GENERIC_WRITE, CREATE_NOT_DIR, &netfid,
&oplock, NULL, cifs_sb->local_nls, &oplock, NULL, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & cifs_remap(cifs_sb));
CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc == 0) { if (rc == 0) {
unsigned int bytes_written; unsigned int bytes_written;
......
...@@ -28,6 +28,10 @@ ...@@ -28,6 +28,10 @@
#include "cifsproto.h" #include "cifsproto.h"
#include "cifs_debug.h" #include "cifs_debug.h"
#include "cifs_fs_sb.h" #include "cifs_fs_sb.h"
#include "cifs_unicode.h"
#ifdef CONFIG_CIFS_SMB2
#include "smb2proto.h"
#endif
/* /*
* M-F Symlink Functions - Begin * M-F Symlink Functions - Begin
...@@ -400,6 +404,134 @@ cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, ...@@ -400,6 +404,134 @@ cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
return rc; return rc;
} }
/*
* SMB 2.1/SMB3 Protocol specific functions
*/
#ifdef CONFIG_CIFS_SMB2
int
smb3_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;
struct cifs_fid fid;
struct cifs_open_parms oparms;
struct cifs_io_parms io_parms;
int buf_type = CIFS_NO_BUFFER;
__le16 *utf16_path;
__u8 oplock = SMB2_OPLOCK_LEVEL_II;
struct smb2_file_all_info *pfile_info = NULL;
oparms.tcon = tcon;
oparms.cifs_sb = cifs_sb;
oparms.desired_access = GENERIC_READ;
oparms.create_options = CREATE_NOT_DIR;
if (backup_cred(cifs_sb))
oparms.create_options |= CREATE_OPEN_BACKUP_INTENT;
oparms.disposition = FILE_OPEN;
oparms.fid = &fid;
oparms.reconnect = false;
utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
if (utf16_path == NULL)
return -ENOMEM;
pfile_info = kzalloc(sizeof(struct smb2_file_all_info) + PATH_MAX * 2,
GFP_KERNEL);
if (pfile_info == NULL) {
kfree(utf16_path);
return -ENOMEM;
}
rc = SMB2_open(xid, &oparms, utf16_path, &oplock, pfile_info, NULL);
if (rc)
goto qmf_out_open_fail;
if (pfile_info->EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) {
/* it's not a symlink */
rc = -ENOENT; /* Is there a better rc to return? */
goto qmf_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;
io_parms.persistent_fid = fid.persistent_fid;
io_parms.volatile_fid = fid.volatile_fid;
rc = SMB2_read(xid, &io_parms, pbytes_read, &pbuf, &buf_type);
qmf_out:
SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
qmf_out_open_fail:
kfree(utf16_path);
kfree(pfile_info);
return rc;
}
int
smb3_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;
struct cifs_fid fid;
struct cifs_open_parms oparms;
struct cifs_io_parms io_parms;
int create_options = CREATE_NOT_DIR;
__le16 *utf16_path;
__u8 oplock = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
struct kvec iov[2];
if (backup_cred(cifs_sb))
create_options |= CREATE_OPEN_BACKUP_INTENT;
cifs_dbg(FYI, "%s: path: %s\n", __func__, path);
utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
if (!utf16_path)
return -ENOMEM;
oparms.tcon = tcon;
oparms.cifs_sb = cifs_sb;
oparms.desired_access = GENERIC_WRITE;
oparms.create_options = create_options;
oparms.disposition = FILE_CREATE;
oparms.fid = &fid;
oparms.reconnect = false;
rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL);
if (rc) {
kfree(utf16_path);
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;
io_parms.persistent_fid = fid.persistent_fid;
io_parms.volatile_fid = fid.volatile_fid;
/* iov[0] is reserved for smb header */
iov[1].iov_base = pbuf;
iov[1].iov_len = CIFS_MF_SYMLINK_FILE_SIZE;
rc = SMB2_write(xid, &io_parms, pbytes_written, iov, 1);
/* Make sure we wrote all of the symlink data */
if ((rc == 0) && (*pbytes_written != CIFS_MF_SYMLINK_FILE_SIZE))
rc = -EIO;
SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
kfree(utf16_path);
return rc;
}
#endif /* CONFIG_CIFS_SMB2 */
/* /*
* M-F Symlink Functions - End * M-F Symlink Functions - End
*/ */
...@@ -435,8 +567,7 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode, ...@@ -435,8 +567,7 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
if (tcon->unix_ext) if (tcon->unix_ext)
rc = CIFSUnixCreateHardLink(xid, tcon, from_name, to_name, rc = CIFSUnixCreateHardLink(xid, tcon, from_name, to_name,
cifs_sb->local_nls, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & cifs_remap(cifs_sb));
CIFS_MOUNT_MAP_SPECIAL_CHR);
else { else {
server = tcon->ses->server; server = tcon->ses->server;
if (!server->ops->create_hardlink) { if (!server->ops->create_hardlink) {
...@@ -461,11 +592,7 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode, ...@@ -461,11 +592,7 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
spin_lock(&old_file->d_inode->i_lock); spin_lock(&old_file->d_inode->i_lock);
inc_nlink(old_file->d_inode); inc_nlink(old_file->d_inode);
spin_unlock(&old_file->d_inode->i_lock); spin_unlock(&old_file->d_inode->i_lock);
/*
* BB should we make this contingent on superblock flag
* NOATIME?
*/
/* old_file->d_inode->i_ctime = CURRENT_TIME; */
/* /*
* parent dir timestamps will update from srv within a * parent dir timestamps will update from srv within a
* second, would it really be worth it to set the parent * second, would it really be worth it to set the parent
...@@ -475,7 +602,9 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode, ...@@ -475,7 +602,9 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
} }
/* /*
* if not oplocked will force revalidate to get info on source * if not oplocked will force revalidate to get info on source
* file from srv * file from srv. Note Samba server prior to 4.2 has bug -
* not updating src file ctime on hardlinks but Windows servers
* handle it properly
*/ */
cifsInode->time = 0; cifsInode->time = 0;
......
...@@ -239,7 +239,7 @@ int get_symlink_reparse_path(char *full_path, struct cifs_sb_info *cifs_sb, ...@@ -239,7 +239,7 @@ int get_symlink_reparse_path(char *full_path, struct cifs_sb_info *cifs_sb,
rc = CIFSSMBOpen(xid, ptcon, full_path, FILE_OPEN, GENERIC_READ, rc = CIFSSMBOpen(xid, ptcon, full_path, FILE_OPEN, GENERIC_READ,
OPEN_REPARSE_POINT, &fid, &oplock, NULL, OPEN_REPARSE_POINT, &fid, &oplock, NULL,
cifs_sb->local_nls, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); cifs_remap(cifs_sb);
if (!rc) { if (!rc) {
tmpbuffer = kmalloc(maxpath); tmpbuffer = kmalloc(maxpath);
rc = CIFSSMBQueryReparseLinkInfo(xid, ptcon, full_path, rc = CIFSSMBQueryReparseLinkInfo(xid, ptcon, full_path,
...@@ -704,15 +704,15 @@ static int cifs_filldir(char *find_entry, struct file *file, ...@@ -704,15 +704,15 @@ static int cifs_filldir(char *find_entry, struct file *file,
if (file_info->srch_inf.unicode) { if (file_info->srch_inf.unicode) {
struct nls_table *nlt = cifs_sb->local_nls; struct nls_table *nlt = cifs_sb->local_nls;
int map_type;
map_type = cifs_remap(cifs_sb);
name.name = scratch_buf; name.name = scratch_buf;
name.len = name.len =
cifs_from_utf16((char *)name.name, (__le16 *)de.name, cifs_from_utf16((char *)name.name, (__le16 *)de.name,
UNICODE_NAME_MAX, UNICODE_NAME_MAX,
min_t(size_t, de.namelen, min_t(size_t, de.namelen,
(size_t)max_len), nlt, (size_t)max_len), nlt, map_type);
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
name.len -= nls_nullsize(nlt); name.len -= nls_nullsize(nlt);
} else { } else {
name.name = de.name; name.name = de.name;
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "cifsproto.h" #include "cifsproto.h"
#include "cifs_debug.h" #include "cifs_debug.h"
#include "cifspdu.h" #include "cifspdu.h"
#include "cifs_unicode.h"
/* /*
* An NT cancel request header looks just like the original request except: * An NT cancel request header looks just like the original request except:
...@@ -530,13 +531,11 @@ cifs_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -530,13 +531,11 @@ cifs_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon,
rc = CIFSSMBQPathInfo(xid, tcon, full_path, file_info, rc = CIFSSMBQPathInfo(xid, tcon, full_path, file_info,
0 /* not legacy */, cifs_sb->local_nls, 0 /* not legacy */, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & cifs_remap(cifs_sb));
CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc == -EOPNOTSUPP || rc == -EINVAL) if (rc == -EOPNOTSUPP || rc == -EINVAL)
rc = SMBQueryInformation(xid, tcon, full_path, file_info, rc = SMBQueryInformation(xid, tcon, full_path, file_info,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & cifs_sb->local_nls, cifs_remap(cifs_sb));
CIFS_MOUNT_MAP_SPECIAL_CHR);
kfree(file_info); kfree(file_info);
return rc; return rc;
} }
...@@ -552,8 +551,7 @@ cifs_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -552,8 +551,7 @@ cifs_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
/* could do find first instead but this returns more info */ /* could do find first instead but this returns more info */
rc = CIFSSMBQPathInfo(xid, tcon, full_path, data, 0 /* not legacy */, rc = CIFSSMBQPathInfo(xid, tcon, full_path, data, 0 /* not legacy */,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & cifs_sb->local_nls, cifs_remap(cifs_sb));
CIFS_MOUNT_MAP_SPECIAL_CHR);
/* /*
* BB optimize code so we do not make the above call when server claims * BB optimize code so we do not make the above call when server claims
* no NT SMB support and the above call failed at least once - set flag * no NT SMB support and the above call failed at least once - set flag
...@@ -562,8 +560,7 @@ cifs_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -562,8 +560,7 @@ cifs_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
if ((rc == -EOPNOTSUPP) || (rc == -EINVAL)) { if ((rc == -EOPNOTSUPP) || (rc == -EINVAL)) {
rc = SMBQueryInformation(xid, tcon, full_path, data, rc = SMBQueryInformation(xid, tcon, full_path, data,
cifs_sb->local_nls, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & cifs_remap(cifs_sb));
CIFS_MOUNT_MAP_SPECIAL_CHR);
*adjustTZ = true; *adjustTZ = true;
} }
...@@ -611,8 +608,7 @@ cifs_get_srv_inum(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -611,8 +608,7 @@ cifs_get_srv_inum(const unsigned int xid, struct cifs_tcon *tcon,
*/ */
return CIFSGetSrvInodeNumber(xid, tcon, full_path, uniqueid, return CIFSGetSrvInodeNumber(xid, tcon, full_path, uniqueid,
cifs_sb->local_nls, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & cifs_remap(cifs_sb));
CIFS_MOUNT_MAP_SPECIAL_CHR);
} }
static int static int
...@@ -703,8 +699,7 @@ cifs_mkdir_setinfo(struct inode *inode, const char *full_path, ...@@ -703,8 +699,7 @@ cifs_mkdir_setinfo(struct inode *inode, const char *full_path,
dosattrs = cifsInode->cifsAttrs|ATTR_READONLY; dosattrs = cifsInode->cifsAttrs|ATTR_READONLY;
info.Attributes = cpu_to_le32(dosattrs); info.Attributes = cpu_to_le32(dosattrs);
rc = CIFSSMBSetPathInfo(xid, tcon, full_path, &info, cifs_sb->local_nls, rc = CIFSSMBSetPathInfo(xid, tcon, full_path, &info, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & cifs_remap(cifs_sb));
CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc == 0) if (rc == 0)
cifsInode->cifsAttrs = dosattrs; cifsInode->cifsAttrs = dosattrs;
} }
...@@ -720,8 +715,7 @@ cifs_open_file(const unsigned int xid, struct cifs_open_parms *oparms, ...@@ -720,8 +715,7 @@ cifs_open_file(const unsigned int xid, struct cifs_open_parms *oparms,
oparms->create_options, oparms->create_options,
&oparms->fid->netfid, oplock, buf, &oparms->fid->netfid, oplock, buf,
oparms->cifs_sb->local_nls, oparms->cifs_sb->local_nls,
oparms->cifs_sb->mnt_cifs_flags cifs_remap(oparms->cifs_sb));
& CIFS_MOUNT_MAP_SPECIAL_CHR);
return CIFS_open(xid, oparms, oplock, buf); return CIFS_open(xid, oparms, oplock, buf);
} }
...@@ -749,21 +743,21 @@ cifs_flush_file(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -749,21 +743,21 @@ cifs_flush_file(const unsigned int xid, struct cifs_tcon *tcon,
} }
static int static int
cifs_sync_read(const unsigned int xid, struct cifsFileInfo *cfile, cifs_sync_read(const unsigned int xid, struct cifs_fid *pfid,
struct cifs_io_parms *parms, unsigned int *bytes_read, struct cifs_io_parms *parms, unsigned int *bytes_read,
char **buf, int *buf_type) char **buf, int *buf_type)
{ {
parms->netfid = cfile->fid.netfid; parms->netfid = pfid->netfid;
return CIFSSMBRead(xid, parms, bytes_read, buf, buf_type); return CIFSSMBRead(xid, parms, bytes_read, buf, buf_type);
} }
static int static int
cifs_sync_write(const unsigned int xid, struct cifsFileInfo *cfile, cifs_sync_write(const unsigned int xid, struct cifs_fid *pfid,
struct cifs_io_parms *parms, unsigned int *written, struct cifs_io_parms *parms, unsigned int *written,
struct kvec *iov, unsigned long nr_segs) struct kvec *iov, unsigned long nr_segs)
{ {
parms->netfid = cfile->fid.netfid; parms->netfid = pfid->netfid;
return CIFSSMBWrite2(xid, parms, written, iov, nr_segs); return CIFSSMBWrite2(xid, parms, written, iov, nr_segs);
} }
...@@ -800,8 +794,7 @@ smb_set_file_info(struct inode *inode, const char *full_path, ...@@ -800,8 +794,7 @@ smb_set_file_info(struct inode *inode, const char *full_path,
tcon = tlink_tcon(tlink); tcon = tlink_tcon(tlink);
rc = CIFSSMBSetPathInfo(xid, tcon, full_path, buf, cifs_sb->local_nls, rc = CIFSSMBSetPathInfo(xid, tcon, full_path, buf, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & cifs_remap(cifs_sb));
CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc == 0) { if (rc == 0) {
cinode->cifsAttrs = le32_to_cpu(buf->Attributes); cinode->cifsAttrs = le32_to_cpu(buf->Attributes);
goto out; goto out;
......
...@@ -379,6 +379,14 @@ cifs_convert_path_to_utf16(const char *from, struct cifs_sb_info *cifs_sb) ...@@ -379,6 +379,14 @@ cifs_convert_path_to_utf16(const char *from, struct cifs_sb_info *cifs_sb)
int len; int len;
const char *start_of_path; const char *start_of_path;
__le16 *to; __le16 *to;
int map_type;
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SFM_CHR)
map_type = SFM_MAP_UNI_RSVD;
else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR)
map_type = SFU_MAP_UNI_RSVD;
else
map_type = NO_MAP_UNI_RSVD;
/* Windows doesn't allow paths beginning with \ */ /* Windows doesn't allow paths beginning with \ */
if (from[0] == '\\') if (from[0] == '\\')
...@@ -386,9 +394,7 @@ cifs_convert_path_to_utf16(const char *from, struct cifs_sb_info *cifs_sb) ...@@ -386,9 +394,7 @@ cifs_convert_path_to_utf16(const char *from, struct cifs_sb_info *cifs_sb)
else else
start_of_path = from; start_of_path = from;
to = cifs_strndup_to_utf16(start_of_path, PATH_MAX, &len, to = cifs_strndup_to_utf16(start_of_path, PATH_MAX, &len,
cifs_sb->local_nls, cifs_sb->local_nls, map_type);
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
return to; return to;
} }
......
...@@ -265,15 +265,18 @@ SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon) ...@@ -265,15 +265,18 @@ SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon)
FSCTL_QUERY_NETWORK_INTERFACE_INFO, true /* is_fsctl */, FSCTL_QUERY_NETWORK_INTERFACE_INFO, true /* is_fsctl */,
NULL /* no data input */, 0 /* no data input */, NULL /* no data input */, 0 /* no data input */,
(char **)&out_buf, &ret_data_len); (char **)&out_buf, &ret_data_len);
if (rc != 0)
if ((rc == 0) && (ret_data_len > 0)) { cifs_dbg(VFS, "error %d on ioctl to get interface list\n", rc);
else if (ret_data_len < sizeof(struct network_interface_info_ioctl_rsp)) {
cifs_dbg(VFS, "server returned bad net interface info buf\n");
rc = -EINVAL;
} else {
/* Dump info on first interface */ /* Dump info on first interface */
cifs_dbg(FYI, "Adapter Capability 0x%x\t", cifs_dbg(FYI, "Adapter Capability 0x%x\t",
le32_to_cpu(out_buf->Capability)); le32_to_cpu(out_buf->Capability));
cifs_dbg(FYI, "Link Speed %lld\n", cifs_dbg(FYI, "Link Speed %lld\n",
le64_to_cpu(out_buf->LinkSpeed)); le64_to_cpu(out_buf->LinkSpeed));
} else }
cifs_dbg(VFS, "error %d on ioctl to get interface list\n", rc);
return rc; return rc;
} }
...@@ -711,23 +714,23 @@ smb2_read_data_length(char *buf) ...@@ -711,23 +714,23 @@ smb2_read_data_length(char *buf)
static int static int
smb2_sync_read(const unsigned int xid, struct cifsFileInfo *cfile, smb2_sync_read(const unsigned int xid, struct cifs_fid *pfid,
struct cifs_io_parms *parms, unsigned int *bytes_read, struct cifs_io_parms *parms, unsigned int *bytes_read,
char **buf, int *buf_type) char **buf, int *buf_type)
{ {
parms->persistent_fid = cfile->fid.persistent_fid; parms->persistent_fid = pfid->persistent_fid;
parms->volatile_fid = cfile->fid.volatile_fid; parms->volatile_fid = pfid->volatile_fid;
return SMB2_read(xid, parms, bytes_read, buf, buf_type); return SMB2_read(xid, parms, bytes_read, buf, buf_type);
} }
static int static int
smb2_sync_write(const unsigned int xid, struct cifsFileInfo *cfile, smb2_sync_write(const unsigned int xid, struct cifs_fid *pfid,
struct cifs_io_parms *parms, unsigned int *written, struct cifs_io_parms *parms, unsigned int *written,
struct kvec *iov, unsigned long nr_segs) struct kvec *iov, unsigned long nr_segs)
{ {
parms->persistent_fid = cfile->fid.persistent_fid; parms->persistent_fid = pfid->persistent_fid;
parms->volatile_fid = cfile->fid.volatile_fid; parms->volatile_fid = pfid->volatile_fid;
return SMB2_write(xid, parms, written, iov, nr_segs); return SMB2_write(xid, parms, written, iov, nr_segs);
} }
...@@ -1452,6 +1455,8 @@ struct smb_version_operations smb21_operations = { ...@@ -1452,6 +1455,8 @@ struct smb_version_operations smb21_operations = {
.rename = smb2_rename_path, .rename = smb2_rename_path,
.create_hardlink = smb2_create_hardlink, .create_hardlink = smb2_create_hardlink,
.query_symlink = smb2_query_symlink, .query_symlink = smb2_query_symlink,
.query_mf_symlink = smb3_query_mf_symlink,
.create_mf_symlink = smb3_create_mf_symlink,
.open = smb2_open_file, .open = smb2_open_file,
.set_fid = smb2_set_fid, .set_fid = smb2_set_fid,
.close = smb2_close_file, .close = smb2_close_file,
...@@ -1531,6 +1536,8 @@ struct smb_version_operations smb30_operations = { ...@@ -1531,6 +1536,8 @@ struct smb_version_operations smb30_operations = {
.rename = smb2_rename_path, .rename = smb2_rename_path,
.create_hardlink = smb2_create_hardlink, .create_hardlink = smb2_create_hardlink,
.query_symlink = smb2_query_symlink, .query_symlink = smb2_query_symlink,
.query_mf_symlink = smb3_query_mf_symlink,
.create_mf_symlink = smb3_create_mf_symlink,
.open = smb2_open_file, .open = smb2_open_file,
.set_fid = smb2_set_fid, .set_fid = smb2_set_fid,
.close = smb2_close_file, .close = smb2_close_file,
......
...@@ -1098,6 +1098,8 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, ...@@ -1098,6 +1098,8 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
if (oparms->create_options & CREATE_OPTION_READONLY) if (oparms->create_options & CREATE_OPTION_READONLY)
file_attributes |= ATTR_READONLY; file_attributes |= ATTR_READONLY;
if (oparms->create_options & CREATE_OPTION_SPECIAL)
file_attributes |= ATTR_SYSTEM;
req->ImpersonationLevel = IL_IMPERSONATION; req->ImpersonationLevel = IL_IMPERSONATION;
req->DesiredAccess = cpu_to_le32(oparms->desired_access); req->DesiredAccess = cpu_to_le32(oparms->desired_access);
......
...@@ -352,6 +352,8 @@ struct smb2_tree_disconnect_rsp { ...@@ -352,6 +352,8 @@ struct smb2_tree_disconnect_rsp {
#define FILE_ATTRIBUTE_OFFLINE 0x00001000 #define FILE_ATTRIBUTE_OFFLINE 0x00001000
#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x00002000 #define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x00002000
#define FILE_ATTRIBUTE_ENCRYPTED 0x00004000 #define FILE_ATTRIBUTE_ENCRYPTED 0x00004000
#define FILE_ATTRIBUTE_INTEGRITY_STREAM 0x00008000
#define FILE_ATTRIBUTE_NO_SCRUB_DATA 0x00020000
/* Oplock levels */ /* Oplock levels */
#define SMB2_OPLOCK_LEVEL_NONE 0x00 #define SMB2_OPLOCK_LEVEL_NONE 0x00
......
...@@ -82,7 +82,13 @@ extern int smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -82,7 +82,13 @@ extern int smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon,
extern int smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon, extern int smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
const char *from_name, const char *to_name, const char *from_name, const char *to_name,
struct cifs_sb_info *cifs_sb); struct cifs_sb_info *cifs_sb);
extern int smb3_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);
extern int smb3_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);
extern int smb2_open_file(const unsigned int xid, extern int smb2_open_file(const unsigned int xid,
struct cifs_open_parms *oparms, struct cifs_open_parms *oparms,
__u32 *oplock, FILE_ALL_INFO *buf); __u32 *oplock, FILE_ALL_INFO *buf);
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <linux/string.h> #include <linux/string.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/random.h> #include <linux/random.h>
#include "cifs_fs_sb.h"
#include "cifs_unicode.h" #include "cifs_unicode.h"
#include "cifspdu.h" #include "cifspdu.h"
#include "cifsglob.h" #include "cifsglob.h"
......
...@@ -28,6 +28,8 @@ ...@@ -28,6 +28,8 @@
#include "cifsglob.h" #include "cifsglob.h"
#include "cifsproto.h" #include "cifsproto.h"
#include "cifs_debug.h" #include "cifs_debug.h"
#include "cifs_fs_sb.h"
#include "cifs_unicode.h"
#define MAX_EA_VALUE_SIZE 65535 #define MAX_EA_VALUE_SIZE 65535
#define CIFS_XATTR_DOS_ATTRIB "user.DosAttrib" #define CIFS_XATTR_DOS_ATTRIB "user.DosAttrib"
...@@ -85,8 +87,7 @@ int cifs_removexattr(struct dentry *direntry, const char *ea_name) ...@@ -85,8 +87,7 @@ int cifs_removexattr(struct dentry *direntry, const char *ea_name)
if (pTcon->ses->server->ops->set_EA) if (pTcon->ses->server->ops->set_EA)
rc = pTcon->ses->server->ops->set_EA(xid, pTcon, rc = pTcon->ses->server->ops->set_EA(xid, pTcon,
full_path, ea_name, NULL, (__u16)0, full_path, ea_name, NULL, (__u16)0,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & cifs_sb->local_nls, cifs_remap(cifs_sb));
CIFS_MOUNT_MAP_SPECIAL_CHR);
} }
remove_ea_exit: remove_ea_exit:
kfree(full_path); kfree(full_path);
...@@ -154,8 +155,7 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name, ...@@ -154,8 +155,7 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name,
if (pTcon->ses->server->ops->set_EA) if (pTcon->ses->server->ops->set_EA)
rc = pTcon->ses->server->ops->set_EA(xid, pTcon, rc = pTcon->ses->server->ops->set_EA(xid, pTcon,
full_path, ea_name, ea_value, (__u16)value_size, full_path, ea_name, ea_value, (__u16)value_size,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & cifs_sb->local_nls, cifs_remap(cifs_sb));
CIFS_MOUNT_MAP_SPECIAL_CHR);
} else if (strncmp(ea_name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) } else if (strncmp(ea_name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN)
== 0) { == 0) {
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
...@@ -165,8 +165,7 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name, ...@@ -165,8 +165,7 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name,
if (pTcon->ses->server->ops->set_EA) if (pTcon->ses->server->ops->set_EA)
rc = pTcon->ses->server->ops->set_EA(xid, pTcon, rc = pTcon->ses->server->ops->set_EA(xid, pTcon,
full_path, ea_name, ea_value, (__u16)value_size, full_path, ea_name, ea_value, (__u16)value_size,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & cifs_sb->local_nls, cifs_remap(cifs_sb));
CIFS_MOUNT_MAP_SPECIAL_CHR);
} else if (strncmp(ea_name, CIFS_XATTR_CIFS_ACL, } else if (strncmp(ea_name, CIFS_XATTR_CIFS_ACL,
strlen(CIFS_XATTR_CIFS_ACL)) == 0) { strlen(CIFS_XATTR_CIFS_ACL)) == 0) {
#ifdef CONFIG_CIFS_ACL #ifdef CONFIG_CIFS_ACL
...@@ -199,8 +198,7 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name, ...@@ -199,8 +198,7 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name,
rc = CIFSSMBSetPosixACL(xid, pTcon, full_path, rc = CIFSSMBSetPosixACL(xid, pTcon, full_path,
ea_value, (const int)value_size, ea_value, (const int)value_size,
ACL_TYPE_ACCESS, cifs_sb->local_nls, ACL_TYPE_ACCESS, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & cifs_remap(cifs_sb));
CIFS_MOUNT_MAP_SPECIAL_CHR);
cifs_dbg(FYI, "set POSIX ACL rc %d\n", rc); cifs_dbg(FYI, "set POSIX ACL rc %d\n", rc);
#else #else
cifs_dbg(FYI, "set POSIX ACL not supported\n"); cifs_dbg(FYI, "set POSIX ACL not supported\n");
...@@ -212,8 +210,7 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name, ...@@ -212,8 +210,7 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name,
rc = CIFSSMBSetPosixACL(xid, pTcon, full_path, rc = CIFSSMBSetPosixACL(xid, pTcon, full_path,
ea_value, (const int)value_size, ea_value, (const int)value_size,
ACL_TYPE_DEFAULT, cifs_sb->local_nls, ACL_TYPE_DEFAULT, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & cifs_remap(cifs_sb));
CIFS_MOUNT_MAP_SPECIAL_CHR);
cifs_dbg(FYI, "set POSIX default ACL rc %d\n", rc); cifs_dbg(FYI, "set POSIX default ACL rc %d\n", rc);
#else #else
cifs_dbg(FYI, "set default POSIX ACL not supported\n"); cifs_dbg(FYI, "set default POSIX ACL not supported\n");
...@@ -285,8 +282,7 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name, ...@@ -285,8 +282,7 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
if (pTcon->ses->server->ops->query_all_EAs) if (pTcon->ses->server->ops->query_all_EAs)
rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon, rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon,
full_path, ea_name, ea_value, buf_size, full_path, ea_name, ea_value, buf_size,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & cifs_sb->local_nls, cifs_remap(cifs_sb));
CIFS_MOUNT_MAP_SPECIAL_CHR);
} else if (strncmp(ea_name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) == 0) { } else if (strncmp(ea_name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) == 0) {
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
goto get_ea_exit; goto get_ea_exit;
...@@ -295,8 +291,7 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name, ...@@ -295,8 +291,7 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
if (pTcon->ses->server->ops->query_all_EAs) if (pTcon->ses->server->ops->query_all_EAs)
rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon, rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon,
full_path, ea_name, ea_value, buf_size, full_path, ea_name, ea_value, buf_size,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & cifs_sb->local_nls, cifs_remap(cifs_sb));
CIFS_MOUNT_MAP_SPECIAL_CHR);
} else if (strncmp(ea_name, POSIX_ACL_XATTR_ACCESS, } else if (strncmp(ea_name, POSIX_ACL_XATTR_ACCESS,
strlen(POSIX_ACL_XATTR_ACCESS)) == 0) { strlen(POSIX_ACL_XATTR_ACCESS)) == 0) {
#ifdef CONFIG_CIFS_POSIX #ifdef CONFIG_CIFS_POSIX
...@@ -304,8 +299,7 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name, ...@@ -304,8 +299,7 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
rc = CIFSSMBGetPosixACL(xid, pTcon, full_path, rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
ea_value, buf_size, ACL_TYPE_ACCESS, ea_value, buf_size, ACL_TYPE_ACCESS,
cifs_sb->local_nls, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & cifs_remap(cifs_sb));
CIFS_MOUNT_MAP_SPECIAL_CHR);
#else #else
cifs_dbg(FYI, "Query POSIX ACL not supported yet\n"); cifs_dbg(FYI, "Query POSIX ACL not supported yet\n");
#endif /* CONFIG_CIFS_POSIX */ #endif /* CONFIG_CIFS_POSIX */
...@@ -316,8 +310,7 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name, ...@@ -316,8 +310,7 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
rc = CIFSSMBGetPosixACL(xid, pTcon, full_path, rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
ea_value, buf_size, ACL_TYPE_DEFAULT, ea_value, buf_size, ACL_TYPE_DEFAULT,
cifs_sb->local_nls, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & cifs_remap(cifs_sb));
CIFS_MOUNT_MAP_SPECIAL_CHR);
#else #else
cifs_dbg(FYI, "Query POSIX default ACL not supported yet\n"); cifs_dbg(FYI, "Query POSIX default ACL not supported yet\n");
#endif /* CONFIG_CIFS_POSIX */ #endif /* CONFIG_CIFS_POSIX */
...@@ -421,8 +414,7 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size) ...@@ -421,8 +414,7 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size)
if (pTcon->ses->server->ops->query_all_EAs) if (pTcon->ses->server->ops->query_all_EAs)
rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon, rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon,
full_path, NULL, data, buf_size, full_path, NULL, data, buf_size,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & cifs_sb->local_nls, cifs_remap(cifs_sb));
CIFS_MOUNT_MAP_SPECIAL_CHR);
list_ea_exit: list_ea_exit:
kfree(full_path); kfree(full_path);
free_xid(xid); free_xid(xid);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment