Пример #1
0
 static extern bool SetLxssEa(SafeFileHandle hFile, LxssEaData data, int dataLength);
Пример #2
0
        public static void ExtractTar(Stream stream, string tarRootPath, string targetPath)
        {
            targetPath = targetPath.ToExactPath();

            Utils.Log($"Extracting the tar file to \"{targetPath}\".");

            using (var tar = new TarInputStream(stream)) {
                while (true)
                {
                    var entry = tar.GetNextEntry();
                    if (entry == null)
                    {
                        break;
                    }

                    var type        = entry.TarHeader.TypeFlag;
                    var newFilePath = entry.Name.StripRootPath(tarRootPath);
                    if (newFilePath == null)
                    {
                        continue;
                    }
                    newFilePath = Path.Combine(targetPath, newFilePath.ToWslPath());

                    if (type == TarHeader.LF_LINK)
                    {
                        var linkTargetPath = entry.TarHeader.LinkName.StripRootPath(tarRootPath);
                        if (linkTargetPath == null)
                        {
                            Utils.Warning($"Igoring the hard link \"{newFilePath}\" to \"{entry.TarHeader.LinkName}\", which points to a location out of the specified root directory.");
                            continue;
                        }
                        linkTargetPath = Path.Combine(targetPath, linkTargetPath.ToWslPath());

                        using (var hTarget = GetFileHandle(linkTargetPath.ToNtPath(), false, false, false)) {
                            CheckFileHandle(hTarget, linkTargetPath);
                            if (!MakeHardLink(hTarget, newFilePath.ToNtPath()))
                            {
                                Utils.Error($"Couldn't create the hard link from \"{newFilePath}\" to \"{linkTargetPath}\".");
                            }
                        }
                    }
                    else
                    {
                        using (var hNew = GetFileHandle(newFilePath.ToNtPath(), type == TarHeader.LF_DIR, true, true)) {
                            CheckFileHandle(hNew, newFilePath);

                            var eaData = new LxssEaData {
                                Mode = entry.TarHeader.Mode,
                                Uid  = entry.UserId,
                                Gid  = entry.GroupId
                            };
                            DateTimeOffset modTime = DateTime.SpecifyKind(entry.ModTime, DateTimeKind.Utc);
                            eaData.Atime = eaData.Mtime = eaData.Ctime = modTime.ToUnixTimeSeconds();

                            switch (type)
                            {
                            case TarHeader.LF_DIR:
                                eaData.Mode |= 0x4000;
                                break;

                            case TarHeader.LF_SYMLINK:
                                eaData.Mode |= 0xa000;
                                break;

                            case TarHeader.LF_OLDNORM:
                                goto case TarHeader.LF_NORMAL;

                            case TarHeader.LF_NORMAL:
                                eaData.Mode |= 0x8000;
                                break;

                            default:
                                Utils.Warning($"Ignoring the file \"{entry.Name}\" of unsupported file type '{(char)type}'.");
                                continue;
                            }

                            if (!SetLxssEa(hNew, eaData, Marshal.SizeOf(typeof(LxssEaData))))
                            {
                                Utils.Error($"Couldn't set extended attributes of \"{newFilePath}\".");
                            }

                            if (type == TarHeader.LF_DIR)
                            {
                                continue;
                            }
                            using (var fsNew = new FileStream(hNew, FileAccess.Write)) {
                                if (entry.TarHeader.TypeFlag == TarHeader.LF_SYMLINK)
                                {
                                    var linkData = Encoding.UTF8.GetBytes(entry.TarHeader.LinkName);
                                    fsNew.Write(linkData, 0, linkData.Length);
                                }
                                else
                                {
                                    tar.CopyEntryContents(fsNew);
                                }
                            }
                        }
                    }
                }
            }
        }