|
32 | 32 | #include "cifs_debug.h"
|
33 | 33 | #include "cifs_fs_sb.h"
|
34 | 34 | #include "cifsfs.h"
|
| 35 | +#include "smb2proto.h" |
35 | 36 |
|
36 | 37 | /*
|
37 | 38 | * To be safe - for UCS to UTF-8 with strings loaded with the rare long
|
@@ -217,6 +218,60 @@ cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb)
|
217 | 218 | }
|
218 | 219 | }
|
219 | 220 |
|
| 221 | +/* Fill a cifs_fattr struct with info from SMB_FIND_FILE_POSIX_INFO. */ |
| 222 | +static void |
| 223 | +cifs_posix_to_fattr(struct cifs_fattr *fattr, struct smb2_posix_info *info, |
| 224 | + struct cifs_sb_info *cifs_sb) |
| 225 | +{ |
| 226 | + struct smb2_posix_info_parsed parsed; |
| 227 | + |
| 228 | + posix_info_parse(info, NULL, &parsed); |
| 229 | + |
| 230 | + memset(fattr, 0, sizeof(*fattr)); |
| 231 | + fattr->cf_uniqueid = le64_to_cpu(info->Inode); |
| 232 | + fattr->cf_bytes = le64_to_cpu(info->AllocationSize); |
| 233 | + fattr->cf_eof = le64_to_cpu(info->EndOfFile); |
| 234 | + |
| 235 | + fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime); |
| 236 | + fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime); |
| 237 | + fattr->cf_ctime = cifs_NTtimeToUnix(info->CreationTime); |
| 238 | + |
| 239 | + fattr->cf_nlink = le32_to_cpu(info->HardLinks); |
| 240 | + fattr->cf_cifsattrs = le32_to_cpu(info->DosAttributes); |
| 241 | + |
| 242 | + /* |
| 243 | + * Since we set the inode type below we need to mask off |
| 244 | + * to avoid strange results if bits set above. |
| 245 | + * XXX: why not make server&client use the type bits? |
| 246 | + */ |
| 247 | + fattr->cf_mode = le32_to_cpu(info->Mode) & ~S_IFMT; |
| 248 | + |
| 249 | + cifs_dbg(VFS, "XXX dev %d, reparse %d, mode %o", |
| 250 | + le32_to_cpu(info->DeviceId), |
| 251 | + le32_to_cpu(info->ReparseTag), |
| 252 | + le32_to_cpu(info->Mode)); |
| 253 | + |
| 254 | + if (fattr->cf_cifsattrs & ATTR_DIRECTORY) { |
| 255 | + fattr->cf_mode |= S_IFDIR; |
| 256 | + fattr->cf_dtype = DT_DIR; |
| 257 | + } else { |
| 258 | + /* |
| 259 | + * mark anything that is not a dir as regular |
| 260 | + * file. special files should have the REPARSE |
| 261 | + * attribute and will be marked as needing revaluation |
| 262 | + */ |
| 263 | + fattr->cf_mode |= S_IFREG; |
| 264 | + fattr->cf_dtype = DT_REG; |
| 265 | + } |
| 266 | + |
| 267 | + if (reparse_file_needs_reval(fattr)) |
| 268 | + fattr->cf_flags |= CIFS_FATTR_NEED_REVAL; |
| 269 | + |
| 270 | + /* TODO map SIDs */ |
| 271 | + fattr->cf_uid = cifs_sb->mnt_uid; |
| 272 | + fattr->cf_gid = cifs_sb->mnt_gid; |
| 273 | +} |
| 274 | + |
220 | 275 | static void __dir_info_to_fattr(struct cifs_fattr *fattr, const void *info)
|
221 | 276 | {
|
222 | 277 | const FILE_DIRECTORY_INFO *fi = info;
|
@@ -359,6 +414,8 @@ initiate_cifs_search(const unsigned int xid, struct file *file)
|
359 | 414 | /* if (cap_unix(tcon->ses) { */
|
360 | 415 | if (tcon->unix_ext)
|
361 | 416 | cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX;
|
| 417 | + else if (tcon->posix_extensions) |
| 418 | + cifsFile->srch_inf.info_level = SMB_FIND_FILE_POSIX_INFO; |
362 | 419 | else if ((tcon->ses->capabilities &
|
363 | 420 | tcon->ses->server->vals->cap_nt_find) == 0) {
|
364 | 421 | cifsFile->srch_inf.info_level = SMB_FIND_FILE_INFO_STANDARD;
|
@@ -451,6 +508,23 @@ struct cifs_dirent {
|
451 | 508 | u64 ino;
|
452 | 509 | };
|
453 | 510 |
|
| 511 | +static void cifs_fill_dirent_posix(struct cifs_dirent *de, |
| 512 | + const struct smb2_posix_info *info) |
| 513 | +{ |
| 514 | + struct smb2_posix_info_parsed parsed; |
| 515 | + |
| 516 | + /* payload should have already been checked at this point */ |
| 517 | + if (posix_info_parse(info, NULL, &parsed) < 0) { |
| 518 | + cifs_dbg(VFS, "invalid POSIX info payload"); |
| 519 | + return; |
| 520 | + } |
| 521 | + |
| 522 | + de->name = parsed.name; |
| 523 | + de->namelen = parsed.name_len; |
| 524 | + de->resume_key = info->Ignored; |
| 525 | + de->ino = le64_to_cpu(info->Inode); |
| 526 | +} |
| 527 | + |
454 | 528 | static void cifs_fill_dirent_unix(struct cifs_dirent *de,
|
455 | 529 | const FILE_UNIX_INFO *info, bool is_unicode)
|
456 | 530 | {
|
@@ -511,6 +585,9 @@ static int cifs_fill_dirent(struct cifs_dirent *de, const void *info,
|
511 | 585 | memset(de, 0, sizeof(*de));
|
512 | 586 |
|
513 | 587 | switch (level) {
|
| 588 | + case SMB_FIND_FILE_POSIX_INFO: |
| 589 | + cifs_fill_dirent_posix(de, info); |
| 590 | + break; |
514 | 591 | case SMB_FIND_FILE_UNIX:
|
515 | 592 | cifs_fill_dirent_unix(de, info, is_unicode);
|
516 | 593 | break;
|
@@ -786,6 +863,11 @@ static int cifs_filldir(char *find_entry, struct file *file,
|
786 | 863 | }
|
787 | 864 |
|
788 | 865 | switch (file_info->srch_inf.info_level) {
|
| 866 | + case SMB_FIND_FILE_POSIX_INFO: |
| 867 | + cifs_posix_to_fattr(&fattr, |
| 868 | + (struct smb2_posix_info *)find_entry, |
| 869 | + cifs_sb); |
| 870 | + break; |
789 | 871 | case SMB_FIND_FILE_UNIX:
|
790 | 872 | cifs_unix_basic_to_fattr(&fattr,
|
791 | 873 | &((FILE_UNIX_INFO *)find_entry)->basic,
|
|
0 commit comments