aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/inode.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/cifs/inode.c')
-rw-r--r--fs/cifs/inode.c644
1 files changed, 339 insertions, 305 deletions
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 9c548f110102..a8c833345fc9 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -665,40 +665,201 @@ struct inode *cifs_iget(struct super_block *sb, unsigned long ino)
665 return inode; 665 return inode;
666} 666}
667 667
668int cifs_unlink(struct inode *inode, struct dentry *direntry) 668static int
669cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid,
670 char *full_path, __u32 dosattr)
671{
672 int rc;
673 int oplock = 0;
674 __u16 netfid;
675 __u32 netpid;
676 bool set_time = false;
677 struct cifsFileInfo *open_file;
678 struct cifsInodeInfo *cifsInode = CIFS_I(inode);
679 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
680 struct cifsTconInfo *pTcon = cifs_sb->tcon;
681 FILE_BASIC_INFO info_buf;
682
683 if (attrs->ia_valid & ATTR_ATIME) {
684 set_time = true;
685 info_buf.LastAccessTime =
686 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime));
687 } else
688 info_buf.LastAccessTime = 0;
689
690 if (attrs->ia_valid & ATTR_MTIME) {
691 set_time = true;
692 info_buf.LastWriteTime =
693 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime));
694 } else
695 info_buf.LastWriteTime = 0;
696
697 /*
698 * Samba throws this field away, but windows may actually use it.
699 * Do not set ctime unless other time stamps are changed explicitly
700 * (i.e. by utimes()) since we would then have a mix of client and
701 * server times.
702 */
703 if (set_time && (attrs->ia_valid & ATTR_CTIME)) {
704 cFYI(1, ("CIFS - CTIME changed"));
705 info_buf.ChangeTime =
706 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
707 } else
708 info_buf.ChangeTime = 0;
709
710 info_buf.CreationTime = 0; /* don't change */
711 info_buf.Attributes = cpu_to_le32(dosattr);
712
713 /*
714 * If the file is already open for write, just use that fileid
715 */
716 open_file = find_writable_file(cifsInode);
717 if (open_file) {
718 netfid = open_file->netfid;
719 netpid = open_file->pid;
720 goto set_via_filehandle;
721 }
722
723 /*
724 * NT4 apparently returns success on this call, but it doesn't
725 * really work.
726 */
727 if (!(pTcon->ses->flags & CIFS_SES_NT4)) {
728 rc = CIFSSMBSetPathInfo(xid, pTcon, full_path,
729 &info_buf, cifs_sb->local_nls,
730 cifs_sb->mnt_cifs_flags &
731 CIFS_MOUNT_MAP_SPECIAL_CHR);
732 if (rc == 0) {
733 cifsInode->cifsAttrs = dosattr;
734 goto out;
735 } else if (rc != -EOPNOTSUPP && rc != -EINVAL)
736 goto out;
737 }
738
739 cFYI(1, ("calling SetFileInfo since SetPathInfo for "
740 "times not supported by this server"));
741 rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN,
742 SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
743 CREATE_NOT_DIR, &netfid, &oplock,
744 NULL, cifs_sb->local_nls,
745 cifs_sb->mnt_cifs_flags &
746 CIFS_MOUNT_MAP_SPECIAL_CHR);
747
748 if (rc != 0) {
749 if (rc == -EIO)
750 rc = -EINVAL;
751 goto out;
752 }
753
754 netpid = current->tgid;
755
756set_via_filehandle:
757 rc = CIFSSMBSetFileInfo(xid, pTcon, &info_buf, netfid, netpid);
758 if (!rc)
759 cifsInode->cifsAttrs = dosattr;
760
761 if (open_file == NULL)
762 CIFSSMBClose(xid, pTcon, netfid);
763 else
764 atomic_dec(&open_file->wrtPending);
765out:
766 return rc;
767}
768
769/*
770 * open the given file (if it isn't already), set the DELETE_ON_CLOSE bit
771 * and rename it to a random name that hopefully won't conflict with
772 * anything else.
773 */
774static int
775cifs_rename_pending_delete(char *full_path, struct inode *inode, int xid)
776{
777 int oplock = 0;
778 int rc;
779 __u16 netfid;
780 struct cifsInodeInfo *cifsInode = CIFS_I(inode);
781 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
782 struct cifsTconInfo *tcon = cifs_sb->tcon;
783 __u32 dosattr;
784 FILE_BASIC_INFO *info_buf;
785
786 rc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN,
787 DELETE|FILE_WRITE_ATTRIBUTES,
788 CREATE_NOT_DIR|CREATE_DELETE_ON_CLOSE,
789 &netfid, &oplock, NULL, cifs_sb->local_nls,
790 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
791 if (rc != 0)
792 goto out;
793
794 /* set ATTR_HIDDEN and clear ATTR_READONLY */
795 cifsInode = CIFS_I(inode);
796 dosattr = cifsInode->cifsAttrs & ~ATTR_READONLY;
797 if (dosattr == 0)
798 dosattr |= ATTR_NORMAL;
799 dosattr |= ATTR_HIDDEN;
800
801 info_buf = kzalloc(sizeof(*info_buf), GFP_KERNEL);
802 if (info_buf == NULL) {
803 rc = -ENOMEM;
804 goto out_close;
805 }
806 info_buf->Attributes = cpu_to_le32(dosattr);
807 rc = CIFSSMBSetFileInfo(xid, tcon, info_buf, netfid, current->tgid);
808 kfree(info_buf);
809 if (rc != 0)
810 goto out_close;
811 cifsInode->cifsAttrs = dosattr;
812
813 /* silly-rename the file */
814 CIFSSMBRenameOpenFile(xid, tcon, netfid, NULL, cifs_sb->local_nls,
815 cifs_sb->mnt_cifs_flags &
816 CIFS_MOUNT_MAP_SPECIAL_CHR);
817
818 /* set DELETE_ON_CLOSE */
819 rc = CIFSSMBSetFileDisposition(xid, tcon, true, netfid, current->tgid);
820
821 /*
822 * some samba versions return -ENOENT when we try to set the file
823 * disposition here. Likely a samba bug, but work around it for now
824 */
825 if (rc == -ENOENT)
826 rc = 0;
827
828out_close:
829 CIFSSMBClose(xid, tcon, netfid);
830out:
831 return rc;
832}
833
834int cifs_unlink(struct inode *dir, struct dentry *dentry)
669{ 835{
670 int rc = 0; 836 int rc = 0;
671 int xid; 837 int xid;
672 struct cifs_sb_info *cifs_sb;
673 struct cifsTconInfo *pTcon;
674 char *full_path = NULL; 838 char *full_path = NULL;
675 struct cifsInodeInfo *cifsInode; 839 struct inode *inode = dentry->d_inode;
676 FILE_BASIC_INFO *pinfo_buf; 840 struct cifsInodeInfo *cifsInode = CIFS_I(inode);
841 struct super_block *sb = dir->i_sb;
842 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
843 struct cifsTconInfo *tcon = cifs_sb->tcon;
844 struct iattr *attrs = NULL;
845 __u32 dosattr = 0, origattr = 0;
677 846
678 cFYI(1, ("cifs_unlink, inode = 0x%p", inode)); 847 cFYI(1, ("cifs_unlink, dir=0x%p, dentry=0x%p", dir, dentry));
679 848
680 xid = GetXid(); 849 xid = GetXid();
681 850
682 if (inode) 851 /* Unlink can be called from rename so we can not take the
683 cifs_sb = CIFS_SB(inode->i_sb); 852 * sb->s_vfs_rename_mutex here */
684 else 853 full_path = build_path_from_dentry(dentry);
685 cifs_sb = CIFS_SB(direntry->d_sb);
686 pTcon = cifs_sb->tcon;
687
688 /* Unlink can be called from rename so we can not grab the sem here
689 since we deadlock otherwise */
690/* mutex_lock(&direntry->d_sb->s_vfs_rename_mutex);*/
691 full_path = build_path_from_dentry(direntry);
692/* mutex_unlock(&direntry->d_sb->s_vfs_rename_mutex);*/
693 if (full_path == NULL) { 854 if (full_path == NULL) {
694 FreeXid(xid); 855 FreeXid(xid);
695 return -ENOMEM; 856 return -ENOMEM;
696 } 857 }
697 858
698 if ((pTcon->ses->capabilities & CAP_UNIX) && 859 if ((tcon->ses->capabilities & CAP_UNIX) &&
699 (CIFS_UNIX_POSIX_PATH_OPS_CAP & 860 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
700 le64_to_cpu(pTcon->fsUnixInfo.Capability))) { 861 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
701 rc = CIFSPOSIXDelFile(xid, pTcon, full_path, 862 rc = CIFSPOSIXDelFile(xid, tcon, full_path,
702 SMB_POSIX_UNLINK_FILE_TARGET, cifs_sb->local_nls, 863 SMB_POSIX_UNLINK_FILE_TARGET, cifs_sb->local_nls,
703 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); 864 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
704 cFYI(1, ("posix del rc %d", rc)); 865 cFYI(1, ("posix del rc %d", rc));
@@ -706,125 +867,60 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
706 goto psx_del_no_retry; 867 goto psx_del_no_retry;
707 } 868 }
708 869
709 rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls, 870retry_std_delete:
871 rc = CIFSSMBDelFile(xid, tcon, full_path, cifs_sb->local_nls,
710 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); 872 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
873
711psx_del_no_retry: 874psx_del_no_retry:
712 if (!rc) { 875 if (!rc) {
713 if (direntry->d_inode) 876 if (inode)
714 drop_nlink(direntry->d_inode); 877 drop_nlink(inode);
715 } else if (rc == -ENOENT) { 878 } else if (rc == -ENOENT) {
716 d_drop(direntry); 879 d_drop(dentry);
717 } else if (rc == -ETXTBSY) { 880 } else if (rc == -ETXTBSY) {
718 int oplock = 0; 881 rc = cifs_rename_pending_delete(full_path, inode, xid);
719 __u16 netfid; 882 if (rc == 0)
720 883 drop_nlink(inode);
721 rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE, 884 } else if (rc == -EACCES && dosattr == 0) {
722 CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE, 885 attrs = kzalloc(sizeof(*attrs), GFP_KERNEL);
723 &netfid, &oplock, NULL, cifs_sb->local_nls, 886 if (attrs == NULL) {
724 cifs_sb->mnt_cifs_flags & 887 rc = -ENOMEM;
725 CIFS_MOUNT_MAP_SPECIAL_CHR); 888 goto out_reval;
726 if (rc == 0) {
727 CIFSSMBRenameOpenFile(xid, pTcon, netfid, NULL,
728 cifs_sb->local_nls,
729 cifs_sb->mnt_cifs_flags &
730 CIFS_MOUNT_MAP_SPECIAL_CHR);
731 CIFSSMBClose(xid, pTcon, netfid);
732 if (direntry->d_inode)
733 drop_nlink(direntry->d_inode);
734 } 889 }
735 } else if (rc == -EACCES) {
736 /* try only if r/o attribute set in local lookup data? */
737 pinfo_buf = kzalloc(sizeof(FILE_BASIC_INFO), GFP_KERNEL);
738 if (pinfo_buf) {
739 /* ATTRS set to normal clears r/o bit */
740 pinfo_buf->Attributes = cpu_to_le32(ATTR_NORMAL);
741 if (!(pTcon->ses->flags & CIFS_SES_NT4))
742 rc = CIFSSMBSetPathInfo(xid, pTcon, full_path,
743 pinfo_buf,
744 cifs_sb->local_nls,
745 cifs_sb->mnt_cifs_flags &
746 CIFS_MOUNT_MAP_SPECIAL_CHR);
747 else
748 rc = -EOPNOTSUPP;
749 890
750 if (rc == -EOPNOTSUPP) { 891 /* try to reset dos attributes */
751 int oplock = 0; 892 origattr = cifsInode->cifsAttrs;
752 __u16 netfid; 893 if (origattr == 0)
753 /* rc = CIFSSMBSetAttrLegacy(xid, pTcon, 894 origattr |= ATTR_NORMAL;
754 full_path, 895 dosattr = origattr & ~ATTR_READONLY;
755 (__u16)ATTR_NORMAL, 896 if (dosattr == 0)
756 cifs_sb->local_nls); 897 dosattr |= ATTR_NORMAL;
757 For some strange reason it seems that NT4 eats the 898 dosattr |= ATTR_HIDDEN;
758 old setattr call without actually setting the 899
759 attributes so on to the third attempted workaround 900 rc = cifs_set_file_info(inode, attrs, xid, full_path, dosattr);
760 */ 901 if (rc != 0)
761 902 goto out_reval;
762 /* BB could scan to see if we already have it open 903
763 and pass in pid of opener to function */ 904 goto retry_std_delete;
764 rc = CIFSSMBOpen(xid, pTcon, full_path,
765 FILE_OPEN, SYNCHRONIZE |
766 FILE_WRITE_ATTRIBUTES, 0,
767 &netfid, &oplock, NULL,
768 cifs_sb->local_nls,
769 cifs_sb->mnt_cifs_flags &
770 CIFS_MOUNT_MAP_SPECIAL_CHR);
771 if (rc == 0) {
772 rc = CIFSSMBSetFileInfo(xid, pTcon,
773 pinfo_buf,
774 netfid,
775 current->tgid);
776 CIFSSMBClose(xid, pTcon, netfid);
777 }
778 }
779 kfree(pinfo_buf);
780 }
781 if (rc == 0) {
782 rc = CIFSSMBDelFile(xid, pTcon, full_path,
783 cifs_sb->local_nls,
784 cifs_sb->mnt_cifs_flags &
785 CIFS_MOUNT_MAP_SPECIAL_CHR);
786 if (!rc) {
787 if (direntry->d_inode)
788 drop_nlink(direntry->d_inode);
789 } else if (rc == -ETXTBSY) {
790 int oplock = 0;
791 __u16 netfid;
792
793 rc = CIFSSMBOpen(xid, pTcon, full_path,
794 FILE_OPEN, DELETE,
795 CREATE_NOT_DIR |
796 CREATE_DELETE_ON_CLOSE,
797 &netfid, &oplock, NULL,
798 cifs_sb->local_nls,
799 cifs_sb->mnt_cifs_flags &
800 CIFS_MOUNT_MAP_SPECIAL_CHR);
801 if (rc == 0) {
802 CIFSSMBRenameOpenFile(xid, pTcon,
803 netfid, NULL,
804 cifs_sb->local_nls,
805 cifs_sb->mnt_cifs_flags &
806 CIFS_MOUNT_MAP_SPECIAL_CHR);
807 CIFSSMBClose(xid, pTcon, netfid);
808 if (direntry->d_inode)
809 drop_nlink(direntry->d_inode);
810 }
811 /* BB if rc = -ETXTBUSY goto the rename logic BB */
812 }
813 }
814 }
815 if (direntry->d_inode) {
816 cifsInode = CIFS_I(direntry->d_inode);
817 cifsInode->time = 0; /* will force revalidate to get info
818 when needed */
819 direntry->d_inode->i_ctime = current_fs_time(inode->i_sb);
820 } 905 }
906
907 /* undo the setattr if we errored out and it's needed */
908 if (rc != 0 && dosattr != 0)
909 cifs_set_file_info(inode, attrs, xid, full_path, origattr);
910
911out_reval:
821 if (inode) { 912 if (inode) {
822 inode->i_ctime = inode->i_mtime = current_fs_time(inode->i_sb);
823 cifsInode = CIFS_I(inode); 913 cifsInode = CIFS_I(inode);
824 cifsInode->time = 0; /* force revalidate of dir as well */ 914 cifsInode->time = 0; /* will force revalidate to get info
915 when needed */
916 inode->i_ctime = current_fs_time(sb);
825 } 917 }
918 dir->i_ctime = dir->i_mtime = current_fs_time(sb);
919 cifsInode = CIFS_I(dir);
920 CIFS_I(dir)->time = 0; /* force revalidate of dir as well */
826 921
827 kfree(full_path); 922 kfree(full_path);
923 kfree(attrs);
828 FreeXid(xid); 924 FreeXid(xid);
829 return rc; 925 return rc;
830} 926}
@@ -869,7 +965,7 @@ static void posix_fill_in_inode(struct inode *tmp_inode,
869 965
870int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) 966int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
871{ 967{
872 int rc = 0; 968 int rc = 0, tmprc;
873 int xid; 969 int xid;
874 struct cifs_sb_info *cifs_sb; 970 struct cifs_sb_info *cifs_sb;
875 struct cifsTconInfo *pTcon; 971 struct cifsTconInfo *pTcon;
@@ -931,6 +1027,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
931 kfree(pInfo); 1027 kfree(pInfo);
932 goto mkdir_get_info; 1028 goto mkdir_get_info;
933 } 1029 }
1030
934 /* Is an i_ino of zero legal? */ 1031 /* Is an i_ino of zero legal? */
935 /* Are there sanity checks we can use to ensure that 1032 /* Are there sanity checks we can use to ensure that
936 the server is really filling in that field? */ 1033 the server is really filling in that field? */
@@ -1019,12 +1116,20 @@ mkdir_get_info:
1019 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) && 1116 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
1020 (mode & S_IWUGO) == 0) { 1117 (mode & S_IWUGO) == 0) {
1021 FILE_BASIC_INFO pInfo; 1118 FILE_BASIC_INFO pInfo;
1119 struct cifsInodeInfo *cifsInode;
1120 u32 dosattrs;
1121
1022 memset(&pInfo, 0, sizeof(pInfo)); 1122 memset(&pInfo, 0, sizeof(pInfo));
1023 pInfo.Attributes = cpu_to_le32(ATTR_READONLY); 1123 cifsInode = CIFS_I(newinode);
1024 CIFSSMBSetPathInfo(xid, pTcon, full_path, 1124 dosattrs = cifsInode->cifsAttrs|ATTR_READONLY;
1025 &pInfo, cifs_sb->local_nls, 1125 pInfo.Attributes = cpu_to_le32(dosattrs);
1126 tmprc = CIFSSMBSetPathInfo(xid, pTcon,
1127 full_path, &pInfo,
1128 cifs_sb->local_nls,
1026 cifs_sb->mnt_cifs_flags & 1129 cifs_sb->mnt_cifs_flags &
1027 CIFS_MOUNT_MAP_SPECIAL_CHR); 1130 CIFS_MOUNT_MAP_SPECIAL_CHR);
1131 if (tmprc == 0)
1132 cifsInode->cifsAttrs = dosattrs;
1028 } 1133 }
1029 if (direntry->d_inode) { 1134 if (direntry->d_inode) {
1030 if (cifs_sb->mnt_cifs_flags & 1135 if (cifs_sb->mnt_cifs_flags &
@@ -1096,117 +1201,141 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
1096 return rc; 1201 return rc;
1097} 1202}
1098 1203
1204static int
1205cifs_do_rename(int xid, struct dentry *from_dentry, const char *fromPath,
1206 struct dentry *to_dentry, const char *toPath)
1207{
1208 struct cifs_sb_info *cifs_sb = CIFS_SB(from_dentry->d_sb);
1209 struct cifsTconInfo *pTcon = cifs_sb->tcon;
1210 __u16 srcfid;
1211 int oplock, rc;
1212
1213 /* try path-based rename first */
1214 rc = CIFSSMBRename(xid, pTcon, fromPath, toPath, cifs_sb->local_nls,
1215 cifs_sb->mnt_cifs_flags &
1216 CIFS_MOUNT_MAP_SPECIAL_CHR);
1217
1218 /*
1219 * don't bother with rename by filehandle unless file is busy and
1220 * source Note that cross directory moves do not work with
1221 * rename by filehandle to various Windows servers.
1222 */
1223 if (rc == 0 || rc != -ETXTBSY)
1224 return rc;
1225
1226 /* open the file to be renamed -- we need DELETE perms */
1227 rc = CIFSSMBOpen(xid, pTcon, fromPath, FILE_OPEN, DELETE,
1228 CREATE_NOT_DIR, &srcfid, &oplock, NULL,
1229 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
1230 CIFS_MOUNT_MAP_SPECIAL_CHR);
1231
1232 if (rc == 0) {
1233 rc = CIFSSMBRenameOpenFile(xid, pTcon, srcfid,
1234 (const char *) to_dentry->d_name.name,
1235 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
1236 CIFS_MOUNT_MAP_SPECIAL_CHR);
1237
1238 CIFSSMBClose(xid, pTcon, srcfid);
1239 }
1240
1241 return rc;
1242}
1243
1099int cifs_rename(struct inode *source_inode, struct dentry *source_direntry, 1244int cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
1100 struct inode *target_inode, struct dentry *target_direntry) 1245 struct inode *target_inode, struct dentry *target_direntry)
1101{ 1246{
1102 char *fromName; 1247 char *fromName = NULL;
1103 char *toName; 1248 char *toName = NULL;
1104 struct cifs_sb_info *cifs_sb_source; 1249 struct cifs_sb_info *cifs_sb_source;
1105 struct cifs_sb_info *cifs_sb_target; 1250 struct cifs_sb_info *cifs_sb_target;
1106 struct cifsTconInfo *pTcon; 1251 struct cifsTconInfo *pTcon;
1252 FILE_UNIX_BASIC_INFO *info_buf_source = NULL;
1253 FILE_UNIX_BASIC_INFO *info_buf_target;
1107 int xid; 1254 int xid;
1108 int rc = 0; 1255 int rc;
1109
1110 xid = GetXid();
1111 1256
1112 cifs_sb_target = CIFS_SB(target_inode->i_sb); 1257 cifs_sb_target = CIFS_SB(target_inode->i_sb);
1113 cifs_sb_source = CIFS_SB(source_inode->i_sb); 1258 cifs_sb_source = CIFS_SB(source_inode->i_sb);
1114 pTcon = cifs_sb_source->tcon; 1259 pTcon = cifs_sb_source->tcon;
1115 1260
1261 xid = GetXid();
1262
1263 /*
1264 * BB: this might be allowed if same server, but different share.
1265 * Consider adding support for this
1266 */
1116 if (pTcon != cifs_sb_target->tcon) { 1267 if (pTcon != cifs_sb_target->tcon) {
1117 FreeXid(xid); 1268 rc = -EXDEV;
1118 return -EXDEV; /* BB actually could be allowed if same server, 1269 goto cifs_rename_exit;
1119 but different share.
1120 Might eventually add support for this */
1121 } 1270 }
1122 1271
1123 /* we already have the rename sem so we do not need to grab it again 1272 /*
1124 here to protect the path integrity */ 1273 * we already have the rename sem so we do not need to
1274 * grab it again here to protect the path integrity
1275 */
1125 fromName = build_path_from_dentry(source_direntry); 1276 fromName = build_path_from_dentry(source_direntry);
1277 if (fromName == NULL) {
1278 rc = -ENOMEM;
1279 goto cifs_rename_exit;
1280 }
1281
1126 toName = build_path_from_dentry(target_direntry); 1282 toName = build_path_from_dentry(target_direntry);
1127 if ((fromName == NULL) || (toName == NULL)) { 1283 if (toName == NULL) {
1128 rc = -ENOMEM; 1284 rc = -ENOMEM;
1129 goto cifs_rename_exit; 1285 goto cifs_rename_exit;
1130 } 1286 }
1131 1287
1132 rc = CIFSSMBRename(xid, pTcon, fromName, toName, 1288 rc = cifs_do_rename(xid, source_direntry, fromName,
1133 cifs_sb_source->local_nls, 1289 target_direntry, toName);
1134 cifs_sb_source->mnt_cifs_flags & 1290
1135 CIFS_MOUNT_MAP_SPECIAL_CHR);
1136 if (rc == -EEXIST) { 1291 if (rc == -EEXIST) {
1137 /* check if they are the same file because rename of hardlinked 1292 if (pTcon->unix_ext) {
1138 files is a noop */ 1293 /*
1139 FILE_UNIX_BASIC_INFO *info_buf_source; 1294 * Are src and dst hardlinks of same inode? We can
1140 FILE_UNIX_BASIC_INFO *info_buf_target; 1295 * only tell with unix extensions enabled
1141 1296 */
1142 info_buf_source = 1297 info_buf_source =
1143 kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL); 1298 kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO),
1144 if (info_buf_source != NULL) { 1299 GFP_KERNEL);
1300 if (info_buf_source == NULL)
1301 goto unlink_target;
1302
1145 info_buf_target = info_buf_source + 1; 1303 info_buf_target = info_buf_source + 1;
1146 if (pTcon->unix_ext) 1304 rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName,
1147 rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName, 1305 info_buf_source,
1148 info_buf_source, 1306 cifs_sb_source->local_nls,
1149 cifs_sb_source->local_nls, 1307 cifs_sb_source->mnt_cifs_flags &
1150 cifs_sb_source->mnt_cifs_flags &
1151 CIFS_MOUNT_MAP_SPECIAL_CHR); 1308 CIFS_MOUNT_MAP_SPECIAL_CHR);
1152 /* else rc is still EEXIST so will fall through to 1309 if (rc != 0)
1153 unlink the target and retry rename */ 1310 goto unlink_target;
1154 if (rc == 0) { 1311
1155 rc = CIFSSMBUnixQPathInfo(xid, pTcon, toName, 1312 rc = CIFSSMBUnixQPathInfo(xid, pTcon,
1156 info_buf_target, 1313 toName, info_buf_target,
1157 cifs_sb_target->local_nls, 1314 cifs_sb_target->local_nls,
1158 /* remap based on source sb */ 1315 /* remap based on source sb */
1159 cifs_sb_source->mnt_cifs_flags & 1316 cifs_sb_source->mnt_cifs_flags &
1160 CIFS_MOUNT_MAP_SPECIAL_CHR);
1161 }
1162 if ((rc == 0) &&
1163 (info_buf_source->UniqueId ==
1164 info_buf_target->UniqueId)) {
1165 /* do not rename since the files are hardlinked which
1166 is a noop */
1167 } else {
1168 /* we either can not tell the files are hardlinked
1169 (as with Windows servers) or files are not
1170 hardlinked so delete the target manually before
1171 renaming to follow POSIX rather than Windows
1172 semantics */
1173 cifs_unlink(target_inode, target_direntry);
1174 rc = CIFSSMBRename(xid, pTcon, fromName,
1175 toName,
1176 cifs_sb_source->local_nls,
1177 cifs_sb_source->mnt_cifs_flags
1178 & CIFS_MOUNT_MAP_SPECIAL_CHR);
1179 }
1180 kfree(info_buf_source);
1181 } /* if we can not get memory just leave rc as EEXIST */
1182 }
1183
1184 if (rc)
1185 cFYI(1, ("rename rc %d", rc));
1186
1187 if ((rc == -EIO) || (rc == -EEXIST)) {
1188 int oplock = 0;
1189 __u16 netfid;
1190
1191 /* BB FIXME Is Generic Read correct for rename? */
1192 /* if renaming directory - we should not say CREATE_NOT_DIR,
1193 need to test renaming open directory, also GENERIC_READ
1194 might not right be right access to request */
1195 rc = CIFSSMBOpen(xid, pTcon, fromName, FILE_OPEN, GENERIC_READ,
1196 CREATE_NOT_DIR, &netfid, &oplock, NULL,
1197 cifs_sb_source->local_nls,
1198 cifs_sb_source->mnt_cifs_flags &
1199 CIFS_MOUNT_MAP_SPECIAL_CHR);
1200 if (rc == 0) {
1201 rc = CIFSSMBRenameOpenFile(xid, pTcon, netfid, toName,
1202 cifs_sb_source->local_nls,
1203 cifs_sb_source->mnt_cifs_flags &
1204 CIFS_MOUNT_MAP_SPECIAL_CHR); 1317 CIFS_MOUNT_MAP_SPECIAL_CHR);
1205 CIFSSMBClose(xid, pTcon, netfid); 1318
1206 } 1319 if (rc == 0 && (info_buf_source->UniqueId ==
1320 info_buf_target->UniqueId))
1321 /* same file, POSIX says that this is a noop */
1322 goto cifs_rename_exit;
1323 } /* else ... BB we could add the same check for Windows by
1324 checking the UniqueId via FILE_INTERNAL_INFO */
1325unlink_target:
1326 /*
1327 * we either can not tell the files are hardlinked (as with
1328 * Windows servers) or files are not hardlinked. Delete the
1329 * target manually before renaming to follow POSIX rather than
1330 * Windows semantics
1331 */
1332 cifs_unlink(target_inode, target_direntry);
1333 rc = cifs_do_rename(xid, source_direntry, fromName,
1334 target_direntry, toName);
1207 } 1335 }
1208 1336
1209cifs_rename_exit: 1337cifs_rename_exit:
1338 kfree(info_buf_source);
1210 kfree(fromName); 1339 kfree(fromName);
1211 kfree(toName); 1340 kfree(toName);
1212 FreeXid(xid); 1341 FreeXid(xid);
@@ -1507,101 +1636,6 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
1507} 1636}
1508 1637
1509static int 1638static int
1510cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid,
1511 char *full_path, __u32 dosattr)
1512{
1513 int rc;
1514 int oplock = 0;
1515 __u16 netfid;
1516 __u32 netpid;
1517 bool set_time = false;
1518 struct cifsFileInfo *open_file;
1519 struct cifsInodeInfo *cifsInode = CIFS_I(inode);
1520 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
1521 struct cifsTconInfo *pTcon = cifs_sb->tcon;
1522 FILE_BASIC_INFO info_buf;
1523
1524 if (attrs->ia_valid & ATTR_ATIME) {
1525 set_time = true;
1526 info_buf.LastAccessTime =
1527 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime));
1528 } else
1529 info_buf.LastAccessTime = 0;
1530
1531 if (attrs->ia_valid & ATTR_MTIME) {
1532 set_time = true;
1533 info_buf.LastWriteTime =
1534 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime));
1535 } else
1536 info_buf.LastWriteTime = 0;
1537
1538 /*
1539 * Samba throws this field away, but windows may actually use it.
1540 * Do not set ctime unless other time stamps are changed explicitly
1541 * (i.e. by utimes()) since we would then have a mix of client and
1542 * server times.
1543 */
1544 if (set_time && (attrs->ia_valid & ATTR_CTIME)) {
1545 cFYI(1, ("CIFS - CTIME changed"));
1546 info_buf.ChangeTime =
1547 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
1548 } else
1549 info_buf.ChangeTime = 0;
1550
1551 info_buf.CreationTime = 0; /* don't change */
1552 info_buf.Attributes = cpu_to_le32(dosattr);
1553
1554 /*
1555 * If the file is already open for write, just use that fileid
1556 */
1557 open_file = find_writable_file(cifsInode);
1558 if (open_file) {
1559 netfid = open_file->netfid;
1560 netpid = open_file->pid;
1561 goto set_via_filehandle;
1562 }
1563
1564 /*
1565 * NT4 apparently returns success on this call, but it doesn't
1566 * really work.
1567 */
1568 if (!(pTcon->ses->flags & CIFS_SES_NT4)) {
1569 rc = CIFSSMBSetPathInfo(xid, pTcon, full_path,
1570 &info_buf, cifs_sb->local_nls,
1571 cifs_sb->mnt_cifs_flags &
1572 CIFS_MOUNT_MAP_SPECIAL_CHR);
1573 if (rc != -EOPNOTSUPP && rc != -EINVAL)
1574 goto out;
1575 }
1576
1577 cFYI(1, ("calling SetFileInfo since SetPathInfo for "
1578 "times not supported by this server"));
1579 rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN,
1580 SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
1581 CREATE_NOT_DIR, &netfid, &oplock,
1582 NULL, cifs_sb->local_nls,
1583 cifs_sb->mnt_cifs_flags &
1584 CIFS_MOUNT_MAP_SPECIAL_CHR);
1585
1586 if (rc != 0) {
1587 if (rc == -EIO)
1588 rc = -EINVAL;
1589 goto out;
1590 }
1591
1592 netpid = current->tgid;
1593
1594set_via_filehandle:
1595 rc = CIFSSMBSetFileInfo(xid, pTcon, &info_buf, netfid, netpid);
1596 if (open_file == NULL)
1597 CIFSSMBClose(xid, pTcon, netfid);
1598 else
1599 atomic_dec(&open_file->wrtPending);
1600out:
1601 return rc;
1602}
1603
1604static int
1605cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) 1639cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
1606{ 1640{
1607 int rc; 1641 int rc;