forked from microsoft/VFSForGit
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathNativeUnixMethods.cs
More file actions
153 lines (136 loc) · 6.53 KB
/
Copy pathNativeUnixMethods.cs
File metadata and controls
153 lines (136 loc) · 6.53 KB
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
using GVFS.Common.Tracing;
using System;
using System.ComponentModel;
using System.IO.MemoryMappedFiles;
using System.Runtime.InteropServices;
namespace FastFetch
{
public class NativeUnixMethods
{
public const int ReadOnly = 0x0000;
public const int WriteOnly = 0x0001;
public const int Create = 0x0200;
public const int Truncate = 0x0400;
private const int InvalidFileDescriptor = -1;
private const ushort SymLinkMode = 0xA000;
public static unsafe void WriteFile(ITracer tracer, byte* originalData, long originalSize, string destination, ushort mode)
{
int fileDescriptor = InvalidFileDescriptor;
try
{
if (mode == SymLinkMode)
{
string linkTarget = Marshal.PtrToStringUTF8(new IntPtr(originalData));
int result = CreateSymLink(linkTarget, destination);
if (result == -1)
{
throw new Win32Exception(Marshal.GetLastWin32Error(), $"Failed to create symlink({linkTarget}, {destination}).");
}
}
else
{
fileDescriptor = Open(destination, WriteOnly | Create | Truncate, mode);
if (fileDescriptor == InvalidFileDescriptor)
{
throw new Win32Exception(Marshal.GetLastWin32Error(), $"Failed to open({destination}.)");
}
IntPtr result = Write(fileDescriptor, originalData, (IntPtr)originalSize);
if (result.ToInt32() == -1)
{
throw new Win32Exception(Marshal.GetLastWin32Error(), $"Failed to write contents into {destination}.");
}
}
}
catch (Win32Exception e)
{
EventMetadata metadata = new EventMetadata();
metadata.Add("filemode", mode);
metadata.Add("destination", destination);
metadata.Add("exception", e.ToString());
tracer.RelatedError(metadata, $"Failed to properly create {destination}");
throw;
}
finally
{
Close(fileDescriptor);
}
}
public static bool TryStatFileAndUpdateIndex(ITracer tracer, string path, MemoryMappedViewAccessor indexView, long offset)
{
try
{
NativeStat.StatBuffer st = StatFile(path);
Index.IndexEntry indexEntry = new Index.IndexEntry(indexView, offset);
indexEntry.MtimeSeconds = (uint)st.MTimespec.Sec;
indexEntry.MtimeNanosecondFraction = (uint)st.MTimespec.Nsec;
indexEntry.CtimeSeconds = (uint)st.CTimespec.Sec;
indexEntry.CtimeNanosecondFraction = (uint)st.CTimespec.Nsec;
indexEntry.Size = (uint)st.Size;
indexEntry.Dev = (uint)st.Dev;
indexEntry.Ino = (uint)st.Ino;
indexEntry.Uid = st.UID;
indexEntry.Gid = st.GID;
return true;
}
catch (Win32Exception e)
{
EventMetadata metadata = new EventMetadata();
metadata.Add("path", path);
metadata.Add("exception", e.ToString());
tracer.RelatedError(metadata, "Error stat-ing file.");
return false;
}
}
[DllImport("libc", EntryPoint = "open", SetLastError = true)]
public static extern int Open(string path, int flag, ushort creationMode);
[DllImport("libc", EntryPoint = "close", SetLastError = true)]
public static extern int Close(int fd);
[DllImport("libc", EntryPoint = "write", SetLastError = true)]
private static unsafe extern IntPtr Write(int fileDescriptor, void* buf, IntPtr count);
[DllImport("libc", EntryPoint = "symlink", SetLastError = true)]
private static extern int CreateSymLink(string linkTarget, string newLinkPath);
private static NativeStat.StatBuffer StatFile(string fileName)
{
NativeStat.StatBuffer statBuffer = new NativeStat.StatBuffer();
if (NativeStat.Stat(fileName, out statBuffer) != 0)
{
throw new Win32Exception(Marshal.GetLastWin32Error(), $"Failed to stat {fileName}");
}
return statBuffer;
}
private static class NativeStat
{
[DllImport("libc", EntryPoint = "stat$INODE64", SetLastError = true)]
public static extern int Stat(string path, [Out] out StatBuffer statBuffer);
[StructLayout(LayoutKind.Sequential)]
public struct TimeSpec
{
public long Sec;
public long Nsec;
}
[StructLayout(LayoutKind.Sequential)]
public struct StatBuffer
{
public int Dev; /* ID of device containing file */
public ushort Mode; /* Mode of file (see below) */
public ushort NLink; /* Number of hard links */
public ulong Ino; /* File serial number */
public uint UID; /* User ID of the file */
public uint GID; /* Group ID of the file */
public int RDev; /* Device ID */
public TimeSpec ATimespec; /* time of last access */
public TimeSpec MTimespec; /* time of last data modification */
public TimeSpec CTimespec; /* time of last status change */
public TimeSpec BirthTimespec; /* time of file creation(birth) */
public long Size; /* file size, in bytes */
public long Blocks; /* blocks allocated for file */
public int BlkSize; /* optimal blocksize for I/O */
public uint Glags; /* user defined flags for file */
public uint Gen; /* file generation number */
public int LSpare; /* RESERVED: DO NOT USE! */
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public long[] QSpare; /* RESERVED: DO NOT USE! */
}
}
}
}