Пример #1
0
        internal static bool IsReadOnly(Interop.Sys.FileStatus fileStatus)
        {
#if TARGET_BROWSER
            const Interop.Sys.Permissions readBit  = Interop.Sys.Permissions.S_IRUSR;
            const Interop.Sys.Permissions writeBit = Interop.Sys.Permissions.S_IWUSR;
#else
            Interop.Sys.Permissions readBit, writeBit;
            if (fileStatus.Uid == Interop.Sys.GetEUid())
            {
                // User effectively owns the file
                readBit  = Interop.Sys.Permissions.S_IRUSR;
                writeBit = Interop.Sys.Permissions.S_IWUSR;
            }
            else if (fileStatus.Gid == Interop.Sys.GetEGid())
            {
                // User belongs to a group that effectively owns the file
                readBit  = Interop.Sys.Permissions.S_IRGRP;
                writeBit = Interop.Sys.Permissions.S_IWGRP;
            }
            else
            {
                // Others permissions
                readBit  = Interop.Sys.Permissions.S_IROTH;
                writeBit = Interop.Sys.Permissions.S_IWOTH;
            }
#endif

            return((fileStatus.Mode & (int)readBit) != 0 && // has read permission
                   (fileStatus.Mode & (int)writeBit) == 0); // but not write permission
        }
        partial void VerifyPlatformSpecificMetadata(string filePath, TarEntry entry)
        {
            Interop.Sys.FileStatus status = default;
            status.Mode = default;
            status.Dev  = default;
            Interop.CheckIo(Interop.Sys.LStat(filePath, out status));

            Assert.Equal((int)status.Uid, entry.Uid);
            Assert.Equal((int)status.Gid, entry.Gid);

            if (entry is PosixTarEntry posix)
            {
                string gname = Interop.Sys.GetGroupName(status.Gid);
                string uname = Interop.Sys.GetUserNameFromPasswd(status.Uid);

                Assert.Equal(gname, posix.GroupName);
                Assert.Equal(uname, posix.UserName);

                if (entry.EntryType is not TarEntryType.BlockDevice and not TarEntryType.CharacterDevice)
                {
                    Assert.Equal(DefaultDeviceMajor, posix.DeviceMajor);
                    Assert.Equal(DefaultDeviceMinor, posix.DeviceMinor);
                }
            }

            if (entry.EntryType is not TarEntryType.Directory)
            {
                TarFileMode    expectedMode  = (TarFileMode)(status.Mode & 4095); // First 12 bits
                DateTimeOffset expectedMTime = DateTimeOffset.FromUnixTimeSeconds(status.MTime);
                DateTimeOffset expectedATime = DateTimeOffset.FromUnixTimeSeconds(status.ATime);
                DateTimeOffset expectedCTime = DateTimeOffset.FromUnixTimeSeconds(status.CTime);

                Assert.Equal(expectedMode, entry.Mode);
                Assert.Equal(expectedMTime, entry.ModificationTime);

                if (entry is PaxTarEntry pax)
                {
                    Assert.NotNull(pax.ExtendedAttributes);
                    Assert.True(pax.ExtendedAttributes.Count >= 4);
                    Assert.Contains("path", pax.ExtendedAttributes);
                    VerifyExtendedAttributeTimestamp(pax, "mtime");
                    VerifyExtendedAttributeTimestamp(pax, "atime");
                    VerifyExtendedAttributeTimestamp(pax, "ctime");
                }
                else if (entry is GnuTarEntry gnu)
                {
                    Assert.Equal(expectedATime, gnu.AccessTime);
                    Assert.Equal(expectedCTime, gnu.ChangeTime);
                }
            }
        }
