/// <summary> /// Converts a FileSystemInfo into a FileSystemObject by reading in data about the file /// </summary> /// <param name="fileInfo"> A reference to a file on disk. </param> /// <param name="downloadCloud"> /// If the file is hosted in the cloud, the user has the option to include cloud files or not. /// </param> /// <param name="includeContentHash"> If we should generate a hash of the file. </param> /// <returns> </returns> public FileSystemObject FilePathToFileSystemObject(string path) { FileSystemObject obj = new FileSystemObject(path); // Get Owner/Group if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { try { var fileSecurity = new FileSecurity(path, AccessControlSections.Owner); IdentityReference?oid = fileSecurity.GetOwner(typeof(SecurityIdentifier)); obj.Owner = AsaHelpers.SidToName(oid); } catch (Exception e) { Log.Verbose("Failed to get owner for {0} ({1}:{2})", path, e.GetType(), e.Message); } try { var fileSecurity = new FileSecurity(path, AccessControlSections.Group); IdentityReference?gid = fileSecurity.GetGroup(typeof(SecurityIdentifier)); obj.Group = AsaHelpers.SidToName(gid); } catch (Exception e) { Log.Verbose("Failed to get group for {0} ({1}:{2})", path, e.GetType(), e.Message); } try { var fileSecurity = new FileSecurity(path, AccessControlSections.Access); var rules = fileSecurity.GetAccessRules(true, true, typeof(SecurityIdentifier)); obj.Permissions = new Dictionary <string, string>(); foreach (FileSystemAccessRule?rule in rules) { if (rule != null) { string name = AsaHelpers.SidToName(rule.IdentityReference); foreach (var permission in rule.FileSystemRights.ToString().Split(',')) { if (obj.Permissions.ContainsKey(name)) { obj.Permissions[name] = $"{obj.Permissions[name]},{permission}"; } else { obj.Permissions.Add(name, permission); } } } } } catch (Exception e) { Log.Verbose("Failed to get FileSecurity for {0} ({1}:{2})", path, e.GetType(), e.Message); } } else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { try { var file = new UnixSymbolicLinkInfo(path); obj.Owner = file.OwnerUser.UserName; obj.Group = file.OwnerGroup.GroupName; obj.SetGid = file.IsSetGroup; obj.SetUid = file.IsSetUser; obj.Permissions = new Dictionary <string, string>(); if (file.FileAccessPermissions.ToString().Equals("AllPermissions", StringComparison.InvariantCulture)) { obj.Permissions.Add("User", "Read,Write,Execute"); obj.Permissions.Add("Group", "Read,Write,Execute"); obj.Permissions.Add("Other", "Read,Write,Execute"); } else { var keys = new List <string>() { "User", "Group", "Other" }; var splits = file.FileAccessPermissions.ToString().Split(',').Select(x => x.Trim()); foreach (var key in keys) { foreach (var permission in splits.Where((x) => x.StartsWith(key, StringComparison.InvariantCulture))) { if (permission.Contains("ReadWriteExecute", StringComparison.InvariantCulture)) { obj.Permissions.Add(key, "Read,Write,Execute"); } else { if (obj.Permissions.ContainsKey(key)) { obj.Permissions[key] = $"{obj.Permissions[key]},{permission.Trim().Substring(key.Length)}"; } else { obj.Permissions.Add(key, permission.Trim().Substring(key.Length)); } } } } } } catch (Exception e) when( e is ArgumentNullException || e is ArgumentException || e is InvalidOperationException) { Log.Verbose("Failed to get permissions for {0} ({1}:{2})", path, e.GetType(), e.Message); } } try { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { if (Directory.Exists(path)) { var fileInfo = new DirectoryInfo(path); if (fileInfo.Attributes.HasFlag(FileAttributes.ReparsePoint)) { obj.IsLink = true; obj.Target = NativeMethods.GetFinalPathName(path); } else { obj.IsDirectory = true; } } else { var fileInfo = new FileInfo(path); obj.Size = fileInfo.Length; obj.SizeOnDisk = WindowsSizeOnDisk(fileInfo); // This check is to try to prevent reading of cloud based files (like a dropbox // folder) and subsequently causing a download, unless the user specifically requests // it with DownloadCloud. if (opts.DownloadCloud || obj.SizeOnDisk > 0 || WindowsFileSystemUtils.IsLocal(obj.Path)) { obj.LastModified = File.GetLastWriteTimeUtc(path); obj.Created = File.GetCreationTimeUtc(path); if (opts.GatherHashes == true) { obj.ContentHash = FileSystemUtils.GetFileHash(fileInfo); } var exeType = FileSystemUtils.GetExecutableType(path); if (exeType != EXECUTABLE_TYPE.NONE && exeType != EXECUTABLE_TYPE.UNKNOWN) { obj.IsExecutable = true; } if (exeType == EXECUTABLE_TYPE.WINDOWS) { obj.SignatureStatus = WindowsFileSystemUtils.GetSignatureStatus(path); obj.Characteristics = WindowsFileSystemUtils.GetDllCharacteristics(path); } else if (exeType == EXECUTABLE_TYPE.MACOS) { obj.MacSignatureStatus = FileSystemUtils.GetMacSignature(path); } } } } else { UnixSymbolicLinkInfo i = new UnixSymbolicLinkInfo(path); obj.FileType = i.FileType.ToString(); obj.Size = i.Length; obj.IsDirectory = false; switch (i.FileType) { case FileTypes.SymbolicLink: obj.IsLink = true; obj.Target = i.ContentsPath; break; case FileTypes.Fifo: case FileTypes.Socket: case FileTypes.BlockDevice: case FileTypes.CharacterDevice: case FileTypes.Directory: obj.IsDirectory = true; if (path?.EndsWith(".app", StringComparison.InvariantCultureIgnoreCase) ?? false) { obj.MacSignatureStatus = FileSystemUtils.GetMacSignature(path); } break; case FileTypes.RegularFile: var fileInfo = new FileInfo(path); obj.SizeOnDisk = i.BlocksAllocated * i.BlockSize; if (opts.DownloadCloud || obj.SizeOnDisk > 0) { obj.LastModified = File.GetLastWriteTimeUtc(path); obj.Created = File.GetCreationTimeUtc(path); if (opts.GatherHashes) { obj.ContentHash = FileSystemUtils.GetFileHash(path); } var exeType = FileSystemUtils.GetExecutableType(path); if (exeType != EXECUTABLE_TYPE.NONE && exeType != EXECUTABLE_TYPE.UNKNOWN) { obj.IsExecutable = true; } if (exeType == EXECUTABLE_TYPE.WINDOWS) { obj.SignatureStatus = WindowsFileSystemUtils.GetSignatureStatus(path); obj.Characteristics = WindowsFileSystemUtils.GetDllCharacteristics(path); } else if (exeType == EXECUTABLE_TYPE.MACOS) { obj.MacSignatureStatus = FileSystemUtils.GetMacSignature(path); } } break; } } } catch (Exception e) when( e is ArgumentNullException || e is SecurityException || e is ArgumentException || e is UnauthorizedAccessException || e is PathTooLongException || e is NotSupportedException || e is InvalidOperationException || e is FileNotFoundException || e is Win32Exception || e is IOException) { Log.Verbose("Failed to create FileInfo from File at {0} ({1}:{2})", path, e.GetType(), e.Message); } catch (Exception e) { Log.Debug("Should be caught in DirectoryWalker {0} {1}", e.GetType().ToString(), path); } if (path is not null) { try { obj.LastModified = File.GetLastWriteTimeUtc(path); obj.Created = File.GetCreationTimeUtc(path); } catch (Exception e) { Log.Verbose("Failed to get last modified for {0} ({1}:{2})", path, e.GetType(), e.Message); } } return(obj); }