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.file.FileVisitOption;
17  import java.nio.file.FileVisitResult;
18  import java.nio.file.Files;
19  import java.nio.file.LinkOption;
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 		if (!Files.isDirectory(directory.toPath(), LinkOption.NOFOLLOW_LINKS)) {
101 			return NO_ENTRIES;
102 		}
103 		List<Entry> result = new ArrayList<>();
104 		FS fs = this;
105 		boolean checkExecutable = fs.supportsExecute();
106 		try {
107 			Files.walkFileTree(directory.toPath(),
108 					EnumSet.noneOf(FileVisitOption.class), 1,
109 					new SimpleFileVisitor<Path>() {
110 						@Override
111 						public FileVisitResult visitFile(Path file,
112 								BasicFileAttributes attrs) throws IOException {
113 							File f = file.toFile();
114 							FS.Attributes attributes = new FS.Attributes(fs, f,
115 									true, attrs.isDirectory(),
116 									checkExecutable && f.canExecute(),
117 									attrs.isSymbolicLink(),
118 									attrs.isRegularFile(),
119 									attrs.creationTime().toMillis(),
120 									attrs.lastModifiedTime().toInstant(),
121 									attrs.size());
122 							result.add(new FileEntry(f, fs, attributes,
123 									fileModeStrategy));
124 							return FileVisitResult.CONTINUE;
125 						}
126 
127 						@Override
128 						public FileVisitResult visitFileFailed(Path file,
129 								IOException exc) throws IOException {
130 							// Just ignore it
131 							return FileVisitResult.CONTINUE;
132 						}
133 					});
134 		} catch (IOException e) {
135 			// Ignore
136 		}
137 		if (result.isEmpty()) {
138 			return NO_ENTRIES;
139 		}
140 		return result.toArray(new Entry[0]);
141 	}
142 
143 	/** {@inheritDoc} */
144 	@Override
145 	protected File discoverGitExe() {
146 		String path = SystemReader.getInstance().getenv("PATH"); //$NON-NLS-1$
147 		File gitExe = searchPath(path, "git.exe", "git.cmd"); //$NON-NLS-1$ //$NON-NLS-2$
148 
149 		if (gitExe == null) {
150 			if (searchPath(path, "bash.exe") != null) { //$NON-NLS-1$
151 				// This isn't likely to work, but its worth trying:
152 				// If bash is in $PATH, git should also be in $PATH.
153 				String w;
154 				try {
155 					w = readPipe(userHome(),
156 							new String[] { "bash", "--login", "-c", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
157 									"which git" }, // //$NON-NLS-1$
158 							SystemReader.getInstance().getDefaultCharset()
159 									.name());
160 				} catch (CommandFailedException e) {
161 					LOG.warn(e.getMessage());
162 					return null;
163 				}
164 				if (!StringUtils.isEmptyOrNull(w)) {
165 					// The path may be in cygwin/msys notation so resolve it right away
166 					gitExe = resolve(null, w);
167 				}
168 			}
169 		}
170 
171 		return gitExe;
172 	}
173 
174 	/** {@inheritDoc} */
175 	@Override
176 	protected File userHomeImpl() {
177 		String home = SystemReader.getInstance().getenv("HOME"); //$NON-NLS-1$
178 		if (home != null) {
179 			return resolve(null, home);
180 		}
181 		String homeDrive = SystemReader.getInstance().getenv("HOMEDRIVE"); //$NON-NLS-1$
182 		if (homeDrive != null) {
183 			String homePath = SystemReader.getInstance().getenv("HOMEPATH"); //$NON-NLS-1$
184 			if (homePath != null) {
185 				return new File(homeDrive, homePath);
186 			}
187 		}
188 
189 		String homeShare = SystemReader.getInstance().getenv("HOMESHARE"); //$NON-NLS-1$
190 		if (homeShare != null) {
191 			return new File(homeShare);
192 		}
193 
194 		return super.userHomeImpl();
195 	}
196 
197 	/** {@inheritDoc} */
198 	@Override
199 	public ProcessBuilder runInShell(String cmd, String[] args) {
200 		List<String> argv = new ArrayList<>(3 + args.length);
201 		argv.add("cmd.exe"); //$NON-NLS-1$
202 		argv.add("/c"); //$NON-NLS-1$
203 		argv.add(cmd);
204 		argv.addAll(Arrays.asList(args));
205 		ProcessBuilder proc = new ProcessBuilder();
206 		proc.command(argv);
207 		return proc;
208 	}
209 
210 	/** {@inheritDoc} */
211 	@Override
212 	public Attributes getAttributes(File path) {
213 		return FileUtils.getFileAttributesBasic(this, path);
214 	}
215 }