This repository was archived by the owner on May 9, 2022. It is now read-only.
forked from microsoft/VFSForGit
-
Notifications
You must be signed in to change notification settings - Fork 16
Expand file tree
/
Copy pathLinuxFileSystem.cs
More file actions
162 lines (133 loc) · 5.92 KB
/
LinuxFileSystem.cs
File metadata and controls
162 lines (133 loc) · 5.92 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
154
155
156
157
158
159
160
161
162
using GVFS.Common;
using GVFS.Platform.POSIX;
using System;
using System.Runtime.InteropServices;
namespace GVFS.Platform.Linux
{
public class LinuxFileSystem : POSIXFileSystem
{
public override void ChangeMode(string path, ushort mode)
{
Chmod(path, mode);
}
public override bool HydrateFile(string fileName, byte[] buffer)
{
return NativeFileReader.TryReadFirstByteOfFile(fileName, buffer);
}
public override bool IsExecutable(string fileName)
{
NativeStat.StatBuffer statBuffer = this.StatFile(fileName);
return NativeStat.IsExecutable(statBuffer.Mode);
}
public override bool IsSocket(string fileName)
{
NativeStat.StatBuffer statBuffer = this.StatFile(fileName);
return NativeStat.IsSock(statBuffer.Mode);
}
[DllImport("libc", EntryPoint = "chmod", SetLastError = true)]
private static extern int Chmod(string pathname, uint mode);
private NativeStat.StatBuffer StatFile(string fileName)
{
if (NativeStat.Stat(fileName, out NativeStat.StatBuffer statBuffer) != 0)
{
NativeMethods.ThrowLastWin32Exception($"Failed to stat {fileName}");
}
return statBuffer;
}
private static class NativeStat
{
// #define S_IFMT 0170000 /* [XSI] type of file mask */
private static readonly uint IFMT = Convert.ToUInt32("170000", 8);
// #define S_IFSOCK 0140000 /* [XSI] socket */
private static readonly uint IFSOCK = Convert.ToUInt32("0140000", 8);
// #define S_IXUSR 0000100 /* [XSI] X for owner */
private static readonly uint IXUSR = Convert.ToUInt32("100", 8);
// #define S_IXGRP 0000010 /* [XSI] X for group */
private static readonly uint IXGRP = Convert.ToUInt32("10", 8);
// #define S_IXOTH 0000001 /* [XSI] X for other */
private static readonly uint IXOTH = Convert.ToUInt32("1", 8);
// #define _STAT_VER 1
private static readonly int STAT_VER = 1;
public static bool IsSock(uint mode)
{
// #define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) /* socket */
return (mode & IFMT) == IFSOCK;
}
public static bool IsExecutable(uint mode)
{
return (mode & (IXUSR | IXGRP | IXOTH)) != 0;
}
public static int Stat(string path, [Out] out StatBuffer buf)
{
return __XStat64(STAT_VER, path, out buf);
}
// TODO(Linux): assumes recent GNU libc or ABI-compatible libc
[DllImport("libc", EntryPoint = "__xstat64", SetLastError = true)]
public static extern int __XStat64(int vers, string path, [Out] out StatBuffer buf);
[StructLayout(LayoutKind.Sequential)]
public struct TimeSpec
{
public long Sec;
public long Nsec;
}
// TODO(Linux): assumes stat64 field layout of x86-64 architecture
[StructLayout(LayoutKind.Sequential)]
public struct StatBuffer
{
public ulong Dev; /* ID of device containing file */
public ulong Ino; /* File serial number */
public ulong NLink; /* Number of hard links */
public uint Mode; /* Mode of file (see below) */
public uint UID; /* User ID of the file */
public uint GID; /* Group ID of the file */
public uint Padding; /* RESERVED: DO NOT USE! */
public ulong RDev; /* Device ID if special file */
public long Size; /* file size, in bytes */
public long BlkSize; /* optimal blocksize for I/O */
public long Blocks; /* blocks allocated for file */
public TimeSpec ATimespec; /* time of last access */
public TimeSpec MTimespec; /* time of last data modification */
public TimeSpec CTimespec; /* time of last status change */
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public long[] Reserved; /* RESERVED: DO NOT USE! */
}
}
private static class NativeFileReader
{
private const int ReadOnly = 0x0000;
internal static bool TryReadFirstByteOfFile(string fileName, byte[] buffer)
{
int fileDescriptor = -1;
bool readStatus = false;
try
{
fileDescriptor = Open(fileName, ReadOnly);
if (fileDescriptor != -1)
{
readStatus = TryReadOneByte(fileDescriptor, buffer);
}
}
finally
{
Close(fileDescriptor);
}
return readStatus;
}
[DllImport("libc", EntryPoint = "open", SetLastError = true)]
private static extern int Open(string path, int flag);
[DllImport("libc", EntryPoint = "close", SetLastError = true)]
private static extern int Close(int fd);
[DllImport("libc", EntryPoint = "read", SetLastError = true)]
private static extern long Read(int fd, [Out] byte[] buf, ulong count);
private static bool TryReadOneByte(int fileDescriptor, byte[] buffer)
{
long numBytes = Read(fileDescriptor, buffer, 1);
if (numBytes == -1)
{
return false;
}
return true;
}
}
}
}