|
32 | 32 | #include "cifspdu.h" |
33 | 33 | #include "cifsglob.h" |
34 | 34 | #include "cifsproto.h" |
| 35 | +#include "smb2proto.h" |
35 | 36 | #include "cifs_debug.h" |
36 | 37 | #include "cifs_fs_sb.h" |
37 | 38 | #include "cifs_unicode.h" |
@@ -595,6 +596,62 @@ static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path, |
595 | 596 | #endif |
596 | 597 | } |
597 | 598 |
|
| 599 | +/* Fill a cifs_fattr struct with info from POSIX info struct */ |
| 600 | +static void |
| 601 | +smb311_posix_info_to_fattr(struct cifs_fattr *fattr, struct smb311_posix_qinfo *info, |
| 602 | + struct super_block *sb, bool adjust_tz, bool symlink) |
| 603 | +{ |
| 604 | + struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
| 605 | + struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); |
| 606 | + |
| 607 | + memset(fattr, 0, sizeof(*fattr)); |
| 608 | + |
| 609 | + /* no fattr->flags to set */ |
| 610 | + fattr->cf_cifsattrs = le32_to_cpu(info->DosAttributes); |
| 611 | + fattr->cf_uniqueid = le64_to_cpu(info->Inode); |
| 612 | + |
| 613 | + if (info->LastAccessTime) |
| 614 | + fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime); |
| 615 | + else |
| 616 | + ktime_get_coarse_real_ts64(&fattr->cf_atime); |
| 617 | + |
| 618 | + fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime); |
| 619 | + fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime); |
| 620 | + |
| 621 | + if (adjust_tz) { |
| 622 | + fattr->cf_ctime.tv_sec += tcon->ses->server->timeAdj; |
| 623 | + fattr->cf_mtime.tv_sec += tcon->ses->server->timeAdj; |
| 624 | + } |
| 625 | + |
| 626 | + fattr->cf_eof = le64_to_cpu(info->EndOfFile); |
| 627 | + fattr->cf_bytes = le64_to_cpu(info->AllocationSize); |
| 628 | + fattr->cf_createtime = le64_to_cpu(info->CreationTime); |
| 629 | + |
| 630 | + fattr->cf_nlink = le32_to_cpu(info->HardLinks); |
| 631 | + fattr->cf_mode = (umode_t) le32_to_cpu(info->Mode); |
| 632 | + /* The srv fs device id is overridden on network mount so setting rdev isn't needed here */ |
| 633 | + /* fattr->cf_rdev = le32_to_cpu(info->DeviceId); */ |
| 634 | + |
| 635 | + if (symlink) { |
| 636 | + fattr->cf_mode |= S_IFLNK; |
| 637 | + fattr->cf_dtype = DT_LNK; |
| 638 | + } else if (fattr->cf_cifsattrs & ATTR_DIRECTORY) { |
| 639 | + fattr->cf_mode |= S_IFDIR; |
| 640 | + fattr->cf_dtype = DT_DIR; |
| 641 | + } else { /* file */ |
| 642 | + fattr->cf_mode |= S_IFREG; |
| 643 | + fattr->cf_dtype = DT_REG; |
| 644 | + } |
| 645 | + /* else if reparse point ... TODO: add support for FIFO and blk dev; special file types */ |
| 646 | + |
| 647 | + fattr->cf_uid = cifs_sb->mnt_uid; /* TODO: map uid and gid from SID */ |
| 648 | + fattr->cf_gid = cifs_sb->mnt_gid; |
| 649 | + |
| 650 | + cifs_dbg(FYI, "POSIX query info: mode 0x%x uniqueid 0x%llx nlink %d\n", |
| 651 | + fattr->cf_mode, fattr->cf_uniqueid, fattr->cf_nlink); |
| 652 | +} |
| 653 | + |
| 654 | + |
598 | 655 | /* Fill a cifs_fattr struct with info from FILE_ALL_INFO */ |
599 | 656 | static void |
600 | 657 | cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info, |
@@ -1023,6 +1080,121 @@ cifs_get_inode_info(struct inode **inode, |
1023 | 1080 | return rc; |
1024 | 1081 | } |
1025 | 1082 |
|
| 1083 | +int |
| 1084 | +smb311_posix_get_inode_info(struct inode **inode, |
| 1085 | + const char *full_path, |
| 1086 | + struct super_block *sb, unsigned int xid) |
| 1087 | +{ |
| 1088 | + struct cifs_tcon *tcon; |
| 1089 | + struct TCP_Server_Info *server; |
| 1090 | + struct tcon_link *tlink; |
| 1091 | + struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
| 1092 | + bool adjust_tz = false; |
| 1093 | + struct cifs_fattr fattr = {0}; |
| 1094 | + bool symlink = false; |
| 1095 | + struct smb311_posix_qinfo *data = NULL; |
| 1096 | + int rc = 0; |
| 1097 | + int tmprc = 0; |
| 1098 | + |
| 1099 | + tlink = cifs_sb_tlink(cifs_sb); |
| 1100 | + if (IS_ERR(tlink)) |
| 1101 | + return PTR_ERR(tlink); |
| 1102 | + tcon = tlink_tcon(tlink); |
| 1103 | + server = tcon->ses->server; |
| 1104 | + |
| 1105 | + /* |
| 1106 | + * 1. Fetch file metadata |
| 1107 | + */ |
| 1108 | + |
| 1109 | + if (is_inode_cache_good(*inode)) { |
| 1110 | + cifs_dbg(FYI, "No need to revalidate cached inode sizes\n"); |
| 1111 | + goto out; |
| 1112 | + } |
| 1113 | + data = kmalloc(sizeof(struct smb311_posix_qinfo), GFP_KERNEL); |
| 1114 | + if (!data) { |
| 1115 | + rc = -ENOMEM; |
| 1116 | + goto out; |
| 1117 | + } |
| 1118 | + |
| 1119 | + rc = smb311_posix_query_path_info(xid, tcon, cifs_sb, |
| 1120 | + full_path, data, |
| 1121 | + &adjust_tz, &symlink); |
| 1122 | + |
| 1123 | + /* |
| 1124 | + * 2. Convert it to internal cifs metadata (fattr) |
| 1125 | + */ |
| 1126 | + |
| 1127 | + switch (rc) { |
| 1128 | + case 0: |
| 1129 | + smb311_posix_info_to_fattr(&fattr, data, sb, adjust_tz, symlink); |
| 1130 | + break; |
| 1131 | + case -EREMOTE: |
| 1132 | + /* DFS link, no metadata available on this server */ |
| 1133 | + cifs_create_dfs_fattr(&fattr, sb); |
| 1134 | + rc = 0; |
| 1135 | + break; |
| 1136 | + case -EACCES: |
| 1137 | + /* |
| 1138 | + * For SMB2 and later the backup intent flag |
| 1139 | + * is already sent if needed on open and there |
| 1140 | + * is no path based FindFirst operation to use |
| 1141 | + * to retry with so nothing we can do, bail out |
| 1142 | + */ |
| 1143 | + goto out; |
| 1144 | + default: |
| 1145 | + cifs_dbg(FYI, "%s: unhandled err rc %d\n", __func__, rc); |
| 1146 | + goto out; |
| 1147 | + } |
| 1148 | + |
| 1149 | + |
| 1150 | + /* |
| 1151 | + * 4. Tweak fattr based on mount options |
| 1152 | + */ |
| 1153 | + |
| 1154 | + /* check for Minshall+French symlinks */ |
| 1155 | + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) { |
| 1156 | + tmprc = check_mf_symlink(xid, tcon, cifs_sb, &fattr, |
| 1157 | + full_path); |
| 1158 | + if (tmprc) |
| 1159 | + cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc); |
| 1160 | + } |
| 1161 | + |
| 1162 | + /* |
| 1163 | + * 5. Update inode with final fattr data |
| 1164 | + */ |
| 1165 | + |
| 1166 | + if (!*inode) { |
| 1167 | + *inode = cifs_iget(sb, &fattr); |
| 1168 | + if (!*inode) |
| 1169 | + rc = -ENOMEM; |
| 1170 | + } else { |
| 1171 | + /* we already have inode, update it */ |
| 1172 | + |
| 1173 | + /* if uniqueid is different, return error */ |
| 1174 | + if (unlikely(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM && |
| 1175 | + CIFS_I(*inode)->uniqueid != fattr.cf_uniqueid)) { |
| 1176 | + CIFS_I(*inode)->time = 0; /* force reval */ |
| 1177 | + rc = -ESTALE; |
| 1178 | + goto out; |
| 1179 | + } |
| 1180 | + |
| 1181 | + /* if filetype is different, return error */ |
| 1182 | + if (unlikely(((*inode)->i_mode & S_IFMT) != |
| 1183 | + (fattr.cf_mode & S_IFMT))) { |
| 1184 | + CIFS_I(*inode)->time = 0; /* force reval */ |
| 1185 | + rc = -ESTALE; |
| 1186 | + goto out; |
| 1187 | + } |
| 1188 | + |
| 1189 | + cifs_fattr_to_inode(*inode, &fattr); |
| 1190 | + } |
| 1191 | +out: |
| 1192 | + cifs_put_tlink(tlink); |
| 1193 | + kfree(data); |
| 1194 | + return rc; |
| 1195 | +} |
| 1196 | + |
| 1197 | + |
1026 | 1198 | static const struct inode_operations cifs_ipc_inode_ops = { |
1027 | 1199 | .lookup = cifs_lookup, |
1028 | 1200 | }; |
@@ -2114,7 +2286,9 @@ int cifs_revalidate_dentry_attr(struct dentry *dentry) |
2114 | 2286 | dentry, cifs_get_time(dentry), jiffies); |
2115 | 2287 |
|
2116 | 2288 | again: |
2117 | | - if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext) |
| 2289 | + if (cifs_sb_master_tcon(CIFS_SB(sb))->posix_extensions) |
| 2290 | + rc = smb311_posix_get_inode_info(&inode, full_path, sb, xid); |
| 2291 | + else if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext) |
2118 | 2292 | rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid); |
2119 | 2293 | else |
2120 | 2294 | rc = cifs_get_inode_info(&inode, full_path, NULL, sb, |
|
0 commit comments