1 5 package org.h2.server.ftp; 6 7 import java.io.ByteArrayInputStream ; 8 import java.io.ByteArrayOutputStream ; 9 import java.io.File ; 10 import java.io.FileOutputStream ; 11 import java.io.IOException ; 12 import java.io.InputStream ; 13 import java.io.OutputStream ; 14 import java.net.ServerSocket ; 15 import java.net.Socket ; 16 import java.sql.Connection ; 17 import java.sql.DriverManager ; 18 import java.sql.SQLException ; 19 import java.text.SimpleDateFormat ; 20 import java.util.Date ; 21 import java.util.HashMap ; 22 import java.util.Locale ; 23 import java.util.Properties ; 24 25 import org.h2.engine.Constants; 26 import org.h2.server.Service; 27 import org.h2.util.IOUtils; 28 import org.h2.util.MathUtils; 29 import org.h2.util.NetUtils; 30 31 35 public class FtpServer implements Service { 36 37 public static final String DEFAULT_ROOT = "ftp"; 38 public static final String DEFAULT_READ = "guest"; 39 public static final String DEFAULT_WRITE = "sa"; 40 public static final String DEFAULT_WRITE_PASSWORD = "sa"; 41 42 private ServerSocket serverSocket; 43 private int port = Constants.DEFAULT_FTP_PORT; 44 private int openConnectionCount; 45 private int maxConnectionCount = 100; 46 47 private SimpleDateFormat dateFormatNew = new SimpleDateFormat ("MMM dd HH:mm", Locale.ENGLISH); 48 private SimpleDateFormat dateFormatOld = new SimpleDateFormat ("MMM dd yyyy", Locale.ENGLISH); 49 private SimpleDateFormat dateFormat = new SimpleDateFormat ("yyyyMMddHHmmss"); 50 51 private String root = DEFAULT_ROOT; 52 private String writeUserName = DEFAULT_WRITE, writePassword = DEFAULT_WRITE_PASSWORD; 53 private String readUserName = DEFAULT_READ; 54 private HashMap tasks = new HashMap (); 55 56 private FileSystemDatabase db; 57 private boolean log; 58 private boolean allowTask; 59 static final String TASK_SUFFIX = ".task"; 60 61 public void listen() { 62 try { 63 while (serverSocket != null) { 64 Socket s = serverSocket.accept(); 65 boolean stop; 66 synchronized(this) { 67 openConnectionCount++; 68 stop = openConnectionCount > maxConnectionCount; 69 } 70 FtpControl c = new FtpControl(s, this, stop); 71 c.start(); 72 } 73 } catch (Exception e) { 74 logError(e); 75 } 76 } 77 78 void closeConnection() { 79 synchronized(this) { 80 openConnectionCount--; 81 } 82 } 83 84 public ServerSocket createDataSocket() throws IOException { 85 ServerSocket dataSocket = new ServerSocket (0); 86 return dataSocket; 87 } 88 89 void appendFile(StringBuffer buff, FileObject f) { 90 buff.append(f.isDirectory() ? 'd' : '-'); 91 buff.append(f.canRead() ? 'r' : '-'); 92 buff.append(f.canWrite() ? 'w' : '-'); 93 buff.append("------- 1 owner group "); 94 String size = String.valueOf(f.length()); 95 for(int i = size.length(); i < 15; i++) { 96 buff.append(' '); 97 } 98 buff.append(size); 99 buff.append(' '); 100 Date now = new Date (), mod = new Date (f.lastModified()); 101 if(mod.after(now) || Math.abs((now.getTime() - mod.getTime())/1000/60/60/24) > 180) { 102 buff.append(dateFormatOld.format(mod)); 103 } else { 104 buff.append(dateFormatNew.format(mod)); 105 } 106 buff.append(' '); 107 buff.append(f.getName()); 108 buff.append("\r\n"); 109 } 110 111 String formatLastModified(FileObject file) { 112 return dateFormat.format(new Date (file.lastModified())); 113 } 114 115 FileObject getFile(String path) { 116 if(path.indexOf("..") > 0) { 117 path = "/"; 118 } 119 while(path.startsWith("/") && root.endsWith("/")) { 120 path = path.substring(1); 121 } 122 while(path.endsWith("/")) { 123 path = path.substring(0, path.length()-1); 124 } 125 log("file: " + root + path); 126 if(db != null) { 127 return FileObjectDatabase.get(db, root + path); 128 } else { 129 return FileObjectNative.get(root + path); 130 } 131 } 132 133 String getDirectoryListing(FileObject directory, boolean listDirectories) { 134 FileObject[] list = directory.listFiles(); 135 StringBuffer buff = new StringBuffer (); 136 for(int i=0; list != null && i<list.length; i++) { 137 FileObject f = list[i]; 138 if(f.isFile() || (f.isDirectory() && listDirectories)) { 139 appendFile(buff, f); 140 } 141 } 142 return buff.toString(); 143 } 144 145 public boolean checkUserPassword(String userName, String password) { 146 return userName.equals(this.writeUserName) && password.equals(this.writePassword); 147 } 148 149 public boolean checkUserPasswordReadOnly(String userName, String param) { 150 return userName.equals(this.readUserName); 151 } 152 153 public void init(String [] args) throws Exception { 154 for(int i=0; args != null && i<args.length; i++) { 155 if("-ftpPort".equals(args[i])) { 156 port = MathUtils.decodeInt(args[++i]); 157 } else if("-ftpDir".equals(args[i])) { 158 root = args[++i]; 159 } else if("-ftpRead".equals(args[i])) { 160 readUserName = args[++i]; 161 } else if("-ftpWrite".equals(args[i])) { 162 writeUserName = args[++i]; 163 } else if("-ftpWritePassword".equals(args[i])) { 164 writePassword = args[++i]; 165 } else if("-log".equals(args[i])) { 166 log = Boolean.valueOf(args[++i]).booleanValue(); 167 } else if("-ftpTask".equals(args[i])) { 168 allowTask = Boolean.valueOf(args[++i]).booleanValue(); 169 } 170 } 171 if(root.startsWith("jdbc:")) { 172 org.h2.Driver.load(); 173 Connection conn = DriverManager.getConnection(root); 174 db = new FileSystemDatabase(conn, log); 175 root = "/"; 176 } 177 } 178 179 public String getURL() { 180 return "ftp://localhost:"+port; 181 } 182 183 public void start() throws SQLException { 184 getFile("").mkdirs(); 185 serverSocket = NetUtils.createServerSocket(port, false); 186 } 187 188 public void stop() { 189 try { 190 serverSocket.close(); 191 } catch(IOException e) { 192 logError(e); 193 } 194 serverSocket = null; 195 } 196 197 public boolean isRunning() { 198 if(serverSocket == null) { 199 return false; 200 } 201 try { 202 Socket s = NetUtils.createLoopbackSocket(port, false); 203 s.close(); 204 return true; 205 } catch(Exception e) { 206 return false; 207 } 208 } 209 210 public boolean getAllowOthers() { 211 return true; 212 } 213 214 public String getType() { 215 return "FTP"; 216 } 217 218 void log(String s) { 219 if(log) { 220 System.out.println(s); 221 } 222 } 223 224 void logError(Throwable e) { 225 if (log) { 226 e.printStackTrace(); 227 } 228 } 229 230 public boolean getAllowTask() { 231 return allowTask; 232 } 233 234 void startTask(FileObject file) throws IOException { 235 stopTask(file); 236 String processName = file.getName(); 237 if(file.getName().endsWith(".zip.task")) { 238 log("expand: " + file.getName()); 239 Process p = Runtime.getRuntime().exec("jar -xf " + file.getName(), null, new File (root)); 240 String processFile = root + "/" + processName; 241 new StreamRedirect(processFile, p.getInputStream(), null).start(); 242 return; 243 } 244 ByteArrayOutputStream out = new ByteArrayOutputStream (); 245 file.read(0, out); 246 byte[] data = out.toByteArray(); 247 Properties prop = new Properties (); 248 prop.load(new ByteArrayInputStream (data)); 249 String command = prop.getProperty("command"); 250 String outFile = processName.substring(0, processName.length() - TASK_SUFFIX.length()); 251 String errorFile = root + "/" + prop.getProperty("error", outFile + ".err.txt"); 252 String outputFile= root + "/" + prop.getProperty("output", outFile + ".out.txt"); 253 String processFile = root + "/" + processName; 254 log("start process: " + processName + " / " + command); 255 Process p = Runtime.getRuntime().exec(command, null, new File (root)); 256 new StreamRedirect(processFile, p.getErrorStream(), errorFile).start(); 257 new StreamRedirect(processFile, p.getInputStream(), outputFile).start(); 258 tasks.put(processName, p); 259 } 260 261 private static class StreamRedirect extends Thread { 262 private InputStream in; 263 private OutputStream out; 264 private String outFile; 265 private String processFile; 266 267 StreamRedirect(String processFile, InputStream in, String outFile) { 268 this.processFile = processFile; 269 this.in = in; 270 this.outFile = outFile; 271 } 272 273 private void openOutput() { 274 if(outFile != null) { 275 try { 276 this.out = new FileOutputStream (outFile); 277 } catch(IOException e) { 278 } 280 outFile = null; 281 } 282 } 283 284 public void run() { 285 while(true) { 286 try { 287 int x = in.read(); 288 if(x < 0) { 289 break; 290 } 291 openOutput(); 292 if(out != null) { 293 out.write(x); 294 } 295 } catch(IOException e) { 296 } 298 } 299 IOUtils.closeSilently(out); 300 IOUtils.closeSilently(in); 301 new File (processFile).delete(); 302 } 303 } 304 305 void stopTask(FileObject file) { 306 String processName = file.getName(); 307 log("kill process: " + processName); 308 Process p = (Process ) tasks.remove(processName); 309 if(p == null) { 310 return; 311 } 312 p.destroy(); 313 } 314 315 } 316 | Popular Tags |