View Javadoc
1   /*
2    * Copyright (C) 2009, Google Inc.
3    * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others
4    *
5    * This program and the accompanying materials are made available under the
6    * terms of the Eclipse Distribution License v. 1.0 which is available at
7    * https://www.eclipse.org/org/documents/edl-v10.php.
8    *
9    * SPDX-License-Identifier: BSD-3-Clause
10   */
11  
12  package org.eclipse.jgit.util;
13  
14  import java.io.File;
15  import java.io.IOException;
16  import java.nio.charset.Charset;
17  import java.nio.file.FileVisitOption;
18  import java.nio.file.FileVisitResult;
19  import java.nio.file.Files;
20  import java.nio.file.Path;
21  import java.nio.file.SimpleFileVisitor;
22  import java.nio.file.attribute.BasicFileAttributes;
23  import java.util.ArrayList;
24  import java.util.Arrays;
25  import java.util.EnumSet;
26  import java.util.List;
27  
28  import org.eclipse.jgit.errors.CommandFailedException;
29  import org.eclipse.jgit.treewalk.FileTreeIterator.FileEntry;
30  import org.eclipse.jgit.treewalk.FileTreeIterator.FileModeStrategy;
31  import org.eclipse.jgit.treewalk.WorkingTreeIterator.Entry;
32  import org.slf4j.Logger;
33  import org.slf4j.LoggerFactory;
34  
35  
36  /**
37   * FS implementation for Windows
38   *
39   * @since 3.0
40   */
41  public class FS_Win32 extends FS {
42  	private static final Logger LOG = LoggerFactory.getLogger(FS_Win32.class);
43  
44  	/**
45  	 * Constructor
46  	 */
47  	public FS_Win32() {
48  		super();
49  	}
50  
51  	/**
52  	 * Constructor
53  	 *
54  	 * @param src
55  	 *            instance whose attributes to copy
56  	 */
57  	protected FS_Win32(FS src) {
58  		super(src);
59  	}
60  
61  	/** {@inheritDoc} */
62  	@Override
63  	public FS newInstance() {
64  		return new FS_Win32(this);
65  	}
66  
67  	/** {@inheritDoc} */
68  	@Override
69  	public boolean supportsExecute() {
70  		return false;
71  	}
72  
73  	/** {@inheritDoc} */
74  	@Override
75  	public boolean canExecute(File f) {
76  		return false;
77  	}
78  
79  	/** {@inheritDoc} */
80  	@Override
81  	public boolean setExecute(File f, boolean canExec) {
82  		return false;
83  	}
84  
85  	/** {@inheritDoc} */
86  	@Override
87  	public boolean isCaseSensitive() {
88  		return false;
89  	}
90  
91  	/** {@inheritDoc} */
92  	@Override
93  	public boolean retryFailedLockFileCommit() {
94  		return true;
95  	}
96  
97  	/** {@inheritDoc} */
98  	@Override
99  	public Entry[] list(File directory, FileModeStrategy fileModeStrategy) {
100 		List<Entry> result = new ArrayList<>();
101 		FS fs = this;
102 		boolean checkExecutable = fs.supportsExecute();
103 		try {
104 			Files.walkFileTree(directory.toPath(),
105 					EnumSet.noneOf(FileVisitOption.class), 1,
106 					new SimpleFileVisitor<Path>() {
107 						@Override
108 						public FileVisitResult visitFile(Path file,
109 								BasicFileAttributes attrs) throws IOException {
110 							File f = file.toFile();
111 							FS.Attributes attributes = new FS.Attributes(fs, f,
112 									true, attrs.isDirectory(),
113 									checkExecutable && f.canExecute(),
114 									attrs.isSymbolicLink(),
115 									attrs.isRegularFile(),
116 									attrs.creationTime().toMillis(),
117 									attrs.lastModifiedTime().toInstant(),
118 									attrs.size());
119 							result.add(new FileEntry(f, fs, attributes,
120 									fileModeStrategy));
121 							return FileVisitResult.CONTINUE;
122 						}
123 
124 						@Override
125 						public FileVisitResult visitFileFailed(Path file,
126 								IOException exc) throws IOException {
127 							// Just ignore it
128 							return FileVisitResult.CONTINUE;
129 						}
130 					});
131 		} catch (IOException e) {
132 			// Ignore
133 		}
134 		if (result.isEmpty()) {
135 			return NO_ENTRIES;
136 		}
137 		return result.toArray(new Entry[0]);
138 	}
139 
140 	/** {@inheritDoc} */
141 	@Override
142 	protected File discoverGitExe() {
143 		String path = SystemReader.getInstance().getenv("PATH"); //$NON-NLS-1$
144 		File gitExe = searchPath(path, "git.exe", "git.cmd"); //$NON-NLS-1$ //$NON-NLS-2$
145 
146 		if (gitExe == null) {
147 			if (searchPath(path, "bash.exe") != null) { //$NON-NLS-1$
148 				// This isn't likely to work, but its worth trying:
149 				// If bash is in $PATH, git should also be in $PATH.
150 				String w;
151 				try {
152 					w = readPipe(userHome(),
153 						new String[]{"bash", "--login", "-c", "which git"}, // //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
154 						Charset.defaultCharset().name());
155 				} catch (CommandFailedException e) {
156 					LOG.warn(e.getMessage());
157 					return null;
158 				}
159 				if (!StringUtils.isEmptyOrNull(w)) {
160 					// The path may be in cygwin/msys notation so resolve it right away
161 					gitExe = resolve(null, w);
162 				}
163 			}
164 		}
165 
166 		return gitExe;
167 	}
168 
169 	/** {@inheritDoc} */
170 	@Override
171 	protected File userHomeImpl() {
172 		String home = SystemReader.getInstance().getenv("HOME"); //$NON-NLS-1$
173 		if (home != null) {
174 			return resolve(null, home);
175 		}
176 		String homeDrive = SystemReader.getInstance().getenv("HOMEDRIVE"); //$NON-NLS-1$
177 		if (homeDrive != null) {
178 			String homePath = SystemReader.getInstance().getenv("HOMEPATH"); //$NON-NLS-1$
179 			if (homePath != null) {
180 				return new File(homeDrive, homePath);
181 			}
182 		}
183 
184 		String homeShare = SystemReader.getInstance().getenv("HOMESHARE"); //$NON-NLS-1$
185 		if (homeShare != null) {
186 			return new File(homeShare);
187 		}
188 
189 		return super.userHomeImpl();
190 	}
191 
192 	/** {@inheritDoc} */
193 	@Override
194 	public ProcessBuilder runInShell(String cmd, String[] args) {
195 		List<String> argv = new ArrayList<>(3 + args.length);
196 		argv.add("cmd.exe"); //$NON-NLS-1$
197 		argv.add("/c"); //$NON-NLS-1$
198 		argv.add(cmd);
199 		argv.addAll(Arrays.asList(args));
200 		ProcessBuilder proc = new ProcessBuilder();
201 		proc.command(argv);
202 		return proc;
203 	}
204 
205 	/** {@inheritDoc} */
206 	@Override
207 	public Attributes getAttributes(File path) {
208 		return FileUtils.getFileAttributesBasic(this, path);
209 	}
210 }