Пример #3
0
        protected void VerifyPlatformSpecificMetadata(string filePath, TarEntry entry)
        {
            Interop.Sys.FileStatus status = default;
            status.Mode = default;
            status.Dev  = default;
            Interop.CheckIo(Interop.Sys.LStat(filePath, out status));

            Assert.Equal((int)status.Uid, entry.Uid);
            Assert.Equal((int)status.Gid, entry.Gid);

            if (entry is PosixTarEntry posix)
            {
                string gname = Interop.Sys.GetGroupName(status.Gid);
                string uname = Interop.Sys.GetUserNameFromPasswd(status.Uid);

                Assert.Equal(gname, posix.GroupName);
                Assert.Equal(uname, posix.UserName);

                if (entry.EntryType is not TarEntryType.BlockDevice and not TarEntryType.CharacterDevice)
                {
                    Assert.Equal(DefaultDeviceMajor, posix.DeviceMajor);
                    Assert.Equal(DefaultDeviceMinor, posix.DeviceMinor);
                }
            }

            if (entry.EntryType is not TarEntryType.Directory)
            {
                UnixFileMode expectedMode = (UnixFileMode)(status.Mode & 4095); // First 12 bits

                Assert.Equal(expectedMode, entry.Mode);
                Assert.True(entry.ModificationTime > DateTimeOffset.UnixEpoch);

                if (entry is PaxTarEntry pax)
                {
                    VerifyExtendedAttributeTimestamps(pax);
                }

                if (entry is GnuTarEntry gnu)
                {
                    VerifyGnuTimestamps(gnu);
                }
            }
        }
Пример #4
0
        private void Verify_Extract_SpecialFiles(string destination, PosixTarEntry entry, TarEntryType entryType)
        {
            Assert.True(File.Exists(destination));

            Interop.Sys.FileStatus status = default;
            status.Mode = default;
            status.Dev  = default;
            Interop.CheckIo(Interop.Sys.LStat(destination, out status));
            int fileType = status.Mode & Interop.Sys.FileTypes.S_IFMT;

            if (entryType is TarEntryType.BlockDevice)
            {
                Assert.Equal(Interop.Sys.FileTypes.S_IFBLK, fileType);
            }
            else if (entryType is TarEntryType.CharacterDevice)
            {
                Assert.Equal(Interop.Sys.FileTypes.S_IFCHR, fileType);
            }
            else if (entryType is TarEntryType.Fifo)
            {
                Assert.Equal(Interop.Sys.FileTypes.S_IFIFO, fileType);
            }

            if (entryType is TarEntryType.BlockDevice or TarEntryType.CharacterDevice)
            {
                uint major;
                uint minor;
                unsafe
                {
                    Interop.Sys.GetDeviceIdentifiers((ulong)status.RDev, &major, &minor);
                }

                Assert.Equal((int)major, entry.DeviceMajor);
                Assert.Equal((int)minor, entry.DeviceMinor);
            }

            AssertFileModeEquals(destination, TestPermission1);
        }
