int
cifs_get_inode_info_unix(struct inode **pinode,
const unsigned char *search_path,
- struct super_block *sb)
+ struct super_block *sb,int xid)
{
- int xid;
int rc = 0;
FILE_UNIX_BASIC_INFO findData;
struct cifsTconInfo *pTcon;
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
char *tmp_path;
- xid = GetXid();
-
pTcon = cifs_sb->tcon;
cFYI(1, (" Getting info on %s ", search_path));
/* we could have done a find first instead but this returns more info */
strnlen(search_path, MAX_PATHCONF) + 1,
GFP_KERNEL);
if (tmp_path == NULL) {
- FreeXid(xid);
return -ENOMEM;
}
/* have to skip first of the double backslash of UNC name */
/* BB fix up inode etc. */
} else if (rc) {
- FreeXid(xid);
return rc;
}
} else {
struct cifsInodeInfo *cifsInfo;
+ __u32 type = le32_to_cpu(findData.Type);
+ __u64 num_of_bytes = le64_to_cpu(findData.NumOfBytes);
+ __u64 end_of_file = le64_to_cpu(findData.EndOfFile);
/* get new inode */
if (*pinode == NULL) {
*pinode = new_inode(sb);
+ if(*pinode == NULL)
+ return -ENOMEM;
+ /* 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) {
+ (*pinode)->i_ino =
+ (unsigned long)findData.UniqueId;
+ } /* note ino incremented to unique num in new_inode */
+ insert_inode_hash(*pinode);
}
+
inode = *pinode;
-
cifsInfo = CIFS_I(inode);
cFYI(1, (" Old time %ld ", cifsInfo->time));
inode->i_ctime =
cifs_NTtimeToUnix(le64_to_cpu(findData.LastStatusChange));
inode->i_mode = le64_to_cpu(findData.Permissions);
- findData.Type = le32_to_cpu(findData.Type);
- if (findData.Type == UNIX_FILE) {
+ if (type == UNIX_FILE) {
inode->i_mode |= S_IFREG;
- } else if (findData.Type == UNIX_SYMLINK) {
+ } else if (type == UNIX_SYMLINK) {
inode->i_mode |= S_IFLNK;
- } else if (findData.Type == UNIX_DIR) {
+ } else if (type == UNIX_DIR) {
inode->i_mode |= S_IFDIR;
- } else if (findData.Type == UNIX_CHARDEV) {
+ } else if (type == UNIX_CHARDEV) {
inode->i_mode |= S_IFCHR;
- } else if (findData.Type == UNIX_BLOCKDEV) {
+ inode->i_rdev = MKDEV(le64_to_cpu(findData.DevMajor),
+ le64_to_cpu(findData.DevMinor) & MINORMASK);
+ } else if (type == UNIX_BLOCKDEV) {
inode->i_mode |= S_IFBLK;
- } else if (findData.Type == UNIX_FIFO) {
+ inode->i_rdev = MKDEV(le64_to_cpu(findData.DevMajor),
+ le64_to_cpu(findData.DevMinor) & MINORMASK);
+ } else if (type == UNIX_FIFO) {
inode->i_mode |= S_IFIFO;
- } else if (findData.Type == UNIX_SOCKET) {
+ } else if (type == UNIX_SOCKET) {
inode->i_mode |= S_IFSOCK;
}
inode->i_uid = le64_to_cpu(findData.Uid);
inode->i_gid = le64_to_cpu(findData.Gid);
inode->i_nlink = le64_to_cpu(findData.Nlinks);
- findData.NumOfBytes = le64_to_cpu(findData.NumOfBytes);
- findData.EndOfFile = le64_to_cpu(findData.EndOfFile);
if(is_size_safe_to_change(cifsInfo)) {
/* can not safely change the file size here if the
client is writing to it due to potential races */
- i_size_write(inode,findData.EndOfFile);
+ i_size_write(inode, end_of_file);
/* 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 */
/* inode->i_blksize =
/* inode->i_blocks =
- (inode->i_blksize - 1 + findData.NumOfBytes) >> inode->i_blkbits;*/
+ (inode->i_blksize - 1 + num_of_bytes) >> inode->i_blkbits;*/
/* 512 bytes (2**9) is the fake blocksize that must be used */
/* for this calculation */
- inode->i_blocks = (512 - 1 + findData.NumOfBytes) >> 9;
+ inode->i_blocks = (512 - 1 + num_of_bytes) >> 9;
}
- if (findData.NumOfBytes < findData.EndOfFile)
+ if (num_of_bytes < end_of_file)
cFYI(1, ("Server inconsistency Error: it says allocation size less than end of file "));
cFYI(1,
("Size %ld and blocks %ld ",
inode->i_rdev);
}
}
- FreeXid(xid);
return rc;
}
int
cifs_get_inode_info(struct inode **pinode, const unsigned char *search_path,
- FILE_ALL_INFO * pfindData, struct super_block *sb)
+ FILE_ALL_INFO * pfindData, struct super_block *sb, int xid)
{
- int xid;
int rc = 0;
struct cifsTconInfo *pTcon;
struct inode *inode;
char *tmp_path;
char *buf = NULL;
- xid = GetXid();
-
pTcon = cifs_sb->tcon;
cFYI(1,("Getting info on %s ", search_path));
if((pfindData == NULL) && (*pinode != NULL)) {
if(CIFS_I(*pinode)->clientCanCacheRead) {
cFYI(1,("No need to revalidate inode sizes on cached file "));
- FreeXid(xid);
return rc;
}
}
/* if file info not passed in then get it from server */
if(pfindData == NULL) {
buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL);
+ if(buf == NULL)
+ return -ENOMEM;
pfindData = (FILE_ALL_INFO *)buf;
/* could do find first instead but this returns more info */
rc = CIFSSMBQPathInfo(xid, pTcon, search_path, pfindData,
if (tmp_path == NULL) {
if(buf)
kfree(buf);
- FreeXid(xid);
return -ENOMEM;
}
} else if (rc) {
if(buf)
kfree(buf);
- FreeXid(xid);
return rc;
}
} else {
struct cifsInodeInfo *cifsInfo;
+ __u32 attr = le32_to_cpu(pfindData->Attributes);
/* get new inode */
if (*pinode == NULL) {
*pinode = new_inode(sb);
- }
+ if(*pinode == NULL)
+ return -ENOMEM;
+ /* 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? */
+
+ /* We can not use the IndexNumber from either
+ Windows or Samba as it is frequently set to zero */
+ /* 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) {
+ (*pinode)->i_ino =
+ (unsigned long)pfindData->IndexNumber;
+ } */ /*NB: ino incremented to unique num in new_inode*/
+ insert_inode_hash(*pinode);
+ }
inode = *pinode;
cifsInfo = CIFS_I(inode);
- pfindData->Attributes = le32_to_cpu(pfindData->Attributes);
- cifsInfo->cifsAttrs = pfindData->Attributes;
+ cifsInfo->cifsAttrs = attr;
cFYI(1, (" Old time %ld ", cifsInfo->time));
cifsInfo->time = jiffies;
cFYI(1, (" New time %ld ", cifsInfo->time));
inode->i_ctime =
cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
cFYI(0,
- (" Attributes came in as 0x%x ", pfindData->Attributes));
+ (" Attributes came in as 0x%x ", attr));
/* set default mode. will override for dirs below */
if(atomic_read(&cifsInfo->inUse) == 0)
/* new inode, can safely set these fields */
inode->i_mode = cifs_sb->mnt_file_mode;
- if (pfindData->Attributes & ATTR_REPARSE) {
- /* Can IFLNK be set as it basically is on windows with IFREG or IFDIR? */
- inode->i_mode |= S_IFLNK;
- } else if (pfindData->Attributes & ATTR_DIRECTORY) {
+/* if (attr & ATTR_REPARSE) */
+/* We no longer handle these as symlinks because we could not */
+/* follow them due to the absolute path with drive letter */
+ if (attr & ATTR_DIRECTORY) {
/* override default perms since we do not do byte range locking on dirs */
inode->i_mode = cifs_sb->mnt_dir_mode;
inode->i_mode |= S_IFDIR;
/* 512 bytes (2**9) is the fake blocksize that must be used */
/* for this calculation */
- inode->i_blocks = (512 - 1 + pfindData->AllocationSize)
+ inode->i_blocks = (512 - 1 + le64_to_cpu(pfindData->AllocationSize))
>> 9;
}
- pfindData->AllocationSize = le64_to_cpu(pfindData->AllocationSize);
inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks);
}
if(buf)
kfree(buf);
- FreeXid(xid);
return rc;
}
void
cifs_read_inode(struct inode *inode)
{ /* gets root inode */
-
+ int xid;
struct cifs_sb_info *cifs_sb;
cifs_sb = CIFS_SB(inode->i_sb);
-
+ xid = GetXid();
if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
- cifs_get_inode_info_unix(&inode, "", inode->i_sb);
+ cifs_get_inode_info_unix(&inode, "", inode->i_sb,xid);
else
- cifs_get_inode_info(&inode, "", NULL, inode->i_sb);
+ cifs_get_inode_info(&inode, "", NULL, inode->i_sb,xid);
+ /* can not call macro FreeXid here since in a void func */
+ _FreeXid(xid);
}
int
cifsInode = CIFS_I(direntry->d_inode);
cifsInode->time = 0; /* will force revalidate to get info when needed */
direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime =
- CURRENT_TIME;
+ current_fs_time(inode->i_sb);
cifsInode = CIFS_I(inode);
cifsInode->time = 0; /* force revalidate of dir as well */
inode->i_nlink++;
if (pTcon->ses->capabilities & CAP_UNIX)
rc = cifs_get_inode_info_unix(&newinode, full_path,
- inode->i_sb);
+ inode->i_sb,xid);
else
rc = cifs_get_inode_info(&newinode, full_path,NULL,
- inode->i_sb);
+ inode->i_sb,xid);
direntry->d_op = &cifs_dentry_ops;
d_instantiate(direntry, newinode);
if(direntry->d_inode)
direntry->d_inode->i_nlink = 2;
- if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
- CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
- (__u64)-1,
- (__u64)-1,
- 0 /* dev_t */,
- cifs_sb->local_nls);
+ if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
+ if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
+ CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
+ (__u64)current->euid,
+ (__u64)current->egid,
+ 0 /* dev_t */,
+ cifs_sb->local_nls);
+ } else {
+ CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
+ (__u64)-1,
+ (__u64)-1,
+ 0 /* dev_t */,
+ cifs_sb->local_nls);
+ }
else { /* BB to be implemented via Windows secrty descriptors*/
/* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/
}
cifsInode = CIFS_I(direntry->d_inode);
cifsInode->time = 0; /* force revalidate to go get info when needed */
direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime =
- CURRENT_TIME;
+ current_fs_time(inode->i_sb);
if (full_path)
kfree(full_path);
if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) {
rc = cifs_get_inode_info_unix(&direntry->d_inode, full_path,
- direntry->d_sb);
+ direntry->d_sb,xid);
if(rc) {
cFYI(1,("error on getting revalidate info %d",rc));
/* if(rc != -ENOENT)
}
} else {
rc = cifs_get_inode_info(&direntry->d_inode, full_path, NULL,
- direntry->d_sb);
+ direntry->d_sb,xid);
if(rc) {
cFYI(1,("error on getting revalidate info %d",rc));
/* if(rc != -ENOENT)
} else
time_buf.ChangeTime = 0;
- if (set_time | time_buf.Attributes) {
+ if (set_time || time_buf.Attributes) {
/* BB what if setting one attribute fails
(such as size) but time setting works */
time_buf.CreationTime = 0; /* do not change */
via Handle (SetFileInfo) instead of by path */
rc = CIFSSMBSetTimes(xid, pTcon, full_path, &time_buf,
cifs_sb->local_nls);
+ if(rc == -EOPNOTSUPP) {
+ cFYI(1,("OS2 level of SetPathInfo not implemented"));
+ /* Need to convert time_buf into old format,
+ but probably better to do that inside the function
+ below rather than here */
+ /* Better to return EOPNOTSUPP until function
+ below is ready */
+ /* CIFSSMBSetTimesLegacy(xid, pTcon, full_path,
+ FILE_INFO_STANDARD * data, cifs_sb->local_nls); */
+ }
}
/* do not need local check to inode_check_ok since the server does that */
- inode_setattr(direntry->d_inode, attrs);
+ if (!rc)
+ rc = inode_setattr(direntry->d_inode, attrs);
if (full_path)
kfree(full_path);
FreeXid(xid);