|
@@ -1,7 +1,7 @@
|
|
|
/*
|
|
|
* fs/cifs/inode.c
|
|
|
*
|
|
|
- * Copyright (C) International Business Machines Corp., 2002,2005
|
|
|
+ * Copyright (C) International Business Machines Corp., 2002,2007
|
|
|
* Author(s): Steve French (sfrench@us.ibm.com)
|
|
|
*
|
|
|
* This library is free software; you can redistribute it and/or modify
|
|
@@ -90,7 +90,7 @@ int cifs_get_inode_info_unix(struct inode **pinode,
|
|
|
(*pinode)->i_ino =
|
|
|
(unsigned long)findData.UniqueId;
|
|
|
} /* note ino incremented to unique num in new_inode */
|
|
|
- if(sb->s_flags & MS_NOATIME)
|
|
|
+ if (sb->s_flags & MS_NOATIME)
|
|
|
(*pinode)->i_flags |= S_NOATIME | S_NOCMTIME;
|
|
|
|
|
|
insert_inode_hash(*pinode);
|
|
@@ -139,8 +139,17 @@ int cifs_get_inode_info_unix(struct inode **pinode,
|
|
|
inode->i_mode |= S_IFREG;
|
|
|
cFYI(1,("unknown type %d",type));
|
|
|
}
|
|
|
- inode->i_uid = le64_to_cpu(findData.Uid);
|
|
|
- inode->i_gid = le64_to_cpu(findData.Gid);
|
|
|
+
|
|
|
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)
|
|
|
+ inode->i_uid = cifs_sb->mnt_uid;
|
|
|
+ else
|
|
|
+ inode->i_uid = le64_to_cpu(findData.Uid);
|
|
|
+
|
|
|
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)
|
|
|
+ inode->i_gid = cifs_sb->mnt_gid;
|
|
|
+ else
|
|
|
+ inode->i_gid = le64_to_cpu(findData.Gid);
|
|
|
+
|
|
|
inode->i_nlink = le64_to_cpu(findData.Nlinks);
|
|
|
|
|
|
spin_lock(&inode->i_lock);
|
|
@@ -178,13 +187,13 @@ int cifs_get_inode_info_unix(struct inode **pinode,
|
|
|
&cifs_file_direct_nobrl_ops;
|
|
|
else
|
|
|
inode->i_fop = &cifs_file_direct_ops;
|
|
|
- } else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
|
|
|
+ } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
|
|
|
inode->i_fop = &cifs_file_nobrl_ops;
|
|
|
else /* not direct, send byte range locks */
|
|
|
inode->i_fop = &cifs_file_ops;
|
|
|
|
|
|
/* check if server can support readpages */
|
|
|
- if(pTcon->ses->server->maxBuf <
|
|
|
+ if (pTcon->ses->server->maxBuf <
|
|
|
PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)
|
|
|
inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
|
|
|
else
|
|
@@ -220,7 +229,7 @@ static int decode_sfu_inode(struct inode * inode, __u64 size,
|
|
|
|
|
|
pbuf = buf;
|
|
|
|
|
|
- if(size == 0) {
|
|
|
+ if (size == 0) {
|
|
|
inode->i_mode |= S_IFIFO;
|
|
|
return 0;
|
|
|
} else if (size < 8) {
|
|
@@ -239,11 +248,11 @@ static int decode_sfu_inode(struct inode * inode, __u64 size,
|
|
|
netfid,
|
|
|
24 /* length */, 0 /* offset */,
|
|
|
&bytes_read, &pbuf, &buf_type);
|
|
|
- if((rc == 0) && (bytes_read >= 8)) {
|
|
|
- if(memcmp("IntxBLK", pbuf, 8) == 0) {
|
|
|
+ if ((rc == 0) && (bytes_read >= 8)) {
|
|
|
+ if (memcmp("IntxBLK", pbuf, 8) == 0) {
|
|
|
cFYI(1,("Block device"));
|
|
|
inode->i_mode |= S_IFBLK;
|
|
|
- if(bytes_read == 24) {
|
|
|
+ if (bytes_read == 24) {
|
|
|
/* we have enough to decode dev num */
|
|
|
__u64 mjr; /* major */
|
|
|
__u64 mnr; /* minor */
|
|
@@ -251,10 +260,10 @@ static int decode_sfu_inode(struct inode * inode, __u64 size,
|
|
|
mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
|
|
|
inode->i_rdev = MKDEV(mjr, mnr);
|
|
|
}
|
|
|
- } else if(memcmp("IntxCHR", pbuf, 8) == 0) {
|
|
|
+ } else if (memcmp("IntxCHR", pbuf, 8) == 0) {
|
|
|
cFYI(1,("Char device"));
|
|
|
inode->i_mode |= S_IFCHR;
|
|
|
- if(bytes_read == 24) {
|
|
|
+ if (bytes_read == 24) {
|
|
|
/* we have enough to decode dev num */
|
|
|
__u64 mjr; /* major */
|
|
|
__u64 mnr; /* minor */
|
|
@@ -262,7 +271,7 @@ static int decode_sfu_inode(struct inode * inode, __u64 size,
|
|
|
mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
|
|
|
inode->i_rdev = MKDEV(mjr, mnr);
|
|
|
}
|
|
|
- } else if(memcmp("IntxLNK", pbuf, 7) == 0) {
|
|
|
+ } else if (memcmp("IntxLNK", pbuf, 7) == 0) {
|
|
|
cFYI(1,("Symlink"));
|
|
|
inode->i_mode |= S_IFLNK;
|
|
|
} else {
|
|
@@ -293,7 +302,7 @@ static int get_sfu_uid_mode(struct inode * inode,
|
|
|
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);
|
|
|
- if(rc < 0)
|
|
|
+ if (rc < 0)
|
|
|
return (int)rc;
|
|
|
else if (rc > 3) {
|
|
|
mode = le32_to_cpu(*((__le32 *)ea_value));
|
|
@@ -348,7 +357,7 @@ int cifs_get_inode_info(struct inode **pinode,
|
|
|
/* 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 in tcon or mount */
|
|
|
- if((rc == -EOPNOTSUPP) || (rc == -EINVAL)) {
|
|
|
+ if ((rc == -EOPNOTSUPP) || (rc == -EINVAL)) {
|
|
|
rc = SMBQueryInformation(xid, pTcon, search_path,
|
|
|
pfindData, cifs_sb->local_nls,
|
|
|
cifs_sb->mnt_cifs_flags &
|
|
@@ -425,7 +434,7 @@ int cifs_get_inode_info(struct inode **pinode,
|
|
|
} else /* do we need cast or hash to ino? */
|
|
|
(*pinode)->i_ino = inode_num;
|
|
|
} /* else ino incremented to unique num in new_inode*/
|
|
|
- if(sb->s_flags & MS_NOATIME)
|
|
|
+ if (sb->s_flags & MS_NOATIME)
|
|
|
(*pinode)->i_flags |= S_NOATIME | S_NOCMTIME;
|
|
|
insert_inode_hash(*pinode);
|
|
|
}
|
|
@@ -442,7 +451,7 @@ int cifs_get_inode_info(struct inode **pinode,
|
|
|
(pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
|
|
|
|
|
|
/* Linux can not store file creation time so ignore it */
|
|
|
- if(pfindData->LastAccessTime)
|
|
|
+ if (pfindData->LastAccessTime)
|
|
|
inode->i_atime = cifs_NTtimeToUnix
|
|
|
(le64_to_cpu(pfindData->LastAccessTime));
|
|
|
else /* do not need to use current_fs_time - time not stored */
|
|
@@ -452,7 +461,7 @@ int cifs_get_inode_info(struct inode **pinode,
|
|
|
inode->i_ctime =
|
|
|
cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
|
|
|
cFYI(0, ("Attributes came in as 0x%x", attr));
|
|
|
- if(adjustTZ && (pTcon->ses) && (pTcon->ses->server)) {
|
|
|
+ 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;
|
|
|
}
|
|
@@ -521,8 +530,10 @@ int cifs_get_inode_info(struct inode **pinode,
|
|
|
|
|
|
/* BB fill in uid and gid here? with help from winbind?
|
|
|
or retrieve from NTFS stream extended attribute */
|
|
|
- if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
|
|
|
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
|
|
|
/* fill in uid, gid, mode from server ACL */
|
|
|
+ /* BB FIXME this should also take into account the
|
|
|
+ * default uid specified on mount if present */
|
|
|
get_sfu_uid_mode(inode, search_path, cifs_sb, xid);
|
|
|
} else if (atomic_read(&cifsInfo->inUse) == 0) {
|
|
|
inode->i_uid = cifs_sb->mnt_uid;
|
|
@@ -541,12 +552,12 @@ int cifs_get_inode_info(struct inode **pinode,
|
|
|
&cifs_file_direct_nobrl_ops;
|
|
|
else
|
|
|
inode->i_fop = &cifs_file_direct_ops;
|
|
|
- } else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
|
|
|
+ } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
|
|
|
inode->i_fop = &cifs_file_nobrl_ops;
|
|
|
else /* not direct, send byte range locks */
|
|
|
inode->i_fop = &cifs_file_ops;
|
|
|
|
|
|
- if(pTcon->ses->server->maxBuf <
|
|
|
+ if (pTcon->ses->server->maxBuf <
|
|
|
PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)
|
|
|
inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
|
|
|
else
|
|
@@ -597,7 +608,7 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
|
|
|
|
|
|
xid = GetXid();
|
|
|
|
|
|
- if(inode)
|
|
|
+ if (inode)
|
|
|
cifs_sb = CIFS_SB(inode->i_sb);
|
|
|
else
|
|
|
cifs_sb = CIFS_SB(direntry->d_sb);
|
|
@@ -723,7 +734,7 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
|
|
|
when needed */
|
|
|
direntry->d_inode->i_ctime = current_fs_time(inode->i_sb);
|
|
|
}
|
|
|
- if(inode) {
|
|
|
+ if (inode) {
|
|
|
inode->i_ctime = inode->i_mtime = current_fs_time(inode->i_sb);
|
|
|
cifsInode = CIFS_I(inode);
|
|
|
cifsInode->time = 0; /* force revalidate of dir as well */
|
|
@@ -734,6 +745,136 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
+static void posix_fill_in_inode(struct inode *tmp_inode,
|
|
|
+ FILE_UNIX_BASIC_INFO *pData, int *pobject_type, int isNewInode)
|
|
|
+{
|
|
|
+ loff_t local_size;
|
|
|
+ struct timespec local_mtime;
|
|
|
+
|
|
|
+ struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
|
|
|
+ struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);
|
|
|
+
|
|
|
+ __u32 type = le32_to_cpu(pData->Type);
|
|
|
+ __u64 num_of_bytes = le64_to_cpu(pData->NumOfBytes);
|
|
|
+ __u64 end_of_file = le64_to_cpu(pData->EndOfFile);
|
|
|
+ cifsInfo->time = jiffies;
|
|
|
+ atomic_inc(&cifsInfo->inUse);
|
|
|
+
|
|
|
+ /* save mtime and size */
|
|
|
+ local_mtime = tmp_inode->i_mtime;
|
|
|
+ local_size = tmp_inode->i_size;
|
|
|
+
|
|
|
+ tmp_inode->i_atime =
|
|
|
+ cifs_NTtimeToUnix(le64_to_cpu(pData->LastAccessTime));
|
|
|
+ tmp_inode->i_mtime =
|
|
|
+ cifs_NTtimeToUnix(le64_to_cpu(pData->LastModificationTime));
|
|
|
+ tmp_inode->i_ctime =
|
|
|
+ cifs_NTtimeToUnix(le64_to_cpu(pData->LastStatusChange));
|
|
|
+
|
|
|
+ tmp_inode->i_mode = le64_to_cpu(pData->Permissions);
|
|
|
+ /* since we set the inode type below we need to mask off type
|
|
|
+ to avoid strange results if bits above were corrupt */
|
|
|
+ tmp_inode->i_mode &= ~S_IFMT;
|
|
|
+ if (type == UNIX_FILE) {
|
|
|
+ *pobject_type = DT_REG;
|
|
|
+ tmp_inode->i_mode |= S_IFREG;
|
|
|
+ } else if (type == UNIX_SYMLINK) {
|
|
|
+ *pobject_type = DT_LNK;
|
|
|
+ tmp_inode->i_mode |= S_IFLNK;
|
|
|
+ } else if (type == UNIX_DIR) {
|
|
|
+ *pobject_type = DT_DIR;
|
|
|
+ tmp_inode->i_mode |= S_IFDIR;
|
|
|
+ } else if (type == UNIX_CHARDEV) {
|
|
|
+ *pobject_type = DT_CHR;
|
|
|
+ tmp_inode->i_mode |= S_IFCHR;
|
|
|
+ tmp_inode->i_rdev = MKDEV(le64_to_cpu(pData->DevMajor),
|
|
|
+ le64_to_cpu(pData->DevMinor) & MINORMASK);
|
|
|
+ } else if (type == UNIX_BLOCKDEV) {
|
|
|
+ *pobject_type = DT_BLK;
|
|
|
+ tmp_inode->i_mode |= S_IFBLK;
|
|
|
+ tmp_inode->i_rdev = MKDEV(le64_to_cpu(pData->DevMajor),
|
|
|
+ le64_to_cpu(pData->DevMinor) & MINORMASK);
|
|
|
+ } else if (type == UNIX_FIFO) {
|
|
|
+ *pobject_type = DT_FIFO;
|
|
|
+ tmp_inode->i_mode |= S_IFIFO;
|
|
|
+ } else if (type == UNIX_SOCKET) {
|
|
|
+ *pobject_type = DT_SOCK;
|
|
|
+ tmp_inode->i_mode |= S_IFSOCK;
|
|
|
+ } else {
|
|
|
+ /* safest to just call it a file */
|
|
|
+ *pobject_type = DT_REG;
|
|
|
+ tmp_inode->i_mode |= S_IFREG;
|
|
|
+ cFYI(1,("unknown inode type %d",type));
|
|
|
+ }
|
|
|
+
|
|
|
+#ifdef CONFIG_CIFS_DEBUG2
|
|
|
+ cFYI(1,("object type: %d", type));
|
|
|
+#endif
|
|
|
+ tmp_inode->i_uid = le64_to_cpu(pData->Uid);
|
|
|
+ tmp_inode->i_gid = le64_to_cpu(pData->Gid);
|
|
|
+ tmp_inode->i_nlink = le64_to_cpu(pData->Nlinks);
|
|
|
+
|
|
|
+ spin_lock(&tmp_inode->i_lock);
|
|
|
+ if (is_size_safe_to_change(cifsInfo, end_of_file)) {
|
|
|
+ /* can not safely change the file size here if the
|
|
|
+ client is writing to it due to potential races */
|
|
|
+ i_size_write(tmp_inode, end_of_file);
|
|
|
+
|
|
|
+ /* 512 bytes (2**9) is the fake blocksize that must be used */
|
|
|
+ /* for this calculation, not the real blocksize */
|
|
|
+ tmp_inode->i_blocks = (512 - 1 + num_of_bytes) >> 9;
|
|
|
+ }
|
|
|
+ spin_unlock(&tmp_inode->i_lock);
|
|
|
+
|
|
|
+ if (S_ISREG(tmp_inode->i_mode)) {
|
|
|
+ cFYI(1, ("File inode"));
|
|
|
+ tmp_inode->i_op = &cifs_file_inode_ops;
|
|
|
+
|
|
|
+ if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
|
|
|
+ if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
|
|
|
+ tmp_inode->i_fop = &cifs_file_direct_nobrl_ops;
|
|
|
+ else
|
|
|
+ tmp_inode->i_fop = &cifs_file_direct_ops;
|
|
|
+
|
|
|
+ } else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
|
|
|
+ tmp_inode->i_fop = &cifs_file_nobrl_ops;
|
|
|
+ else
|
|
|
+ tmp_inode->i_fop = &cifs_file_ops;
|
|
|
+
|
|
|
+ if((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
|
|
|
+ (cifs_sb->tcon->ses->server->maxBuf <
|
|
|
+ PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE))
|
|
|
+ tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
|
|
|
+ else
|
|
|
+ tmp_inode->i_data.a_ops = &cifs_addr_ops;
|
|
|
+
|
|
|
+ if(isNewInode)
|
|
|
+ return; /* No sense invalidating pages for new inode since we
|
|
|
+ have not started caching readahead file data yet */
|
|
|
+
|
|
|
+ if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) &&
|
|
|
+ (local_size == tmp_inode->i_size)) {
|
|
|
+ cFYI(1, ("inode exists but unchanged"));
|
|
|
+ } else {
|
|
|
+ /* file may have changed on server */
|
|
|
+ cFYI(1, ("invalidate inode, readdir detected change"));
|
|
|
+ invalidate_remote_inode(tmp_inode);
|
|
|
+ }
|
|
|
+ } else if (S_ISDIR(tmp_inode->i_mode)) {
|
|
|
+ cFYI(1, ("Directory inode"));
|
|
|
+ tmp_inode->i_op = &cifs_dir_inode_ops;
|
|
|
+ tmp_inode->i_fop = &cifs_dir_ops;
|
|
|
+ } else if (S_ISLNK(tmp_inode->i_mode)) {
|
|
|
+ cFYI(1, ("Symbolic Link inode"));
|
|
|
+ tmp_inode->i_op = &cifs_symlink_inode_ops;
|
|
|
+/* tmp_inode->i_fop = *//* do not need to set to anything */
|
|
|
+ } else {
|
|
|
+ cFYI(1, ("Special inode"));
|
|
|
+ init_special_inode(tmp_inode, tmp_inode->i_mode,
|
|
|
+ tmp_inode->i_rdev);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
|
|
|
{
|
|
|
int rc = 0;
|
|
@@ -755,6 +896,71 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
|
|
|
FreeXid(xid);
|
|
|
return -ENOMEM;
|
|
|
}
|
|
|
+
|
|
|
+ if((pTcon->ses->capabilities & CAP_UNIX) &&
|
|
|
+ (CIFS_UNIX_POSIX_PATH_OPS_CAP &
|
|
|
+ le64_to_cpu(pTcon->fsUnixInfo.Capability))) {
|
|
|
+ u32 oplock = 0;
|
|
|
+ FILE_UNIX_BASIC_INFO * pInfo =
|
|
|
+ kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
|
|
|
+ if(pInfo == NULL) {
|
|
|
+ rc = -ENOMEM;
|
|
|
+ goto mkdir_out;
|
|
|
+ }
|
|
|
+
|
|
|
+ rc = CIFSPOSIXCreate(xid, pTcon, SMB_O_DIRECTORY | SMB_O_CREAT,
|
|
|
+ mode, NULL /* netfid */, pInfo, &oplock,
|
|
|
+ full_path, cifs_sb->local_nls,
|
|
|
+ cifs_sb->mnt_cifs_flags &
|
|
|
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
|
|
|
+ if (rc) {
|
|
|
+ cFYI(1, ("posix mkdir returned 0x%x", rc));
|
|
|
+ d_drop(direntry);
|
|
|
+ } else {
|
|
|
+ int obj_type;
|
|
|
+ if (pInfo->Type == -1) /* no return info - go query */
|
|
|
+ goto mkdir_get_info;
|
|
|
+/*BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if need to set uid/gid */
|
|
|
+ inc_nlink(inode);
|
|
|
+ if (pTcon->nocase)
|
|
|
+ direntry->d_op = &cifs_ci_dentry_ops;
|
|
|
+ else
|
|
|
+ direntry->d_op = &cifs_dentry_ops;
|
|
|
+
|
|
|
+ newinode = new_inode(inode->i_sb);
|
|
|
+ if (newinode == NULL)
|
|
|
+ goto mkdir_get_info;
|
|
|
+ /* Is an i_ino of zero legal? */
|
|
|
+ /* 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) {
|
|
|
+ newinode->i_ino =
|
|
|
+ (unsigned long)pInfo->UniqueId;
|
|
|
+ } /* note ino incremented to unique num in new_inode */
|
|
|
+ if(inode->i_sb->s_flags & MS_NOATIME)
|
|
|
+ newinode->i_flags |= S_NOATIME | S_NOCMTIME;
|
|
|
+ newinode->i_nlink = 2;
|
|
|
+
|
|
|
+ insert_inode_hash(newinode);
|
|
|
+ d_instantiate(direntry, newinode);
|
|
|
+
|
|
|
+ /* we already checked in POSIXCreate whether
|
|
|
+ frame was long enough */
|
|
|
+ posix_fill_in_inode(direntry->d_inode,
|
|
|
+ pInfo, &obj_type, 1 /* NewInode */);
|
|
|
+#ifdef CONFIG_CIFS_DEBUG2
|
|
|
+ cFYI(1,("instantiated dentry %p %s to inode %p",
|
|
|
+ direntry, direntry->d_name.name, newinode));
|
|
|
+
|
|
|
+ if(newinode->i_nlink != 2)
|
|
|
+ cFYI(1,("unexpected number of links %d",
|
|
|
+ newinode->i_nlink));
|
|
|
+#endif
|
|
|
+ }
|
|
|
+ kfree(pInfo);
|
|
|
+ goto mkdir_out;
|
|
|
+ }
|
|
|
+
|
|
|
/* BB add setting the equivalent of mode via CreateX w/ACLs */
|
|
|
rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls,
|
|
|
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
|
|
@@ -762,6 +968,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
|
|
|
cFYI(1, ("cifs_mkdir returned 0x%x", rc));
|
|
|
d_drop(direntry);
|
|
|
} else {
|
|
|
+mkdir_get_info:
|
|
|
inc_nlink(inode);
|
|
|
if (pTcon->ses->capabilities & CAP_UNIX)
|
|
|
rc = cifs_get_inode_info_unix(&newinode, full_path,
|
|
@@ -775,8 +982,10 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
|
|
|
else
|
|
|
direntry->d_op = &cifs_dentry_ops;
|
|
|
d_instantiate(direntry, newinode);
|
|
|
- if (direntry->d_inode)
|
|
|
- direntry->d_inode->i_nlink = 2;
|
|
|
+ /* setting nlink not necessary except in cases where we
|
|
|
+ * failed to get it from the server or was set bogus */
|
|
|
+ if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2))
|
|
|
+ direntry->d_inode->i_nlink = 2;
|
|
|
if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
|
|
|
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
|
|
|
CIFSSMBUnixSetPerms(xid, pTcon, full_path,
|
|
@@ -812,6 +1021,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+mkdir_out:
|
|
|
kfree(full_path);
|
|
|
FreeXid(xid);
|
|
|
return rc;
|
|
@@ -1339,17 +1549,17 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
|
|
|
cpu_to_le32(cifsInode->cifsAttrs |
|
|
|
ATTR_READONLY);
|
|
|
}
|
|
|
- } else if ((mode & S_IWUGO) == S_IWUGO) {
|
|
|
- if (cifsInode->cifsAttrs & ATTR_READONLY) {
|
|
|
- set_dosattr = TRUE;
|
|
|
- time_buf.Attributes =
|
|
|
- cpu_to_le32(cifsInode->cifsAttrs &
|
|
|
- (~ATTR_READONLY));
|
|
|
- /* Windows ignores set to zero */
|
|
|
- if(time_buf.Attributes == 0)
|
|
|
- time_buf.Attributes |=
|
|
|
- cpu_to_le32(ATTR_NORMAL);
|
|
|
- }
|
|
|
+ } else if (cifsInode->cifsAttrs & ATTR_READONLY) {
|
|
|
+ /* If file is readonly on server, we would
|
|
|
+ not be able to write to it - so if any write
|
|
|
+ bit is enabled for user or group or other we
|
|
|
+ need to at least try to remove r/o dos attr */
|
|
|
+ set_dosattr = TRUE;
|
|
|
+ time_buf.Attributes = cpu_to_le32(cifsInode->cifsAttrs &
|
|
|
+ (~ATTR_READONLY));
|
|
|
+ /* Windows ignores set to zero */
|
|
|
+ if(time_buf.Attributes == 0)
|
|
|
+ time_buf.Attributes |= cpu_to_le32(ATTR_NORMAL);
|
|
|
}
|
|
|
/* BB to be implemented -
|
|
|
via Windows security descriptors or streams */
|