2
This code is derived from jgit (http://eclipse.org/jgit).
3
Copyright owners are documented in jgit's IP log.
5
This program and the accompanying materials are made available
6
under the terms of the Eclipse Distribution License v1.0 which
7
accompanies this distribution, is reproduced below, and is
8
available at http://www.eclipse.org/org/documents/edl-v10.php
12
Redistribution and use in source and binary forms, with or
13
without modification, are permitted provided that the following
16
- Redistributions of source code must retain the above copyright
17
notice, this list of conditions and the following disclaimer.
19
- Redistributions in binary form must reproduce the above
20
copyright notice, this list of conditions and the following
21
disclaimer in the documentation and/or other materials provided
22
with the distribution.
24
- Neither the name of the Eclipse Foundation, Inc. nor the
25
names of its contributors may be used to endorse or promote
26
products derived from this software without specific prior
29
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
30
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
31
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
32
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
34
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
36
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
38
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
41
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
45
using System.Diagnostics;
52
/// <summary>Abstraction to support various file system operations not in Java.</summary>
53
/// <remarks>Abstraction to support various file system operations not in Java.</remarks>
54
public abstract class FS
56
/// <summary>The auto-detected implementation selected for this operating system and JRE.
58
/// <remarks>The auto-detected implementation selected for this operating system and JRE.
60
public static readonly NGit.Util.FS DETECTED = Detect();
62
/// <summary>Auto-detect the appropriate file system abstraction.</summary>
63
/// <remarks>Auto-detect the appropriate file system abstraction.</remarks>
64
/// <returns>detected file system abstraction</returns>
65
public static NGit.Util.FS Detect()
71
/// Auto-detect the appropriate file system abstraction, taking into account
72
/// the presence of a Cygwin installation on the system.
75
/// Auto-detect the appropriate file system abstraction, taking into account
76
/// the presence of a Cygwin installation on the system. Using jgit in
77
/// combination with Cygwin requires a more elaborate (and possibly slower)
78
/// resolution of file system paths.
80
/// <param name="cygwinUsed">
82
/// <li><code>Boolean.TRUE</code> to assume that Cygwin is used in
83
/// combination with jgit</li>
84
/// <li><code>Boolean.FALSE</code> to assume that Cygwin is
85
/// <b>not</b> used with jgit</li>
86
/// <li><code>null</code> to auto-detect whether a Cygwin
87
/// installation is present on the system and in this case assume
88
/// that Cygwin is used</li>
90
/// Note: this parameter is only relevant on Windows.
92
/// <returns>detected file system abstraction</returns>
93
public static NGit.Util.FS Detect(bool? cygwinUsed)
95
if (FS_Win32.IsWin32())
97
if (cygwinUsed == null)
99
cygwinUsed = Sharpen.Extensions.ValueOf(FS_Win32_Cygwin.IsCygwin());
101
if (cygwinUsed.Value)
103
return new FS_Win32_Cygwin();
107
return new FS_Win32();
112
if (FS_POSIX_Java6.HasExecute())
114
return new FS_POSIX_Java6();
118
return new FS_POSIX_Java5();
123
private volatile FS.Holder<FilePath> userHome;
125
private volatile FS.Holder<FilePath> gitPrefix;
127
/// <summary>Constructs a file system abstraction.</summary>
128
/// <remarks>Constructs a file system abstraction.</remarks>
133
/// <summary>Initialize this FS using another's current settings.</summary>
134
/// <remarks>Initialize this FS using another's current settings.</remarks>
135
/// <param name="src">the source FS to copy from.</param>
136
protected internal FS(NGit.Util.FS src)
138
// Do nothing by default.
139
userHome = src.userHome;
140
gitPrefix = src.gitPrefix;
143
/// <returns>a new instance of the same type of FS.</returns>
144
public abstract NGit.Util.FS NewInstance();
146
/// <summary>Does this operating system and JRE support the execute flag on files?</summary>
148
/// true if this implementation can provide reasonably accurate
149
/// executable bit information; false otherwise.
151
public abstract bool SupportsExecute();
153
/// <summary>Determine if the file is executable (or not).</summary>
155
/// Determine if the file is executable (or not).
157
/// Not all platforms and JREs support executable flags on files. If the
158
/// feature is unsupported this method will always return false.
160
/// <param name="f">abstract path to test.</param>
161
/// <returns>true if the file is believed to be executable by the user.</returns>
162
public abstract bool CanExecute(FilePath f);
164
/// <summary>Set a file to be executable by the user.</summary>
166
/// Set a file to be executable by the user.
168
/// Not all platforms and JREs support executable flags on files. If the
169
/// feature is unsupported this method will always return false and no
170
/// changes will be made to the file specified.
172
/// <param name="f">path to modify the executable status of.</param>
173
/// <param name="canExec">true to enable execution; false to disable it.</param>
174
/// <returns>true if the change succeeded; false otherwise.</returns>
175
public abstract bool SetExecute(FilePath f, bool canExec);
177
/// <summary>Resolve this file to its actual path name that the JRE can use.</summary>
179
/// Resolve this file to its actual path name that the JRE can use.
181
/// This method can be relatively expensive. Computing a translation may
182
/// require forking an external process per path name translated. Callers
183
/// should try to minimize the number of translations necessary by caching
186
/// Not all platforms and JREs require path name translation. Currently only
187
/// Cygwin on Win32 require translation for Cygwin based paths.
189
/// <param name="dir">directory relative to which the path name is.</param>
190
/// <param name="name">path name to translate.</param>
192
/// the translated path. <code>new File(dir,name)</code> if this
193
/// platform does not require path name translation.
195
public virtual FilePath Resolve(FilePath dir, string name)
197
FilePath abspn = new FilePath(name);
198
if (abspn.IsAbsolute())
202
return new FilePath(dir, name);
205
/// <summary>Determine the user's home directory (location where preferences are).</summary>
207
/// Determine the user's home directory (location where preferences are).
209
/// This method can be expensive on the first invocation if path name
210
/// translation is required. Subsequent invocations return a cached result.
212
/// Not all platforms and JREs require path name translation. Currently only
213
/// Cygwin on Win32 requires translation of the Cygwin HOME directory.
215
/// <returns>the user's home directory; null if the user does not have one.</returns>
216
public virtual FilePath UserHome()
218
FS.Holder<FilePath> p = userHome;
221
p = new FS.Holder<FilePath>(UserHomeImpl());
227
/// <summary>Set the user's home directory location.</summary>
228
/// <remarks>Set the user's home directory location.</remarks>
229
/// <param name="path">
230
/// the location of the user's preferences; null if there is no
231
/// home directory for the current user.
235
/// <code>this</code>
238
public virtual NGit.Util.FS SetUserHome(FilePath path)
240
userHome = new FS.Holder<FilePath>(path);
244
/// <summary>Does this file system have problems with atomic renames?</summary>
245
/// <returns>true if the caller should retry a failed rename of a lock file.</returns>
246
public abstract bool RetryFailedLockFileCommit();
248
/// <summary>Determine the user's home directory (location where preferences are).</summary>
249
/// <remarks>Determine the user's home directory (location where preferences are).</remarks>
250
/// <returns>the user's home directory; null if the user does not have one.</returns>
251
protected internal virtual FilePath UserHomeImpl()
253
string home = AccessController.DoPrivileged(new _PrivilegedAction_234());
254
if (home == null || home.Length == 0)
258
return new FilePath(home).GetAbsoluteFile();
261
private sealed class _PrivilegedAction_234 : PrivilegedAction<string>
263
public _PrivilegedAction_234()
269
return Runtime.GetProperty("user.home");
273
internal static FilePath SearchPath(string path, params string[] lookFor)
275
foreach (string p in path.Split(FilePath.pathSeparator))
277
foreach (string command in lookFor)
279
FilePath e = new FilePath(p, command);
282
return e.GetAbsoluteFile();
289
/// <summary>Execute a command and return a single line of output as a String</summary>
290
/// <param name="dir">Working directory for the command</param>
291
/// <param name="command">as component array</param>
292
/// <param name="encoding"></param>
293
/// <returns>the one-line output of the command</returns>
294
protected internal static string ReadPipe(FilePath dir, string[] command, string
299
SystemProcess p = Runtime.GetRuntime().Exec(command, null, dir);
300
BufferedReader lineRead = new BufferedReader(new InputStreamReader(p.GetInputStream
305
r = lineRead.ReadLine();
309
p.GetOutputStream().Close();
310
p.GetErrorStream().Close();
317
if (p.WaitFor() == 0 && r != null && r.Length > 0)
328
catch (IOException e)
330
// Stop bothering me, I have a zombie to reap.
331
if (SystemReader.GetInstance().GetProperty("jgit.fs.debug") != null)
333
System.Console.Error.WriteLine(e);
336
// Ignore error (but report)
340
/// <returns>the $prefix directory C Git would use.</returns>
341
public virtual FilePath GitPrefix()
343
FS.Holder<FilePath> p = gitPrefix;
346
string overrideGitPrefix = SystemReader.GetInstance().GetProperty("jgit.gitprefix"
348
if (overrideGitPrefix != null)
350
p = new FS.Holder<FilePath>(new FilePath(overrideGitPrefix));
354
p = new FS.Holder<FilePath>(DiscoverGitPrefix());
361
/// <returns>the $prefix directory C Git would use.</returns>
362
protected internal abstract FilePath DiscoverGitPrefix();
364
/// <summary>Set the $prefix directory C Git uses.</summary>
365
/// <remarks>Set the $prefix directory C Git uses.</remarks>
366
/// <param name="path">the directory. Null if C Git is not installed.</param>
369
/// <code>this</code>
371
public virtual NGit.Util.FS SetGitPrefix(FilePath path)
373
gitPrefix = new FS.Holder<FilePath>(path);
377
/// <summary>Initialize a ProcesssBuilder to run a command using the system shell.</summary>
378
/// <remarks>Initialize a ProcesssBuilder to run a command using the system shell.</remarks>
379
/// <param name="cmd">
380
/// command to execute. This string should originate from the
381
/// end-user, and thus is platform specific.
383
/// <param name="args">
384
/// arguments to pass to command. These should be protected from
385
/// shell evaluation.
388
/// a partially completed process builder. Caller should finish
389
/// populating directory, environment, and then start the process.
391
public abstract ProcessStartInfo RunInShell(string cmd, string[] args);
393
private class Holder<V>
395
internal readonly V value;
397
internal Holder(V value)