Пример #5
0
        // Unix specific implementation of the method that reads an entry from disk and writes it into the archive stream.
        partial void ReadFileFromDiskAndWriteToArchiveStreamAsEntry(string fullPath, string entryName)
        {
            Interop.Sys.FileStatus status = default;
            status.Mode = default;
            status.Dev  = default;
            Interop.CheckIo(Interop.Sys.LStat(fullPath, out status));

            TarEntryType entryType = (status.Mode & (uint)Interop.Sys.FileTypes.S_IFMT) switch
            {
                // Hard links are treated as regular files.
                // Unix socket files do not get added to tar files.
                Interop.Sys.FileTypes.S_IFBLK => TarEntryType.BlockDevice,
                Interop.Sys.FileTypes.S_IFCHR => TarEntryType.CharacterDevice,
                Interop.Sys.FileTypes.S_IFIFO => TarEntryType.Fifo,
                Interop.Sys.FileTypes.S_IFLNK => TarEntryType.SymbolicLink,
                Interop.Sys.FileTypes.S_IFREG => Format is TarFormat.V7 ? TarEntryType.V7RegularFile : TarEntryType.RegularFile,
                Interop.Sys.FileTypes.S_IFDIR => TarEntryType.Directory,
                _ => throw new IOException(string.Format(SR.TarUnsupportedFile, fullPath)),
            };

            FileSystemInfo info = entryType is TarEntryType.Directory ? new DirectoryInfo(fullPath) : new FileInfo(fullPath);

            TarEntry entry = Format switch
            {
                TarFormat.V7 => new V7TarEntry(entryType, entryName),
                TarFormat.Ustar => new UstarTarEntry(entryType, entryName),
                TarFormat.Pax => new PaxTarEntry(entryType, entryName),
                TarFormat.Gnu => new GnuTarEntry(entryType, entryName),
                _ => throw new FormatException(string.Format(SR.TarInvalidFormat, Format)),
            };

            if ((entryType is TarEntryType.BlockDevice or TarEntryType.CharacterDevice) && status.Dev > 0)
            {
                uint major;
                uint minor;
                unsafe
                {
                    Interop.CheckIo(Interop.Sys.GetDeviceIdentifiers((ulong)status.Dev, &major, &minor));
                }

                entry._header._devMajor = (int)major;
                entry._header._devMinor = (int)minor;
            }

            entry._header._mTime = TarHelpers.GetDateTimeFromSecondsSinceEpoch(status.MTime);
            entry._header._aTime = TarHelpers.GetDateTimeFromSecondsSinceEpoch(status.ATime);
            entry._header._cTime = TarHelpers.GetDateTimeFromSecondsSinceEpoch(status.CTime);

            entry._header._mode = (status.Mode & 4095); // First 12 bits

            entry.Uid = (int)status.Uid;
            entry.Gid = (int)status.Gid;

            // TODO: Add these p/invokes https://github.com/dotnet/runtime/issues/68230
            entry._header._uName = ""; // Interop.Sys.GetUName();
            entry._header._gName = ""; // Interop.Sys.GetGName();

            if (entry.EntryType == TarEntryType.SymbolicLink)
            {
                entry.LinkName = info.LinkTarget ?? string.Empty;
            }

            if (entry.EntryType is TarEntryType.RegularFile or TarEntryType.V7RegularFile)
            {
                FileStreamOptions options = new()
                {
                    Mode    = FileMode.Open,
                    Access  = FileAccess.Read,
                    Share   = FileShare.Read,
                    Options = FileOptions.None
                };

                Debug.Assert(entry._header._dataStream == null);
                entry._header._dataStream = File.Open(fullPath, options);
            }

            WriteEntry(entry);
            if (entry._header._dataStream != null)
            {
                entry._header._dataStream.Dispose();
            }
        }
    }
Пример #6
0
 // Checks if the specified cache (lstat=_fileCache, stat=_symlinkCache) has the directory attribute set
 // Only call if Refresh has been successfully called at least once, and you're
 // certain the passed-in cache was successfully retrieved
 static bool CacheHasDirectoryFlag(Interop.Sys.FileStatus cache) =>
 (cache.Mode & Interop.Sys.FileTypes.S_IFMT) == Interop.Sys.FileTypes.S_IFDIR;
