|
@@ -82,23 +82,34 @@ void
|
|
|
cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
|
|
|
{
|
|
|
struct cifsInodeInfo *cifs_i = CIFS_I(inode);
|
|
|
- unsigned long now = jiffies;
|
|
|
+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
|
|
|
+ unsigned long oldtime = cifs_i->time;
|
|
|
|
|
|
inode->i_atime = fattr->cf_atime;
|
|
|
inode->i_mtime = fattr->cf_mtime;
|
|
|
inode->i_ctime = fattr->cf_ctime;
|
|
|
- inode->i_mode = fattr->cf_mode;
|
|
|
inode->i_rdev = fattr->cf_rdev;
|
|
|
inode->i_nlink = fattr->cf_nlink;
|
|
|
inode->i_uid = fattr->cf_uid;
|
|
|
inode->i_gid = fattr->cf_gid;
|
|
|
|
|
|
+ /* if dynperm is set, don't clobber existing mode */
|
|
|
+ if (inode->i_state & I_NEW ||
|
|
|
+ !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM))
|
|
|
+ inode->i_mode = fattr->cf_mode;
|
|
|
+
|
|
|
cifs_i->cifsAttrs = fattr->cf_cifsattrs;
|
|
|
cifs_i->uniqueid = fattr->cf_uniqueid;
|
|
|
|
|
|
+ if (fattr->cf_flags & CIFS_FATTR_NEED_REVAL)
|
|
|
+ cifs_i->time = 0;
|
|
|
+ else
|
|
|
+ cifs_i->time = jiffies;
|
|
|
+
|
|
|
cFYI(1, ("inode 0x%p old_time=%ld new_time=%ld", inode,
|
|
|
- cifs_i->time, now));
|
|
|
- cifs_i->time = now;
|
|
|
+ oldtime, cifs_i->time));
|
|
|
+
|
|
|
+ cifs_i->delete_pending = fattr->cf_flags & CIFS_FATTR_DELETE_PENDING;
|
|
|
|
|
|
/*
|
|
|
* Can't safely change the file size here if the client is writing to
|
|
@@ -219,49 +230,6 @@ cifs_create_dfs_fattr(struct cifs_fattr *fattr, struct super_block *sb)
|
|
|
fattr->cf_flags |= CIFS_FATTR_DFS_REFERRAL;
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * cifs_new inode - create new inode, initialize, and hash it
|
|
|
- * @sb - pointer to superblock
|
|
|
- * @inum - if valid pointer and serverino is enabled, replace i_ino with val
|
|
|
- *
|
|
|
- * Create a new inode, initialize it for CIFS and hash it. Returns the new
|
|
|
- * inode or NULL if one couldn't be allocated.
|
|
|
- *
|
|
|
- * If the share isn't mounted with "serverino" or inum is a NULL pointer then
|
|
|
- * we'll just use the inode number assigned by new_inode(). Note that this can
|
|
|
- * mean i_ino collisions since the i_ino assigned by new_inode is not
|
|
|
- * guaranteed to be unique.
|
|
|
- */
|
|
|
-struct inode *
|
|
|
-cifs_new_inode(struct super_block *sb, __u64 *inum)
|
|
|
-{
|
|
|
- struct inode *inode;
|
|
|
-
|
|
|
- inode = new_inode(sb);
|
|
|
- if (inode == NULL)
|
|
|
- return NULL;
|
|
|
-
|
|
|
- /*
|
|
|
- * BB: Is i_ino == 0 legal? Here, we assume that it is. If it isn't we
|
|
|
- * stop passing inum as ptr. Are there sanity checks we can use to
|
|
|
- * ensure that the server is really filling in that field? Also,
|
|
|
- * if serverino is disabled, perhaps we should be using iunique()?
|
|
|
- */
|
|
|
- if (inum && (CIFS_SB(sb)->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM))
|
|
|
- inode->i_ino = (unsigned long) *inum;
|
|
|
-
|
|
|
- /*
|
|
|
- * must set this here instead of cifs_alloc_inode since VFS will
|
|
|
- * clobber i_flags
|
|
|
- */
|
|
|
- if (sb->s_flags & MS_NOATIME)
|
|
|
- inode->i_flags |= S_NOATIME | S_NOCMTIME;
|
|
|
-
|
|
|
- insert_inode_hash(inode);
|
|
|
-
|
|
|
- return inode;
|
|
|
-}
|
|
|
-
|
|
|
int cifs_get_inode_info_unix(struct inode **pinode,
|
|
|
const unsigned char *full_path,
|
|
|
struct super_block *sb, int xid)
|
|
@@ -302,9 +270,9 @@ int cifs_get_inode_info_unix(struct inode **pinode,
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
-static int decode_sfu_inode(struct inode *inode, __u64 size,
|
|
|
- const unsigned char *path,
|
|
|
- struct cifs_sb_info *cifs_sb, int xid)
|
|
|
+static int
|
|
|
+cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path,
|
|
|
+ struct cifs_sb_info *cifs_sb, int xid)
|
|
|
{
|
|
|
int rc;
|
|
|
int oplock = 0;
|
|
@@ -316,10 +284,15 @@ static int decode_sfu_inode(struct inode *inode, __u64 size,
|
|
|
|
|
|
pbuf = buf;
|
|
|
|
|
|
- if (size == 0) {
|
|
|
- inode->i_mode |= S_IFIFO;
|
|
|
+ fattr->cf_mode &= ~S_IFMT;
|
|
|
+
|
|
|
+ if (fattr->cf_eof == 0) {
|
|
|
+ fattr->cf_mode |= S_IFIFO;
|
|
|
+ fattr->cf_dtype = DT_FIFO;
|
|
|
return 0;
|
|
|
- } else if (size < 8) {
|
|
|
+ } else if (fattr->cf_eof < 8) {
|
|
|
+ fattr->cf_mode |= S_IFREG;
|
|
|
+ fattr->cf_dtype = DT_REG;
|
|
|
return -EINVAL; /* EOPNOTSUPP? */
|
|
|
}
|
|
|
|
|
@@ -331,42 +304,46 @@ static int decode_sfu_inode(struct inode *inode, __u64 size,
|
|
|
if (rc == 0) {
|
|
|
int buf_type = CIFS_NO_BUFFER;
|
|
|
/* Read header */
|
|
|
- rc = CIFSSMBRead(xid, pTcon,
|
|
|
- netfid,
|
|
|
+ rc = CIFSSMBRead(xid, pTcon, netfid,
|
|
|
24 /* length */, 0 /* offset */,
|
|
|
&bytes_read, &pbuf, &buf_type);
|
|
|
if ((rc == 0) && (bytes_read >= 8)) {
|
|
|
if (memcmp("IntxBLK", pbuf, 8) == 0) {
|
|
|
cFYI(1, ("Block device"));
|
|
|
- inode->i_mode |= S_IFBLK;
|
|
|
+ fattr->cf_mode |= S_IFBLK;
|
|
|
+ fattr->cf_dtype = DT_BLK;
|
|
|
if (bytes_read == 24) {
|
|
|
/* we have enough to decode dev num */
|
|
|
__u64 mjr; /* major */
|
|
|
__u64 mnr; /* minor */
|
|
|
mjr = le64_to_cpu(*(__le64 *)(pbuf+8));
|
|
|
mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
|
|
|
- inode->i_rdev = MKDEV(mjr, mnr);
|
|
|
+ fattr->cf_rdev = MKDEV(mjr, mnr);
|
|
|
}
|
|
|
} else if (memcmp("IntxCHR", pbuf, 8) == 0) {
|
|
|
cFYI(1, ("Char device"));
|
|
|
- inode->i_mode |= S_IFCHR;
|
|
|
+ fattr->cf_mode |= S_IFCHR;
|
|
|
+ fattr->cf_dtype = DT_CHR;
|
|
|
if (bytes_read == 24) {
|
|
|
/* we have enough to decode dev num */
|
|
|
__u64 mjr; /* major */
|
|
|
__u64 mnr; /* minor */
|
|
|
mjr = le64_to_cpu(*(__le64 *)(pbuf+8));
|
|
|
mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
|
|
|
- inode->i_rdev = MKDEV(mjr, mnr);
|
|
|
+ fattr->cf_rdev = MKDEV(mjr, mnr);
|
|
|
}
|
|
|
} else if (memcmp("IntxLNK", pbuf, 7) == 0) {
|
|
|
cFYI(1, ("Symlink"));
|
|
|
- inode->i_mode |= S_IFLNK;
|
|
|
+ fattr->cf_mode |= S_IFLNK;
|
|
|
+ fattr->cf_dtype = DT_LNK;
|
|
|
} else {
|
|
|
- inode->i_mode |= S_IFREG; /* file? */
|
|
|
+ fattr->cf_mode |= S_IFREG; /* file? */
|
|
|
+ fattr->cf_dtype = DT_REG;
|
|
|
rc = -EOPNOTSUPP;
|
|
|
}
|
|
|
} else {
|
|
|
- inode->i_mode |= S_IFREG; /* then it is a file */
|
|
|
+ fattr->cf_mode |= S_IFREG; /* then it is a file */
|
|
|
+ fattr->cf_dtype = DT_REG;
|
|
|
rc = -EOPNOTSUPP; /* or some unknown SFU type */
|
|
|
}
|
|
|
CIFSSMBClose(xid, pTcon, netfid);
|
|
@@ -376,9 +353,13 @@ static int decode_sfu_inode(struct inode *inode, __u64 size,
|
|
|
|
|
|
#define SFBITS_MASK (S_ISVTX | S_ISGID | S_ISUID) /* SETFILEBITS valid bits */
|
|
|
|
|
|
-static int get_sfu_mode(struct inode *inode,
|
|
|
- const unsigned char *path,
|
|
|
- struct cifs_sb_info *cifs_sb, int xid)
|
|
|
+/*
|
|
|
+ * Fetch mode bits as provided by SFU.
|
|
|
+ *
|
|
|
+ * FIXME: Doesn't this clobber the type bit we got from cifs_sfu_type ?
|
|
|
+ */
|
|
|
+static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path,
|
|
|
+ struct cifs_sb_info *cifs_sb, int xid)
|
|
|
{
|
|
|
#ifdef CONFIG_CIFS_XATTR
|
|
|
ssize_t rc;
|
|
@@ -386,68 +367,80 @@ static int get_sfu_mode(struct inode *inode,
|
|
|
__u32 mode;
|
|
|
|
|
|
rc = CIFSSMBQueryEA(xid, cifs_sb->tcon, path, "SETFILEBITS",
|
|
|
- ea_value, 4 /* size of buf */, cifs_sb->local_nls,
|
|
|
- cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
|
|
|
+ ea_value, 4 /* size of buf */, cifs_sb->local_nls,
|
|
|
+ cifs_sb->mnt_cifs_flags &
|
|
|
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
|
|
|
if (rc < 0)
|
|
|
return (int)rc;
|
|
|
else if (rc > 3) {
|
|
|
mode = le32_to_cpu(*((__le32 *)ea_value));
|
|
|
- inode->i_mode &= ~SFBITS_MASK;
|
|
|
- cFYI(1, ("special bits 0%o org mode 0%o", mode, inode->i_mode));
|
|
|
- inode->i_mode = (mode & SFBITS_MASK) | inode->i_mode;
|
|
|
+ fattr->cf_mode &= ~SFBITS_MASK;
|
|
|
+ cFYI(1, ("special bits 0%o org mode 0%o", mode,
|
|
|
+ fattr->cf_mode));
|
|
|
+ fattr->cf_mode = (mode & SFBITS_MASK) | fattr->cf_mode;
|
|
|
cFYI(1, ("special mode bits 0%o", mode));
|
|
|
- return 0;
|
|
|
- } else {
|
|
|
- return 0;
|
|
|
}
|
|
|
+
|
|
|
+ return 0;
|
|
|
#else
|
|
|
return -EOPNOTSUPP;
|
|
|
#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)
|
|
|
+/* Fill a cifs_fattr struct with info from FILE_ALL_INFO */
|
|
|
+void
|
|
|
+cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
|
|
|
+ struct cifs_sb_info *cifs_sb, bool adjust_tz)
|
|
|
{
|
|
|
- memset(pfnd_dat, 0, sizeof(FILE_ALL_INFO));
|
|
|
-
|
|
|
-/* __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);
|
|
|
+ memset(fattr, 0, sizeof(*fattr));
|
|
|
+ fattr->cf_cifsattrs = le32_to_cpu(info->Attributes);
|
|
|
+ if (info->DeletePending)
|
|
|
+ fattr->cf_flags |= CIFS_FATTR_DELETE_PENDING;
|
|
|
+
|
|
|
+ if (info->LastAccessTime)
|
|
|
+ fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime);
|
|
|
+ else
|
|
|
+ fattr->cf_atime = CURRENT_TIME;
|
|
|
+
|
|
|
+ fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime);
|
|
|
+ fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime);
|
|
|
+
|
|
|
+ if (adjust_tz) {
|
|
|
+ fattr->cf_ctime.tv_sec += cifs_sb->tcon->ses->server->timeAdj;
|
|
|
+ fattr->cf_mtime.tv_sec += cifs_sb->tcon->ses->server->timeAdj;
|
|
|
+ }
|
|
|
+
|
|
|
+ fattr->cf_eof = le64_to_cpu(info->EndOfFile);
|
|
|
+ fattr->cf_bytes = le64_to_cpu(info->AllocationSize);
|
|
|
+
|
|
|
+ if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
|
|
|
+ fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode;
|
|
|
+ fattr->cf_dtype = DT_DIR;
|
|
|
+ } else {
|
|
|
+ fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode;
|
|
|
+ fattr->cf_dtype = DT_REG;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* clear write bits if ATTR_READONLY is set */
|
|
|
+ if (fattr->cf_cifsattrs & ATTR_READONLY)
|
|
|
+ fattr->cf_mode &= ~(S_IWUGO);
|
|
|
+
|
|
|
+ fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks);
|
|
|
+
|
|
|
+ fattr->cf_uid = cifs_sb->mnt_uid;
|
|
|
+ fattr->cf_gid = cifs_sb->mnt_gid;
|
|
|
}
|
|
|
|
|
|
int cifs_get_inode_info(struct inode **pinode,
|
|
|
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;
|
|
|
+ int rc = 0, tmprc;
|
|
|
struct cifsTconInfo *pTcon;
|
|
|
- struct inode *inode;
|
|
|
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
|
|
|
char *buf = NULL;
|
|
|
bool adjustTZ = false;
|
|
|
- bool is_dfs_referral = false;
|
|
|
- umode_t default_mode;
|
|
|
+ struct cifs_fattr fattr;
|
|
|
|
|
|
pTcon = cifs_sb->tcon;
|
|
|
cFYI(1, ("Getting info on %s", full_path));
|
|
@@ -482,163 +475,82 @@ int cifs_get_inode_info(struct inode **pinode,
|
|
|
adjustTZ = true;
|
|
|
}
|
|
|
}
|
|
|
- /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */
|
|
|
- if (rc == -EREMOTE) {
|
|
|
- is_dfs_referral = true;
|
|
|
- fill_fake_finddata(pfindData, sb);
|
|
|
+
|
|
|
+ if (!rc) {
|
|
|
+ cifs_all_info_to_fattr(&fattr, (FILE_ALL_INFO *) pfindData,
|
|
|
+ cifs_sb, adjustTZ);
|
|
|
+ } else if (rc == -EREMOTE) {
|
|
|
+ cifs_create_dfs_fattr(&fattr, sb);
|
|
|
rc = 0;
|
|
|
- } else if (rc)
|
|
|
+ } else {
|
|
|
goto cgii_exit;
|
|
|
+ }
|
|
|
|
|
|
- attr = le32_to_cpu(pfindData->Attributes);
|
|
|
-
|
|
|
- /* get new inode */
|
|
|
+ /*
|
|
|
+ * If an inode wasn't passed in, then get the inode number
|
|
|
+ *
|
|
|
+ * Is an i_ino of zero legal? Can we use that to check if the server
|
|
|
+ * supports returning inode numbers? Are there other sanity checks we
|
|
|
+ * can use to ensure that the server is really filling in that field?
|
|
|
+ *
|
|
|
+ * We can not use the IndexNumber field by default from Windows or
|
|
|
+ * Samba (in ALL_INFO buf) but we can request it explicitly. The SNIA
|
|
|
+ * CIFS spec claims that this value is unique within the scope of a
|
|
|
+ * share, and the windows docs hint that it's actually unique
|
|
|
+ * per-machine.
|
|
|
+ *
|
|
|
+ * There may be higher info levels that work but are there Windows
|
|
|
+ * server or network appliances for which IndexNumber field is not
|
|
|
+ * guaranteed unique?
|
|
|
+ */
|
|
|
if (*pinode == NULL) {
|
|
|
- __u64 inode_num;
|
|
|
- __u64 *pinum = &inode_num;
|
|
|
-
|
|
|
- /* Is an i_ino of zero legal? Can we use that to check
|
|
|
- if the server supports returning inode numbers? Are
|
|
|
- there other sanity checks we can use to ensure that
|
|
|
- the server is really filling in that field? */
|
|
|
-
|
|
|
- /* 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 */
|
|
|
-
|
|
|
- /* There may be higher info levels that work but are
|
|
|
- there Windows server or network appliances for which
|
|
|
- IndexNumber field is not guaranteed unique? */
|
|
|
-
|
|
|
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
|
|
|
int rc1 = 0;
|
|
|
|
|
|
rc1 = CIFSGetSrvInodeNumber(xid, pTcon,
|
|
|
- full_path, pinum,
|
|
|
+ full_path, &fattr.cf_uniqueid,
|
|
|
cifs_sb->local_nls,
|
|
|
cifs_sb->mnt_cifs_flags &
|
|
|
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
|
|
if (rc1) {
|
|
|
- cFYI(1, ("GetSrvInodeNum rc %d", rc1));
|
|
|
- pinum = NULL;
|
|
|
/* BB EOPNOSUPP disable SERVER_INUM? */
|
|
|
+ cFYI(1, ("GetSrvInodeNum rc %d", rc1));
|
|
|
+ fattr.cf_uniqueid = iunique(sb, ROOT_I);
|
|
|
}
|
|
|
} else {
|
|
|
- pinum = NULL;
|
|
|
+ fattr.cf_uniqueid = iunique(sb, ROOT_I);
|
|
|
}
|
|
|
-
|
|
|
- *pinode = cifs_new_inode(sb, pinum);
|
|
|
- if (*pinode == NULL) {
|
|
|
- rc = -ENOMEM;
|
|
|
- goto cgii_exit;
|
|
|
- }
|
|
|
- }
|
|
|
- inode = *pinode;
|
|
|
- cifsInfo = CIFS_I(inode);
|
|
|
- cifsInfo->cifsAttrs = attr;
|
|
|
- cifsInfo->delete_pending = pfindData->DeletePending ? true : false;
|
|
|
- cFYI(1, ("Old time %ld", cifsInfo->time));
|
|
|
- cifsInfo->time = jiffies;
|
|
|
- cFYI(1, ("New time %ld", cifsInfo->time));
|
|
|
-
|
|
|
- /* blksize needs to be multiple of two. So safer to default to
|
|
|
- blksize and blkbits set in superblock so 2**blkbits and blksize
|
|
|
- will match rather than setting to:
|
|
|
- (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
|
|
|
-
|
|
|
- /* Linux can not store file creation time so ignore it */
|
|
|
- if (pfindData->LastAccessTime)
|
|
|
- inode->i_atime = cifs_NTtimeToUnix(pfindData->LastAccessTime);
|
|
|
- else /* do not need to use current_fs_time - time not stored */
|
|
|
- inode->i_atime = CURRENT_TIME;
|
|
|
- inode->i_mtime = cifs_NTtimeToUnix(pfindData->LastWriteTime);
|
|
|
- inode->i_ctime = cifs_NTtimeToUnix(pfindData->ChangeTime);
|
|
|
- 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;
|
|
|
- }
|
|
|
-
|
|
|
- /* get default inode mode */
|
|
|
- if (attr & ATTR_DIRECTORY)
|
|
|
- default_mode = cifs_sb->mnt_dir_mode;
|
|
|
- else
|
|
|
- default_mode = cifs_sb->mnt_file_mode;
|
|
|
-
|
|
|
- /* set permission bits */
|
|
|
- if (atomic_read(&cifsInfo->inUse) == 0 ||
|
|
|
- (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0)
|
|
|
- inode->i_mode = default_mode;
|
|
|
- else {
|
|
|
- /* just reenable write bits if !ATTR_READONLY */
|
|
|
- if ((inode->i_mode & S_IWUGO) == 0 &&
|
|
|
- (attr & ATTR_READONLY) == 0)
|
|
|
- inode->i_mode |= (S_IWUGO & default_mode);
|
|
|
-
|
|
|
- inode->i_mode &= ~S_IFMT;
|
|
|
- }
|
|
|
- /* clear write bits if ATTR_READONLY is set */
|
|
|
- if (attr & ATTR_READONLY)
|
|
|
- inode->i_mode &= ~S_IWUGO;
|
|
|
-
|
|
|
- /* set inode type */
|
|
|
- if ((attr & ATTR_SYSTEM) &&
|
|
|
- (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) {
|
|
|
- /* no need to fix endianness on 0 */
|
|
|
- if (pfindData->EndOfFile == 0)
|
|
|
- inode->i_mode |= S_IFIFO;
|
|
|
- else if (decode_sfu_inode(inode,
|
|
|
- le64_to_cpu(pfindData->EndOfFile),
|
|
|
- full_path, cifs_sb, xid))
|
|
|
- cFYI(1, ("unknown SFU file type\n"));
|
|
|
} else {
|
|
|
- if (attr & ATTR_DIRECTORY)
|
|
|
- inode->i_mode |= S_IFDIR;
|
|
|
- else
|
|
|
- inode->i_mode |= S_IFREG;
|
|
|
+ fattr.cf_uniqueid = CIFS_I(*pinode)->uniqueid;
|
|
|
}
|
|
|
|
|
|
- cifsInfo->server_eof = le64_to_cpu(pfindData->EndOfFile);
|
|
|
- spin_lock(&inode->i_lock);
|
|
|
- if (is_size_safe_to_change(cifsInfo, cifsInfo->server_eof)) {
|
|
|
- /* can not safely shrink the file size here if the
|
|
|
- client is writing to it due to potential races */
|
|
|
- i_size_write(inode, cifsInfo->server_eof);
|
|
|
-
|
|
|
- /* 512 bytes (2**9) is the fake blocksize that must be
|
|
|
- used for this calculation */
|
|
|
- inode->i_blocks = (512 - 1 + le64_to_cpu(
|
|
|
- pfindData->AllocationSize)) >> 9;
|
|
|
+ /* query for SFU type info if supported and needed */
|
|
|
+ if (fattr.cf_cifsattrs & ATTR_SYSTEM &&
|
|
|
+ cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
|
|
|
+ tmprc = cifs_sfu_type(&fattr, full_path, cifs_sb, xid);
|
|
|
+ if (tmprc)
|
|
|
+ cFYI(1, ("cifs_sfu_type failed: %d", tmprc));
|
|
|
}
|
|
|
- spin_unlock(&inode->i_lock);
|
|
|
|
|
|
- inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks);
|
|
|
-
|
|
|
- /* BB fill in uid and gid here? with help from winbind?
|
|
|
- or retrieve from NTFS stream extended attribute */
|
|
|
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
|
|
/* 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(cifs_sb, inode, full_path, pfid);
|
|
|
+ cifs_acl_to_fattr(cifs_sb, &fattr, *pinode, 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, 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;
|
|
|
- /* set so we do not keep refreshing these fields with
|
|
|
- bad data after user has changed them in memory */
|
|
|
- atomic_set(&cifsInfo->inUse, 1);
|
|
|
- }
|
|
|
-
|
|
|
- cifs_set_ops(inode, is_dfs_referral);
|
|
|
-
|
|
|
|
|
|
+ /* fill in remaining high mode bits e.g. SUID, VTX */
|
|
|
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)
|
|
|
+ cifs_sfu_mode(&fattr, full_path, cifs_sb, xid);
|
|
|
|
|
|
+ if (!*pinode) {
|
|
|
+ *pinode = cifs_iget(sb, &fattr);
|
|
|
+ if (!*pinode)
|
|
|
+ rc = -ENOMEM;
|
|
|
+ } else {
|
|
|
+ cifs_fattr_to_inode(*pinode, &fattr);
|
|
|
+ }
|
|
|
|
|
|
cgii_exit:
|
|
|
kfree(buf);
|
|
@@ -753,21 +665,14 @@ struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino)
|
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
|
|
xid = GetXid();
|
|
|
- if (cifs_sb->tcon->unix_ext) {
|
|
|
+ if (cifs_sb->tcon->unix_ext)
|
|
|
rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid);
|
|
|
- if (!inode)
|
|
|
- return ERR_PTR(-ENOMEM);
|
|
|
- } else {
|
|
|
- inode = iget_locked(sb, ino);
|
|
|
- if (!inode)
|
|
|
- return ERR_PTR(-ENOMEM);
|
|
|
- if (!(inode->i_state & I_NEW))
|
|
|
- return inode;
|
|
|
-
|
|
|
- rc = cifs_get_inode_info(&inode, full_path, NULL, inode->i_sb,
|
|
|
+ else
|
|
|
+ rc = cifs_get_inode_info(&inode, full_path, NULL, sb,
|
|
|
xid, NULL);
|
|
|
- unlock_new_inode(inode);
|
|
|
- }
|
|
|
+
|
|
|
+ if (!inode)
|
|
|
+ return ERR_PTR(-ENOMEM);
|
|
|
|
|
|
if (rc && cifs_sb->tcon->ipc) {
|
|
|
cFYI(1, ("ipc connection - fake read inode"));
|