Welcome to mirror list, hosted at ThFree Co, Russian Federation.

Archiving.Utils.Windows.cs « IO « System « src « Common « libraries « src - github.com/dotnet/runtime.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: beceebc5604368b11c44ab5bfd26e203ac6c2c08 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Runtime.InteropServices;
using System.Text;

namespace System.IO
{
    internal static partial class ArchivingUtils
    {
        internal static string SanitizeEntryFilePath(string entryPath)
        {
            // Find the first illegal character in the entry path.
            for (int i = 0; i < entryPath.Length; i++)
            {
                switch (entryPath[i])
                {
                    // We found at least one character that needs to be replaced.
                    case < (char)32 or '?' or ':' or '*' or '"' or '<' or '>' or '|':
                        return string.Create(entryPath.Length, (i, entryPath), (dest, state) =>
                        {
                            string entryPath = state.entryPath;

                            // Copy over to the new string everything until the character, then
                            // substitute for the found character.
                            entryPath.AsSpan(0, state.i).CopyTo(dest);
                            dest[state.i] = '_';

                            // Continue looking for and replacing any more illegal characters.
                            for (int i = state.i + 1; i < entryPath.Length; i++)
                            {
                                char c = entryPath[i];
                                dest[i] = c switch
                                {
                                    < (char)32 or '?' or ':' or '*' or '"' or '<' or '>' or '|' => '_',
                                    _ => c,
                                };
                            }
                        });
                }
            }

            // There weren't any characters to sanitize.  Just return the original string.
            return entryPath;
        }

        public static unsafe string EntryFromPath(ReadOnlySpan<char> path, bool appendPathSeparator = false)
        {
            // Remove leading separators.
            int nonSlash = path.IndexOfAnyExcept('/', '\\');
            if (nonSlash < 0)
            {
                nonSlash = path.Length;
            }
            path = path.Slice(nonSlash);

            // Replace \ with /, and append a separator if necessary.

            if (path.IsEmpty)
            {
                return appendPathSeparator ?
                    "/" :
                    string.Empty;
            }

            fixed (char* pathPtr = &MemoryMarshal.GetReference(path))
            {
                return string.Create(appendPathSeparator ? path.Length + 1 : path.Length, (appendPathSeparator, (IntPtr)pathPtr, path.Length), static (dest, state) =>
                {
                    ReadOnlySpan<char> path = new ReadOnlySpan<char>((char*)state.Item2, state.Length);
                    path.CopyTo(dest);
                    if (state.appendPathSeparator)
                    {
                        dest[^1] = '/';
                    }

                    // To ensure tar files remain compatible with Unix, and per the ZIP File Format Specification 4.4.17.1,
                    // all slashes should be forward slashes.
                    dest.Replace('\\', '/');
                });
            }
        }
    }
}