diff options
Diffstat (limited to 'fs/cifs/inode.c')
-rw-r--r-- | fs/cifs/inode.c | 644 |
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 | ||
668 | int cifs_unlink(struct inode *inode, struct dentry *direntry) | 668 | static int |
669 | cifs_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 | |||
756 | set_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); | ||
765 | out: | ||
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 | */ | ||
774 | static int | ||
775 | cifs_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 | |||
828 | out_close: | ||
829 | CIFSSMBClose(xid, tcon, netfid); | ||
830 | out: | ||
831 | return rc; | ||
832 | } | ||
833 | |||
834 | int 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, | 870 | retry_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 | |||
711 | psx_del_no_retry: | 874 | psx_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 | |||
911 | out_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 | ||
870 | int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) | 966 | int 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 | ||
1204 | static int | ||
1205 | cifs_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 | |||
1099 | int cifs_rename(struct inode *source_inode, struct dentry *source_direntry, | 1244 | int 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 */ | ||
1325 | unlink_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 | ||
1209 | cifs_rename_exit: | 1337 | cifs_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 | ||
1509 | static int | 1638 | static int |
1510 | cifs_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 | |||
1594 | set_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); | ||
1600 | out: | ||
1601 | return rc; | ||
1602 | } | ||
1603 | |||
1604 | static int | ||
1605 | cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) | 1639 | cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) |
1606 | { | 1640 | { |
1607 | int rc; | 1641 | int rc; |