View Javadoc

1   /*
2    * Copyright 2009-2009 CommonsSSH Project.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package net.sf.commons.ssh.ganymed;
17  
18  import java.io.*;
19  import java.util.ArrayList;
20  import java.util.Iterator;
21  import java.util.List;
22  
23  import net.sf.commons.ssh.SftpFile;
24  import net.sf.commons.ssh.SftpFileAttributes;
25  import net.sf.commons.ssh.SftpSession;
26  import net.sf.commons.ssh.SftpSessionOptions;
27  
28  import org.apache.commons.logging.Log;
29  import org.apache.commons.logging.LogFactory;
30  
31  import ch.ethz.ssh2.SFTPv3Client;
32  import ch.ethz.ssh2.SFTPv3DirectoryEntry;
33  import ch.ethz.ssh2.SFTPv3FileAttributes;
34  import ch.ethz.ssh2.SFTPv3FileHandle;
35  
36  /***
37   * @author Egor Ivanov (crackcraft at gmail dot com)
38   * @since 1.2
39   */
40  class GanymedSftpSession implements SftpSession {
41      static SftpFileAttributes convertFileAttributes(final SFTPv3FileAttributes a) {
42  	return new SftpFileAttributes() {
43  
44  	    public long getAccessedTime() {
45  		return (a.atime != null) ? a.atime.longValue() : 0;
46  	    }
47  
48  	    public long getGID() {
49  		return (a.gid != null) ? a.gid.longValue() : 0;
50  	    }
51  
52  	    public long getModifiedTime() {
53  		return (a.mtime != null) ? a.mtime.longValue() : 0;
54  	    }
55  
56  	    public long getPermissions() {
57  		return (a.permissions != null) ? a.permissions.longValue() : 0;
58  	    }
59  
60  	    public long getSize() {
61  		return (a.size != null) ? a.size.longValue() : 0;
62  	    }
63  
64  	    public long getUID() {
65  		return (a.uid != null) ? a.uid.longValue() : 0;
66  	    }
67  
68  	    public boolean isBlock() {
69  		return (a.permissions != null)
70  			&& ((a.permissions.intValue() & 0xF000) == 0x1000);
71  	    }
72  
73  	    public boolean isCharacter() {
74  		return (a.permissions != null)
75  			&& ((a.permissions.intValue() & 0xF000) == 0x2000);
76  	    }
77  
78  	    public boolean isDirectory() {
79  		return a.isDirectory();
80  	    }
81  
82  	    public boolean isFifo() {
83  		return (a.permissions != null)
84  			&& ((a.permissions.intValue() & 0xF000) == 0x6000);
85  	    }
86  
87  	    public boolean isFile() {
88  		return a.isRegularFile();
89  	    }
90  
91  	    public boolean isLink() {
92  		return a.isSymlink();
93  	    }
94  
95  	    public boolean isSocket() {
96  		return (a.permissions != null)
97  			&& ((a.permissions.intValue() & 0xF000) == 0xC000);
98  	    }
99  	};
100     }
101 
102     private static List convertFileList(List files) {
103 	ArrayList out = new ArrayList(files.size());
104 	for (Iterator it = files.iterator(); it.hasNext();) {
105 	    final SFTPv3DirectoryEntry f = (SFTPv3DirectoryEntry) it.next();
106 	    out.add(new SftpFile() {
107 		public String getAbsolutePath() {
108 		    return f.filename;
109 		}
110 
111 		public SftpFileAttributes getAttributes() {
112 		    return convertFileAttributes(f.attributes);
113 		}
114 
115 		public String getName() {
116 		    return (f.filename.lastIndexOf("/") < 0) ? f.filename
117 			    : f.filename
118 				    .substring(f.filename.lastIndexOf("/") + 1);
119 		}
120 	    });
121 	}
122 	return out;
123     }
124 
125     private final Log log = LogFactory.getLog(this.getClass());
126     private String lwd;
127     private String rwd;
128 
129     private final SFTPv3Client sftp;
130 
131     private int umask;
132 
133     GanymedSftpSession(final SFTPv3Client sftp, SftpSessionOptions opts)
134 	    throws IOException {
135 	log.trace("<init>");
136 	this.sftp = sftp;
137 	umask(opts.defaultPermissions);
138 	cd((opts.remoteCurrentDirectory != null) ? opts.remoteCurrentDirectory
139 		: "");
140 	lcd((opts.localCurrentDirectory != null) ? opts.localCurrentDirectory
141 		: "");
142     }
143 
144     public void cd(String dir) throws IOException {
145 	String rwd2 = sftp.canonicalPath(rpath(dir));
146 	SFTPv3FileAttributes a = sftp.stat(rwd2);
147 	if (!a.isDirectory()) {
148 	    throw new IOException(dir + " is not a directory");
149 	}
150 
151 	rwd = rwd2;
152     }
153 
154     public void chgrp(int gid, String path) throws IOException {
155 	SFTPv3FileAttributes a = new SFTPv3FileAttributes();
156 	a.gid = new Integer(gid);
157 	sftp.setstat(rpath(path), a);
158     }
159 
160     public void chmod(int permissions, String path) throws IOException {
161 	SFTPv3FileAttributes a = new SFTPv3FileAttributes();
162 	a.permissions = new Integer(permissions);
163 	sftp.setstat(rpath(path), a);
164     }
165 
166     // public void mkdirs(String dir) {
167     // sftp.mkdirs(dir);
168     // }
169 
170     public void chown(int uid, String path) throws IOException {
171 	SFTPv3FileAttributes a = new SFTPv3FileAttributes();
172 	a.uid = new Integer(uid);
173 	sftp.setstat(rpath(path), a);
174     }
175 
176     public void close() throws IOException {
177 	sftp.close();
178     }
179 
180     public void get(String path) throws IOException {
181 	get(path, path);
182     }
183 
184     public void get(String remote, OutputStream local) throws IOException {
185 	SFTPv3FileHandle h = sftp.openFileRO(rpath(remote));
186 	byte[] buff = new byte[32768];
187 	long off = 0;
188 	while (true) {
189 	    int res = sftp.read(h, off, buff, 0, buff.length);
190 	    if (res == -1) {
191 		break;
192 	    }
193 	    if (res > 0) {
194 		local.write(buff, 0, res);
195 		off += res;
196 	    }
197 
198 	}
199 	sftp.closeFile(h);
200     }
201 
202     public void get(String remote, String local) throws IOException {
203 	if ((local.lastIndexOf('/') == local.length() - 1)
204 		|| lpath(local).isDirectory()) {
205 	    int pos = remote.lastIndexOf('/');
206 	    String filename = (pos >= 0) ? remote.substring(pos + 1) : remote;
207 	    local = local + '/' + filename;
208 	}
209 	File f = lpath(local);
210 	if (!f.exists()) {
211 	    f.getParentFile().mkdirs();
212 	}
213 	OutputStream os = new FileOutputStream(f);
214 	try {
215 	    get(remote, os);
216 	} finally {
217 	    os.close();
218 	}
219     }
220 
221     public String getAbsolutePath(String path) throws IOException {
222 	return sftp.canonicalPath(rpath(path));
223     }
224 
225     public boolean isClosed() throws IOException {
226 	try {
227 	    sftp.stat(".");
228 	} catch (IOException ex) {
229 	    return true;
230 	}
231 
232 	return false;
233     }
234 
235     public void lcd(String path) throws IOException {
236 	File f = lpath(path);
237 	if (!f.isDirectory()) {
238 	    throw new IOException(path + " is not a directory");
239 	}
240 	lwd = f.getCanonicalPath();
241     }
242 
243     private File lpath(String path) {
244 	File f = new File(path);
245 	if (!f.isAbsolute()) {
246 	    f = new File(((lwd != null) ? lwd : ""), path);
247 	}
248 	return f;
249     }
250 
251     public String lpwd() {
252 	return lwd;
253     }
254 
255     public List ls() throws IOException {
256 	return ls(".");
257     }
258 
259     public List ls(String path) throws IOException {
260 	return convertFileList(sftp.ls(rpath(path)));
261     }
262 
263     public void mkdir(String dir) throws IOException {
264 	sftp.mkdir(rpath(dir), 0777 ^ umask);
265     }
266 
267     public void put(InputStream in, String remote) throws IOException {
268 	SFTPv3FileAttributes a = new SFTPv3FileAttributes();
269 	a.permissions = new Integer(0777 ^ umask);
270 	SFTPv3FileHandle h = sftp.createFileTruncate(rpath(remote), a);
271 	byte[] buff = new byte[32768];
272 	long off = 0;
273 	while (true) {
274 	    int res = in.read(buff);
275 	    if (res == -1) {
276 		break;
277 	    }
278 	    if (res > 0) {
279 		sftp.write(h, off, buff, 0, res);
280 		off += res;
281 	    }
282 	}
283 	sftp.closeFile(h);
284     }
285 
286     public void put(String local) throws IOException {
287 	put(local, local);
288     }
289 
290     public void put(String local, String remote) throws IOException {
291 	File f = lpath(local);
292 	if (!f.exists() && !f.isFile()) {
293 	    throw new IOException("File not found " + f.getCanonicalPath());
294 	}
295 	if (remote.lastIndexOf('/') == remote.length() - 1) {
296 	    remote = remote + f.getName();
297 	}
298 	InputStream is = new FileInputStream(f);
299 	try {
300 	    put(is, remote);
301 	} finally {
302 	    is.close();
303 	}
304     }
305 
306     public String pwd() throws IOException {
307 	return rpath("");
308     }
309 
310     // public void rm(String path, boolean force, boolean recurse) throws
311     // IOException {
312     // sftp.rm(path, force, recurse);
313     // }
314 
315     public void rename(String oldpath, String newpath) throws IOException {
316 	sftp.mv(rpath(oldpath), rpath(newpath));
317     }
318 
319     public void rm(String path) throws IOException {
320 	SFTPv3FileAttributes a = sftp.stat(rpath(path));
321 	if (a.isDirectory()) {
322 	    sftp.rmdir(rpath(path));
323 	} else {
324 	    sftp.rm(rpath(path));
325 	}
326     }
327 
328     private String rpath(String path) throws IOException {
329 	if (path.startsWith("/")) {
330 	    return path;
331 	}
332 	if (rwd == null) {
333 	    rwd = sftp.canonicalPath("");
334 	}
335 	return rwd + (rwd.endsWith("/") ? "" : "/") + path;
336     }
337 
338     public SftpFileAttributes stat(String path) throws IOException {
339 	return convertFileAttributes(sftp.stat(rpath(path)));
340     }
341 
342     public void symlink(String path, String link) throws IOException {
343 	// TODO test relative links.
344 	// ex: rwd = /home/xxx, path=../yyy link=zzz
345 	// : /home/xxx/zzz -> ../yyy, NOT -> /home/yyy
346 	sftp.createSymlink(path, rpath(link));
347     }
348 
349     public void umask(int umask) {
350 	this.umask = umask;
351     }
352 }