1 11 package org.eclipse.core.runtime.adaptor; 12 13 import java.io.*; 14 import java.util.*; 15 import org.eclipse.core.runtime.internal.adaptor.BasicLocation; 16 import org.eclipse.core.runtime.internal.adaptor.Locker; 17 import org.eclipse.osgi.framework.internal.reliablefile.*; 18 19 43 public class FileManager { 44 static final int FILETYPE_STANDARD = 0; 45 static final int FILETYPE_RELIABLEFILE = 1; 46 private static boolean tempCleanup = Boolean.valueOf(System.getProperty("osgi.embedded.cleanTempFiles")).booleanValue(); private static boolean openCleanup = Boolean.valueOf(System.getProperty("osgi.embedded.cleanupOnOpen")).booleanValue(); 49 private class Entry { 50 int readId; 51 int writeId; 52 int fileType; 53 54 Entry(int readId, int writeId, int type) { 55 this.readId = readId; 56 this.writeId = writeId; 57 this.fileType = type; 58 } 59 60 int getReadId() { 61 return readId; 62 } 63 64 int getWriteId() { 65 return writeId; 66 } 67 68 int getFileType() { 69 return fileType; 70 } 71 72 void setReadId(int value) { 73 readId = value; 74 } 75 76 void setWriteId(int value) { 77 writeId = value; 78 } 79 80 void setFileType(int type) { 81 fileType = type; 82 } 83 } 84 85 private File base; private File managerRoot; 88 private String lockMode = null; 89 private File tableFile = null; 90 private File lockFile; private Locker locker; 93 private File instanceFile = null; private Locker instanceLocker = null; private boolean readOnly; private boolean open; 98 private int tableStamp = -1; 100 101 private Properties table = new Properties(); 102 103 private static final String MANAGER_FOLDER = ".manager"; private static final String TABLE_FILE = ".fileTable"; private static final String LOCK_FILE = ".fileTableLock"; private static final int MAX_LOCK_WAIT = 5000; 108 116 public FileManager(File base, String lockMode) { 117 this(base, lockMode, false); 118 } 119 120 128 public FileManager(File base, String lockMode, boolean readOnly) { 129 this.base = base; 130 this.lockMode = lockMode; 131 this.managerRoot = new File(base, MANAGER_FOLDER); 132 if (!readOnly) 133 this.managerRoot.mkdirs(); 134 this.tableFile = new File(managerRoot, TABLE_FILE); 135 this.lockFile = new File(managerRoot, LOCK_FILE); 136 this.readOnly = readOnly; 137 open = false; 138 } 139 140 private void initializeInstanceFile() throws IOException { 141 if (instanceFile != null || readOnly) 142 return; 143 this.instanceFile = File.createTempFile(".tmp", ".instance", managerRoot); this.instanceFile.deleteOnExit(); 145 instanceLocker = BasicLocation.createLocker(instanceFile, lockMode); 146 instanceLocker.lock(); 147 } 148 149 private String getAbsolutePath(String file) { 150 return new File(base, file).getAbsolutePath(); 151 } 152 153 159 public void add(String file) throws IOException { 160 add(file, FILETYPE_STANDARD); 161 } 162 163 172 protected void add(String file, int fileType) throws IOException { 173 if (!open) 174 throw new IOException(EclipseAdaptorMsg.fileManager_notOpen); 175 if (readOnly) 176 throw new IOException(EclipseAdaptorMsg.fileManager_illegalInReadOnlyMode); 177 if (!lock(true)) 178 throw new IOException(EclipseAdaptorMsg.fileManager_cannotLock); 179 try { 180 updateTable(); 181 Entry entry = (Entry) table.get(file); 182 if (entry == null) { 183 entry = new Entry(0, 1, fileType); 184 table.put(file, entry); 185 int oldestGeneration = findOldestGeneration(file); 189 if (oldestGeneration != 0) 190 entry.setWriteId(oldestGeneration + 1); 191 save(); 192 } else { 193 if (entry.getFileType() != fileType) { 194 entry.setFileType(fileType); 195 updateTable(); 196 save(); 197 } 198 } 199 } finally { 200 release(); 201 } 202 } 203 204 210 private int findOldestGeneration(String file) { 211 String [] files = base.list(); 212 int oldestGeneration = 0; 213 if (files != null) { 214 String name = file + '.'; 215 int len = name.length(); 216 for (int i = 0; i < files.length; i++) { 217 if (!files[i].startsWith(name)) 218 continue; 219 try { 220 int generation = Integer.parseInt(files[i].substring(len)); 221 if (generation > oldestGeneration) 222 oldestGeneration = generation; 223 } catch (NumberFormatException e) { 224 continue; 225 } 226 } 227 } 228 return oldestGeneration; 229 } 230 231 241 public void update(String [] targets, String [] sources) throws IOException { 242 if (!open) 243 throw new IOException(EclipseAdaptorMsg.fileManager_notOpen); 244 if (readOnly) 245 throw new IOException(EclipseAdaptorMsg.fileManager_illegalInReadOnlyMode); 246 if (!lock(true)) 247 throw new IOException(EclipseAdaptorMsg.fileManager_cannotLock); 248 try { 249 updateTable(); 250 int[] originalReadIDs = new int[targets.length]; 251 boolean error = false; 252 for (int i = 0; i < targets.length; i++) { 253 originalReadIDs[i] = getId(targets[i]); 254 if (!update(targets[i], sources[i])) 255 error = true; 256 } 257 if (error) { 258 for (int i = 0; i < targets.length; i++) { 260 Entry entry = (Entry) table.get(targets[i]); 261 entry.setReadId(originalReadIDs[i]); 262 } 263 throw new IOException(EclipseAdaptorMsg.fileManager_updateFailed); 264 } 265 save(); } finally { 267 release(); 268 } 269 } 270 271 276 public String [] getFiles() { 277 if (!open) 278 return null; 279 Set set = table.keySet(); 280 String [] keys = (String []) set.toArray(new String [set.size()]); 281 String [] result = new String [keys.length]; 282 for (int i = 0; i < keys.length; i++) 283 result[i] = new String (keys[i]); 284 return result; 285 } 286 287 293 public File getBase() { 294 return base; 295 } 296 297 306 public int getId(String target) { 307 if (!open) 308 return -1; 309 Entry entry = (Entry) table.get(target); 310 if (entry == null) 311 return -1; 312 return entry.getReadId(); 313 } 314 315 323 protected int getFileType(String target) { 324 if (open) { 325 Entry entry = (Entry) table.get(target); 326 if (entry != null) 327 return entry.getFileType(); 328 } 329 return -1; 330 } 331 332 337 public boolean isReadOnly() { 338 return readOnly; 339 } 340 341 353 private boolean lock(boolean wait) throws IOException { 354 if (readOnly) 355 return false; 356 if (locker == null) { 357 locker = BasicLocation.createLocker(lockFile, lockMode); 358 if (locker == null) 359 throw new IOException(EclipseAdaptorMsg.fileManager_cannotLock); 360 } 361 boolean locked = locker.lock(); 362 if (locked || !wait) 363 return locked; 364 long start = System.currentTimeMillis(); 366 while (true) { 367 try { 368 Thread.sleep(200); } catch (InterruptedException e) { 370 } 371 locked = locker.lock(); 372 if (locked) 373 return true; 374 long time = System.currentTimeMillis() - start; 376 if (time > MAX_LOCK_WAIT) 377 return false; 378 } 379 } 380 381 391 public File lookup(String target, boolean add) throws IOException { 392 if (!open) 393 throw new IOException(EclipseAdaptorMsg.fileManager_notOpen); 394 Entry entry = (Entry) table.get(target); 395 if (entry == null) { 396 if (add) { 397 add(target); 398 entry = (Entry) table.get(target); 399 } else { 400 return null; 401 } 402 } 403 return new File(getAbsolutePath(target + '.' + entry.getReadId())); 404 } 405 406 private boolean move(String source, String target) { 407 File original = new File(source); 408 File targetFile = new File(target); 409 if (!original.exists() || targetFile.exists()) 412 return false; 413 return original.renameTo(targetFile); 414 } 415 416 419 private void release() { 420 if (locker == null) 421 return; 422 locker.release(); 423 } 424 425 430 public void remove(String file) throws IOException { 431 if (!open) 432 throw new IOException(EclipseAdaptorMsg.fileManager_notOpen); 433 if (readOnly) 434 throw new IOException(EclipseAdaptorMsg.fileManager_illegalInReadOnlyMode); 435 if (!lock(true)) 438 throw new IOException(EclipseAdaptorMsg.fileManager_cannotLock); 439 try { 440 updateTable(); 441 table.remove(file); 442 save(); 443 } finally { 444 release(); 445 } 446 } 447 448 private void updateTable() throws IOException { 449 int stamp; 450 stamp = ReliableFile.lastModifiedVersion(tableFile); 451 if (stamp == tableStamp || stamp == -1) 452 return; 453 Properties diskTable = new Properties(); 454 try { 455 InputStream input; 456 input = new ReliableFileInputStream(tableFile); 457 try { 458 diskTable.load(input); 459 } finally { 460 input.close(); 461 } 462 } catch (IOException e) { 463 throw e; } 465 tableStamp = stamp; 466 for (Enumeration e = diskTable.keys(); e.hasMoreElements();) { 467 String file = (String ) e.nextElement(); 468 String value = diskTable.getProperty(file); 469 if (value != null) { 470 Entry entry = (Entry) table.get(file); 471 int id; 473 int fileType; 474 int idx = value.indexOf(','); 475 if (idx != -1) { 476 id = Integer.parseInt(value.substring(0, idx)); 477 fileType = Integer.parseInt(value.substring(idx + 1)); 478 } else { 479 id = Integer.parseInt(value); 480 fileType = FILETYPE_STANDARD; 481 } 482 if (entry == null) { 483 table.put(file, new Entry(id, id + 1, fileType)); 484 } else { 485 entry.setWriteId(id + 1); 486 } 488 } 489 } 490 } 491 492 495 private void save() throws IOException { 496 if (readOnly) 497 return; 498 updateTable(); 501 502 Properties props = new Properties(); 503 for (Enumeration e = table.keys(); e.hasMoreElements();) { 504 String file = (String ) e.nextElement(); 505 Entry entry = (Entry) table.get(file); 506 String value; 507 if (entry.getFileType() != FILETYPE_STANDARD) { 508 value = Integer.toString(entry.getWriteId() - 1) + ',' + Integer.toString(entry.getFileType()); 510 } else { 511 value = Integer.toString(entry.getWriteId() - 1); } 513 props.put(file, value); 514 } 515 ReliableFileOutputStream fileStream = new ReliableFileOutputStream(tableFile); 516 try { 517 boolean error = true; 518 try { 519 props.store(fileStream, "safe table"); fileStream.close(); 521 error = false; 522 } finally { 523 if (error) 524 fileStream.abort(); 525 } 526 } catch (IOException e) { 527 throw new IOException(EclipseAdaptorMsg.fileManager_couldNotSave); 528 } 529 tableStamp = ReliableFile.lastModifiedVersion(tableFile); 530 } 531 532 protected boolean update(String target, String source) { 533 Entry entry = (Entry) table.get(target); 534 int newId = entry.getWriteId(); 535 boolean success = move(getAbsolutePath(source), getAbsolutePath(target) + '.' + newId); 537 if (!success) { 538 newId = findOldestGeneration(target) + 1; 541 success = move(getAbsolutePath(source), getAbsolutePath(target) + '.' + newId); 542 } 543 if (!success) 544 return false; 545 entry.setReadId(newId); 548 entry.setWriteId(newId + 1); 549 return true; 550 } 551 552 557 private void cleanup() throws IOException { 558 if (readOnly) 559 return; 560 if (!lock(true)) 562 throw new IOException(EclipseAdaptorMsg.fileManager_cannotLock); 563 try { 564 String [] files = managerRoot.list(); 566 if (files != null) { 567 for (int i = 0; i < files.length; i++) { 568 if (files[i].endsWith(".instance") && instanceFile != null && !files[i].equalsIgnoreCase(instanceFile.getName())) { Locker tmpLocker = BasicLocation.createLocker(new File(managerRoot, files[i]), lockMode); 570 if (tmpLocker.lock()) { 571 tmpLocker.release(); 573 new File(managerRoot, files[i]).delete(); 574 } else { 575 tmpLocker.release(); 576 return; } 578 } 579 } 580 } 581 582 updateTable(); 584 Collection managedFiles = table.entrySet(); 585 for (Iterator iter = managedFiles.iterator(); iter.hasNext();) { 586 Map.Entry fileEntry = (Map.Entry) iter.next(); 587 String fileName = (String ) fileEntry.getKey(); 588 Entry info = (Entry) fileEntry.getValue(); 589 if (info.getFileType() == FILETYPE_RELIABLEFILE) { 590 ReliableFile.cleanupGenerations(new File(base, fileName)); 591 } else { 592 String readId = Integer.toString(info.getWriteId() - 1); 594 deleteCopies(fileName, readId); 595 } 596 } 597 598 if (tempCleanup) { 599 files = base.list(); 600 if (files != null) { 601 for (int i = 0; i < files.length; i++) { 602 if (files[i].endsWith(ReliableFile.tmpExt)) { new File(base, files[i]).delete(); 604 } 605 } 606 } 607 } 608 } catch (IOException e) { 609 throw e; 612 } finally { 613 release(); 614 } 615 } 616 617 private void deleteCopies(String fileName, String exceptionNumber) { 618 String notToDelete = fileName + '.' + exceptionNumber; 619 String [] files = base.list(); 620 if (files == null) 621 return; 622 for (int i = 0; i < files.length; i++) { 623 if (files[i].startsWith(fileName + '.') && !files[i].equals(notToDelete)) new File(base, files[i]).delete(); 625 } 626 } 627 628 632 public void close() { 633 if (!open) 634 return; 635 open = false; 636 if (readOnly) 637 return; 638 try { 639 cleanup(); 640 } catch (IOException e) { 641 } 643 if (instanceLocker != null) 644 instanceLocker.release(); 645 646 if (instanceFile != null) 647 instanceFile.delete(); 648 } 649 650 654 public void open(boolean wait) throws IOException { 655 if (openCleanup) 656 cleanup(); 657 if (!readOnly) { 658 boolean locked = lock(wait); 659 if (!locked && wait) 660 throw new IOException(EclipseAdaptorMsg.fileManager_cannotLock); 661 } 662 663 try { 664 initializeInstanceFile(); 665 updateTable(); 666 open = true; 667 } finally { 668 release(); 669 } 670 } 671 672 681 public File createTempFile(String file) throws IOException { 682 if (readOnly) 683 throw new IOException(EclipseAdaptorMsg.fileManager_illegalInReadOnlyMode); 684 File tmpFile = File.createTempFile(file, ReliableFile.tmpExt, base); 685 tmpFile.deleteOnExit(); 686 return tmpFile; 687 } 688 689 } | Popular Tags |