Пример #7
0
        // Creates an entry for writing using the specified path and entryName. If this is being called from an async method, FileOptions should contain Asynchronous.
        private TarEntry ConstructEntryForWriting(string fullPath, string entryName, FileOptions fileOptions)
        {
            Debug.Assert(!string.IsNullOrEmpty(fullPath));

            Interop.Sys.FileStatus status = default;
            status.Mode = default;
            status.Dev  = default;
            Interop.CheckIo(Interop.Sys.LStat(fullPath, out status));

            TarEntryType entryType = (status.Mode & (uint)Interop.Sys.FileTypes.S_IFMT) switch
            {
                // Hard links are treated as regular files.
                // Unix socket files do not get added to tar files.
                Interop.Sys.FileTypes.S_IFBLK => TarEntryType.BlockDevice,
                Interop.Sys.FileTypes.S_IFCHR => TarEntryType.CharacterDevice,
                Interop.Sys.FileTypes.S_IFIFO => TarEntryType.Fifo,
                Interop.Sys.FileTypes.S_IFLNK => TarEntryType.SymbolicLink,
                Interop.Sys.FileTypes.S_IFREG => Format is TarEntryFormat.V7 ? TarEntryType.V7RegularFile : TarEntryType.RegularFile,
                Interop.Sys.FileTypes.S_IFDIR => TarEntryType.Directory,
                _ => throw new IOException(string.Format(SR.TarUnsupportedFile, fullPath)),
            };

            FileSystemInfo info = entryType is TarEntryType.Directory ? new DirectoryInfo(fullPath) : new FileInfo(fullPath);

            TarEntry entry = Format switch
            {
                TarEntryFormat.V7 => new V7TarEntry(entryType, entryName),
                TarEntryFormat.Ustar => new UstarTarEntry(entryType, entryName),
                TarEntryFormat.Pax => new PaxTarEntry(entryType, entryName),
                TarEntryFormat.Gnu => new GnuTarEntry(entryType, entryName),
                _ => throw new FormatException(string.Format(SR.TarInvalidFormat, Format)),
            };

            if (entryType is TarEntryType.BlockDevice or TarEntryType.CharacterDevice)
            {
                uint major;
                uint minor;
                unsafe
                {
                    Interop.Sys.GetDeviceIdentifiers((ulong)status.RDev, &major, &minor);
                }

                entry._header._devMajor = (int)major;
                entry._header._devMinor = (int)minor;
            }

            entry._header._mTime = TarHelpers.GetDateTimeOffsetFromSecondsSinceEpoch(status.MTime);
            entry._header._aTime = TarHelpers.GetDateTimeOffsetFromSecondsSinceEpoch(status.ATime);
            entry._header._cTime = TarHelpers.GetDateTimeOffsetFromSecondsSinceEpoch(status.CTime);

            entry._header._mode = status.Mode & 4095; // First 12 bits

            // Uid and UName
            entry._header._uid = (int)status.Uid;
            if (!_userIdentifiers.TryGetValue(status.Uid, out string?uName))
            {
                uName = Interop.Sys.GetUserNameFromPasswd(status.Uid);
                _userIdentifiers.Add(status.Uid, uName);
            }
            entry._header._uName = uName;

            // Gid and GName
            entry._header._gid = (int)status.Gid;
            if (!_groupIdentifiers.TryGetValue(status.Gid, out string?gName))
            {
                gName = Interop.Sys.GetGroupName(status.Gid);
                _groupIdentifiers.Add(status.Gid, gName);
            }
            entry._header._gName = gName;

            if (entry.EntryType == TarEntryType.SymbolicLink)
            {
                entry.LinkName = info.LinkTarget ?? string.Empty;
            }

            if (entry.EntryType is TarEntryType.RegularFile or TarEntryType.V7RegularFile)
            {
                Debug.Assert(entry._header._dataStream == null);
                entry._header._dataStream = new FileStream(fullPath, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, fileOptions);
            }

            return(entry);
        }
Пример #8
0
 internal static bool IsSymLink(Interop.Sys.FileStatus fileStatus)
 {
     return((fileStatus.Mode & Interop.Sys.FileTypes.S_IFMT) == Interop.Sys.FileTypes.S_IFLNK);
 }
Пример #9
0
 internal static bool IsHidden(Interop.Sys.FileStatus fileStatus)
 {
     return((fileStatus.UserFlags & (uint)Interop.Sys.UserFlags.UF_HIDDEN) == (uint)Interop.Sys.UserFlags.UF_HIDDEN);
 }
Пример #10
0
 internal static bool IsDirectory(Interop.Sys.FileStatus fileStatus)
 {
     return((fileStatus.Mode & Interop.Sys.FileTypes.S_IFMT) == Interop.Sys.FileTypes.S_IFDIR);
 }