/// <inheritdoc/> public override WindowsPath Resolve() { if (_cachedResolve != null) { return(_cachedResolve); } using (var fs = File.OpenRead(PurePath.ToString())) { if (fs.SafeFileHandle == null) { return(this); } var builder = new StringBuilder(512); GetFinalPathNameByHandle(fs.SafeFileHandle.DangerousGetHandle(), builder, builder.Capacity, 0); var newPath = builder.ToString(); if (newPath.StartsWith(ExtendedLengthPrefix) && !PurePath.ToString().StartsWith(ExtendedLengthPrefix)) { newPath = newPath.Substring(ExtendedLengthPrefix.Length); } return(_cachedResolve = new WindowsPath(newPath)); } }
/// <summary> /// Return true if the path points to a junction. These are distinct /// from symlinks. /// </summary> /// <returns></returns> public bool IsJunction() { ReparsePoint rep; return(ReparsePoint.TryCreate(PurePath.ToString(), out rep) && rep.Tag == ReparsePoint.TagType.JunctionPoint); }
/// <inheritdoc/> public override bool IsSymlink() { ReparsePoint rep; return(ReparsePoint.TryCreate(PurePath.ToString(), out rep) && rep.Tag == ReparsePoint.TagType.SymbolicLink); }
/// <inheritdoc/> protected override StatInfo Stat(bool flushCache) { if (_cachedStat != null && !flushCache) { return(_cachedStat); } // http://www.delorie.com/gnu/docs/glibc/libc_284.html var info = new FileInfo(PurePath.ToString()); var stat = new StatInfo { Size = info.Length, ATime = info.LastAccessTimeUtc, MTime = info.LastWriteTimeUtc, CTime = info.CreationTimeUtc, Device = 0, Inode = 0, Gid = 0, Uid = 0, Mode = 0 // TODO not implemented }; _cachedStat = stat; return(stat); }
/// <summary> /// Gets the type of the file in the filesystem. This is /// unrelated to the extension/contents, rather it is an /// enumeration between whether the path points to a directory, /// file, symlink, socket, block device, etc. /// This is currently only relevant to Posix/Linux systems. /// </summary> /// <returns></returns> public FileType GetFileType() { var path = PurePath.ToString(); var err = Native.lstat(path, out var info); if (err != 0) { var actualError = Marshal.GetLastWin32Error(); if (actualError == 2) { return(FileType.DoesNotExist); } throw new ApplicationException("Error: " + actualError); } var fmt = info.st_mode & Native.FileTypeFormat; return(fmt switch { Native.FileTypeSymlink => FileType.SymbolicLink, Native.FileTypeDirectory => FileType.Directory, Native.FileTypeCharacterDevice => FileType.CharacterDevice, Native.FileTypeBlockDevice => FileType.BlockDevice, Native.FileTypeFifo => FileType.Fifo, Native.FileTypeSocket => FileType.Socket, Native.FileTypeRegularFile => FileType.RegularFile, _ => throw new ApplicationException($"Unknown file type {fmt}") });
/// <summary> /// Compare two <see cref="PureWindowsPath"/> for equality. /// Case insensitive. /// </summary> /// <param name="other"></param> /// <returns></returns> public bool Equals(WindowsPath other) { if (other is null) { return(false); } return(PurePath.Equals(other.PurePath)); }
/// <summary> /// Convert a path that uses the short 8.3 name (e.g. DOCUME~2.docx) /// into its long path. /// </summary> /// <returns></returns> public WindowsPath ToLongPath() { var oldPath = PurePath.ToString(); var newPath = new StringBuilder(255); if (GetLongPathName(oldPath, newPath, newPath.Capacity) == 0) { return(this); } return(new WindowsPath(PurePath.WithFilename(newPath.ToString()).ToString())); }
/// <inheritdoc/> public override WindowsPath ExpandUser() { var homeDir = new PureWindowsPath("~"); if (homeDir < PurePath) { var newDir = new PureWindowsPath(Environment.GetEnvironmentVariable("USERPROFILE")); return(new WindowsPath(newDir.Join(PurePath.RelativeTo(homeDir)))); } return(this); }
/// <inheritdoc/> public override string ToString() { return(PurePath.ToString()); }
/// <inheritdoc/> public override int GetHashCode() { return(PurePath.GetHashCode()); }
/// <summary> /// Compare two <see cref="PureWindowsPath"/> for equality. /// Case insensitive. /// </summary> /// <param name="other"></param> /// <returns></returns> public bool Equals(WindowsPath other) { return(PurePath.Equals(other.PurePath)); }
/// <inheritdoc/> protected override StatInfo Stat(bool flushCache) { if (_cachedStat != null && !flushCache) { return(_cachedStat); } var path = PurePath.ToString(); var err = Posix.Native.stat64(path, out var info); if (err != 0) { var actualError = Marshal.GetLastWin32Error(); if (actualError == 2) { throw new FileNotFoundException("Cannot stat file that does not exist.", path); } throw new ApplicationException("Error: " + actualError); } var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); var atim = epoch.AddSeconds(info.st_atim.tv_sec); if (info.st_atim.tv_nsec != 0) { atim = atim.AddTicks((long)(info.st_atim.tv_nsec / 100)); } var mtim = epoch.AddSeconds(info.st_mtim.tv_sec); if (info.st_mtim.tv_nsec != 0) { mtim = mtim.AddTicks((long)(info.st_mtim.tv_nsec / 100)); } var ctim = epoch.AddSeconds(info.st_ctim.tv_sec); if (info.st_ctim.tv_nsec != 0) { ctim = ctim.AddTicks((long)(info.st_ctim.tv_nsec / 100)); } var stat = new StatInfo { Size = info.st_size, ATime = atim, MTime = mtim, CTime = ctim, Device = (long)info.st_dev, Inode = (long)info.st_ino, Gid = info.st_uid, Uid = info.st_gid, ModeDecimal = info.st_mode, Mode = Convert.ToString(info.st_mode & (Native.SetBits | Native.UserBits | Native.GroupBits | Native.OtherBits), 8).PadLeft(4, '0'), NumLinks = (long)info.st_nlink }; try { _cachedStat = stat; } // Yes, this assignment throws a NRE if the struct alignment for pinvoke is wrong. // It overwrites 'this' in the stack with null. catch (NullReferenceException e) { throw new NotImplementedException("Layout of stat call not supported on this platform (Only supports Ubuntu x86_64 and anything compatible).", e); } return(stat); }