X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Fcifs%2Finode.c;h=80ab68c3892c8df9b681def396b1130b6bd45d6e;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=c12231b486351418024a5c5ee02b841468b90605;hpb=9213980e6a70d8473e0ffd4b39ab5b6caaba9ff5;p=linux-2.6.git diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index c12231b48..80ab68c38 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -35,9 +35,8 @@ extern int is_size_safe_to_change(struct cifsInodeInfo *); 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; @@ -45,8 +44,6 @@ cifs_get_inode_info_unix(struct inode **pinode, 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 */ @@ -62,7 +59,6 @@ cifs_get_inode_info_unix(struct inode **pinode, 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 */ @@ -75,19 +71,31 @@ cifs_get_inode_info_unix(struct inode **pinode, /* 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)); @@ -103,33 +111,34 @@ cifs_get_inode_info_unix(struct inode **pinode, 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 = @@ -141,14 +150,14 @@ cifs_get_inode_info_unix(struct inode **pinode, /* 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 ", @@ -172,15 +181,13 @@ cifs_get_inode_info_unix(struct inode **pinode, 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; @@ -188,15 +195,12 @@ cifs_get_inode_info(struct inode **pinode, const unsigned char *search_path, 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; } } @@ -204,6 +208,8 @@ cifs_get_inode_info(struct inode **pinode, const unsigned char *search_path, /* 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, @@ -221,7 +227,6 @@ cifs_get_inode_info(struct inode **pinode, const unsigned char *search_path, if (tmp_path == NULL) { if(buf) kfree(buf); - FreeXid(xid); return -ENOMEM; } @@ -235,21 +240,37 @@ cifs_get_inode_info(struct inode **pinode, const unsigned char *search_path, } 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)); @@ -267,17 +288,17 @@ cifs_get_inode_info(struct inode **pinode, const unsigned char *search_path, 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; @@ -296,10 +317,9 @@ cifs_get_inode_info(struct inode **pinode, const unsigned char *search_path, /* 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); @@ -332,22 +352,23 @@ cifs_get_inode_info(struct inode **pinode, const unsigned char *search_path, } 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 @@ -430,7 +451,7 @@ cifs_unlink(struct inode *inode, struct dentry *direntry) 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 */ @@ -473,21 +494,29 @@ cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) 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);*/ } @@ -535,7 +564,7 @@ cifs_rmdir(struct inode *inode, struct dentry *direntry) 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); @@ -698,7 +727,7 @@ cifs_revalidate(struct dentry *direntry) 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) @@ -706,7 +735,7 @@ cifs_revalidate(struct dentry *direntry) } } 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) @@ -943,7 +972,7 @@ cifs_setattr(struct dentry *direntry, struct iattr *attrs) } 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 */ @@ -951,10 +980,21 @@ cifs_setattr(struct dentry *direntry, struct iattr *attrs) 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);