mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-09-28 17:11:11 -09:00
Merge remote-tracking branch 'origin/GP-2184-dragonmacher-remove-jmockit-6'
This commit is contained in:
@@ -22,7 +22,8 @@ import ghidra.util.BigEndianDataConverter;
|
|||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.datastruct.IntSet;
|
import ghidra.util.datastruct.IntSet;
|
||||||
import ghidra.util.exception.*;
|
import ghidra.util.exception.*;
|
||||||
import ghidra.util.task.*;
|
import ghidra.util.task.CancelledListener;
|
||||||
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <code>LocalBufferFile</code> implements a BufferFile as block-oriented
|
* <code>LocalBufferFile</code> implements a BufferFile as block-oriented
|
||||||
@@ -30,7 +31,6 @@ import ghidra.util.task.*;
|
|||||||
* not support the save operation.
|
* not support the save operation.
|
||||||
*/
|
*/
|
||||||
public class LocalBufferFile implements BufferFile {
|
public class LocalBufferFile implements BufferFile {
|
||||||
// static final Logger log = Logger.getLogger(LocalBufferFile.class);
|
|
||||||
|
|
||||||
static final long MAGIC_NUMBER = 0x2f30312c34292c2aL;
|
static final long MAGIC_NUMBER = 0x2f30312c34292c2aL;
|
||||||
|
|
||||||
@@ -48,21 +48,21 @@ public class LocalBufferFile implements BufferFile {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Current file header format version number.
|
* Current file header format version number.
|
||||||
* The third field of the file header indicates a
|
* The third field of the file header indicates a
|
||||||
* format version which indicates how the header
|
* format version which indicates how the header
|
||||||
* is formatted.
|
* is formatted.
|
||||||
*/
|
*/
|
||||||
private static final int HEADER_FORMAT_VERSION = 1;
|
private static final int HEADER_FORMAT_VERSION = 1;
|
||||||
|
|
||||||
//
|
//
|
||||||
// The first block is reserved for use by the BlockFile header.
|
// The first block is reserved for use by the BlockFile header.
|
||||||
// The format of this header is determined by the Field #3.
|
// The format of this header is determined by the Field #3.
|
||||||
//
|
//
|
||||||
// FILE FORMAT - VERSION 1
|
// FILE FORMAT - VERSION 1
|
||||||
//
|
//
|
||||||
// A file header is contained within the first buffer at offset 0 within the file.
|
// A file header is contained within the first buffer at offset 0 within the file.
|
||||||
// This header contains the following fields:
|
// This header contains the following fields:
|
||||||
//
|
//
|
||||||
// 1. Magic number (8,long)
|
// 1. Magic number (8,long)
|
||||||
// 2. File ID (8,long)
|
// 2. File ID (8,long)
|
||||||
// 3. Block file header format version (4,int) = 1
|
// 3. Block file header format version (4,int) = 1
|
||||||
@@ -74,8 +74,8 @@ public class LocalBufferFile implements BufferFile {
|
|||||||
// * Parm name (?,char[])
|
// * Parm name (?,char[])
|
||||||
// * Parm value (4,int)
|
// * Parm value (4,int)
|
||||||
// Parameter space is limited by buffer size.
|
// Parameter space is limited by buffer size.
|
||||||
//
|
//
|
||||||
// In Version 1 - the first available user buffer immediately follows the file
|
// In Version 1 - the first available user buffer immediately follows the file
|
||||||
// header block (i.e., buffer index 0 corresponds to block index 1).
|
// header block (i.e., buffer index 0 corresponds to block index 1).
|
||||||
//
|
//
|
||||||
// Each user block has the following prefix data:
|
// Each user block has the following prefix data:
|
||||||
@@ -101,8 +101,8 @@ public class LocalBufferFile implements BufferFile {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* <code>userParms</code> contains application parameters which correspond to
|
* <code>userParms</code> contains application parameters which correspond to
|
||||||
* this buffer file. This list is established for
|
* this buffer file. This list is established for
|
||||||
* an existing buffer file when the readHeader is invoked. For a non-temporary
|
* an existing buffer file when the readHeader is invoked. For a non-temporary
|
||||||
* writable buffer file, this list is flushed to the file when either close or
|
* writable buffer file, this list is flushed to the file when either close or
|
||||||
* setReadOnly is invoked.
|
* setReadOnly is invoked.
|
||||||
*/
|
*/
|
||||||
@@ -110,32 +110,37 @@ public class LocalBufferFile implements BufferFile {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* <code>freeIndexes</code> contains those buffer indexes which are free/empty
|
* <code>freeIndexes</code> contains those buffer indexes which are free/empty
|
||||||
* and may be re-used in an update of this file. This list is established for
|
* and may be re-used in an update of this file. This list is established for
|
||||||
* an existing buffer file when the readHeader is invoked. For a non-temporary
|
* an existing buffer file when the readHeader is invoked. For a non-temporary
|
||||||
* writable buffer file, this list is flushed to the file when either close or
|
* writable buffer file, this list is flushed to the file when either close or
|
||||||
* setReadOnly is invoked.
|
* setReadOnly is invoked.
|
||||||
*/
|
*/
|
||||||
private int[] freeIndexes = new int[0];
|
private int[] freeIndexes = new int[0];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <code>file</code> is the underlying storage file for this buffer file.
|
* The underlying storage file for this buffer file.
|
||||||
*/
|
*/
|
||||||
private File file;
|
private File file;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <code>raf</code> is the random-access object for the underlying file.
|
* The random-access object for the underlying file.
|
||||||
*/
|
*/
|
||||||
private RandomAccessFile raf;
|
private RandomAccessFile raf;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <code>activeBlockStream</code> provides a handle to the active
|
* Provides a handle to the active OutputBlockStream used to update file via this class's
|
||||||
* OutputBlockStream used to update file via raf. This should be
|
* random access file. This should be checked during {@link #close()} to guard against
|
||||||
* checked during {@link #close()} to guard against partially
|
* partially written file. A LocalOutputBlockStream should only be used for files open for
|
||||||
* written file. A LocalOutputBlockStream should only be used
|
* writing (i.e., !readOnly).
|
||||||
* for files open for writing (i.e., !readOnly).
|
|
||||||
*/
|
*/
|
||||||
private volatile LocalOutputBlockStream activeOutputBlockStream;
|
private volatile LocalOutputBlockStream activeOutputBlockStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple factory that allows this class to support dependency injection.
|
||||||
|
*/
|
||||||
|
private static InputBlockStreamFactory inputBlockStreamFactory =
|
||||||
|
new DefaultInputBlockStreamFactory();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When <code>temporary</code> is true and this file is writable (!readOnly)
|
* When <code>temporary</code> is true and this file is writable (!readOnly)
|
||||||
* it will be deleted when disposed or closed.
|
* it will be deleted when disposed or closed.
|
||||||
@@ -150,10 +155,10 @@ public class LocalBufferFile implements BufferFile {
|
|||||||
private long fileId;
|
private long fileId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If <code>readOnly</code> is true, this file may not be modified
|
* If <code>readOnly</code> is true, this file may not be modified
|
||||||
* via the buffer put method.
|
* via the buffer put method.
|
||||||
* A read-only file may be considered "updateable" if the canSave
|
* A read-only file may be considered "updatable" if the canSave
|
||||||
* method returns true. The term "updateable" means that a Save file
|
* method returns true. The term "updatable" means that a Save file
|
||||||
* can be obtained via the getSaveFile method.
|
* can be obtained via the getSaveFile method.
|
||||||
*/
|
*/
|
||||||
private boolean readOnly;
|
private boolean readOnly;
|
||||||
@@ -172,7 +177,7 @@ public class LocalBufferFile implements BufferFile {
|
|||||||
private int bufferSize;
|
private int bufferSize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <code>bufferCount</code> indicates the number of buffer which have been
|
* <code>bufferCount</code> indicates the number of buffer which have been
|
||||||
* allocated within this file and directly reflects the size of the file.
|
* allocated within this file and directly reflects the size of the file.
|
||||||
* The value corresponds to the next buffer index which can be allocated once all
|
* The value corresponds to the next buffer index which can be allocated once all
|
||||||
* free indexes have been utilized. When an existing file is opened, this value
|
* free indexes have been utilized. When an existing file is opened, this value
|
||||||
@@ -185,6 +190,7 @@ public class LocalBufferFile implements BufferFile {
|
|||||||
* @param bufferSize user buffer size
|
* @param bufferSize user buffer size
|
||||||
* @param tmpPrefix temporary file prefix
|
* @param tmpPrefix temporary file prefix
|
||||||
* @param tmpExtension temporary file extension
|
* @param tmpExtension temporary file extension
|
||||||
|
* @throws IOException if there is an exception creating underlying files
|
||||||
*/
|
*/
|
||||||
LocalBufferFile(int bufferSize, String tmpPrefix, String tmpExtension) throws IOException {
|
LocalBufferFile(int bufferSize, String tmpPrefix, String tmpExtension) throws IOException {
|
||||||
this.bufferSize = bufferSize;
|
this.bufferSize = bufferSize;
|
||||||
@@ -223,8 +229,7 @@ public class LocalBufferFile implements BufferFile {
|
|||||||
* Open an existing block file.
|
* Open an existing block file.
|
||||||
* @param file block file
|
* @param file block file
|
||||||
* @param readOnly if true the file will be opened read-only
|
* @param readOnly if true the file will be opened read-only
|
||||||
* @throws IOException if an IO error occurs or the incorrect magicNumber
|
* @throws IOException if an error occurs or the incorrect magicNumber was read from the file.
|
||||||
* was read from the file.
|
|
||||||
*/
|
*/
|
||||||
public LocalBufferFile(File file, boolean readOnly) throws IOException {
|
public LocalBufferFile(File file, boolean readOnly) throws IOException {
|
||||||
this.file = file;
|
this.file = file;
|
||||||
@@ -236,13 +241,14 @@ public class LocalBufferFile implements BufferFile {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Modify an existing buffer file.
|
* Modify an existing buffer file.
|
||||||
* WARNING! Use with extreme caution since this modifies
|
* <p>
|
||||||
* the original file and could destroy data if used
|
* WARNING! Use with extreme caution since this modifies the original file and could destroy
|
||||||
* improperly.
|
* data if used improperly.
|
||||||
* @param file
|
*
|
||||||
* @param bufferIndex
|
* @param file block file
|
||||||
* @param buf
|
* @param bufferIndex the index at which to place the buffer
|
||||||
* @throws IOException
|
* @param buf the buffer add to the file
|
||||||
|
* @throws IOException if an I/O error occurs
|
||||||
*/
|
*/
|
||||||
public static void poke(File file, int bufferIndex, DataBuffer buf) throws IOException {
|
public static void poke(File file, int bufferIndex, DataBuffer buf) throws IOException {
|
||||||
LocalBufferFile bf = new LocalBufferFile(file, false);
|
LocalBufferFile bf = new LocalBufferFile(file, false);
|
||||||
@@ -256,10 +262,10 @@ public class LocalBufferFile implements BufferFile {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Read a buffer from an existing buffer file.
|
* Read a buffer from an existing buffer file.
|
||||||
* @param file
|
* @param file block file
|
||||||
* @param bufferIndex
|
* @param bufferIndex the index from which to read the buffer
|
||||||
* @return
|
* @return the buffer
|
||||||
* @throws IOException
|
* @throws IOException if an I/O error occurs
|
||||||
*/
|
*/
|
||||||
public static DataBuffer peek(File file, int bufferIndex) throws IOException {
|
public static DataBuffer peek(File file, int bufferIndex) throws IOException {
|
||||||
LocalBufferFile bf = new LocalBufferFile(file, false);
|
LocalBufferFile bf = new LocalBufferFile(file, false);
|
||||||
@@ -275,6 +281,7 @@ public class LocalBufferFile implements BufferFile {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the physical file associated with this BufferFile.
|
* Returns the physical file associated with this BufferFile.
|
||||||
|
* @return the file
|
||||||
*/
|
*/
|
||||||
public File getFile() {
|
public File getFile() {
|
||||||
return file;
|
return file;
|
||||||
@@ -296,7 +303,7 @@ public class LocalBufferFile implements BufferFile {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setParameter(String name, int value) {
|
public void setParameter(String name, int value) {
|
||||||
userParms.put(name, new Integer(value));
|
userParms.put(name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -335,24 +342,24 @@ public class LocalBufferFile implements BufferFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assigns the file ID for this file. This should only be done
|
* Assigns the file ID for this file. This should only be done when reconstructing a file.
|
||||||
* when reconstructing a file.
|
* @param id file ID
|
||||||
* @param fileId file ID
|
|
||||||
*/
|
*/
|
||||||
void setFileId(long id) {
|
void setFileId(long id) {
|
||||||
fileId = id;
|
fileId = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return number of buffers countained within this file
|
* The number of buffers contained within this file.
|
||||||
|
* @return the number of buffers contained within this file
|
||||||
*/
|
*/
|
||||||
int getBufferCount() {
|
int getBufferCount() {
|
||||||
return bufferCount;
|
return bufferCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assigns the buffer count for this file. This should only be done
|
* Assigns the buffer count for this file. This should only be done when reconstructing a
|
||||||
* when reconstructing a file.
|
* file.
|
||||||
* @param count number of valid buffers contained within this file
|
* @param count number of valid buffers contained within this file
|
||||||
*/
|
*/
|
||||||
void setBufferCount(int count) {
|
void setBufferCount(int count) {
|
||||||
@@ -360,9 +367,9 @@ public class LocalBufferFile implements BufferFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the temporary status of this buffer file.
|
* Set the temporary status of this buffer file. Temporary buffer files are deleted when
|
||||||
* Temporary buffer files are deleted when closed.
|
* closed.
|
||||||
* @param isTemporary
|
* @param isTemporary true if temporary
|
||||||
*/
|
*/
|
||||||
void setTemporary(boolean isTemporary) {
|
void setTemporary(boolean isTemporary) {
|
||||||
temporary = isTemporary;
|
temporary = isTemporary;
|
||||||
@@ -370,9 +377,9 @@ public class LocalBufferFile implements BufferFile {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Rename underlying file
|
* Rename underlying file
|
||||||
* @param newFile
|
* @param newFile the new file for this class
|
||||||
* @return true if rename successful
|
* @return true if rename successful
|
||||||
* @throws IOException
|
* @throws IOException if an I/O error occurs
|
||||||
*/
|
*/
|
||||||
boolean renameFile(File newFile) throws IOException {
|
boolean renameFile(File newFile) throws IOException {
|
||||||
if (raf != null) {
|
if (raf != null) {
|
||||||
@@ -389,17 +396,17 @@ public class LocalBufferFile implements BufferFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set random access file (raf) position to the file block containing the specified buffer
|
* Set the random access file position to the file block containing the specified buffer
|
||||||
* identified by its bufferIndex. It is important to understand the distinction between
|
* identified by its bufferIndex. It is important to understand the distinction between
|
||||||
* blocks and buffers, where buffers are stored within file blocks which are slightly larger.
|
* blocks and buffers, where buffers are stored within file blocks which are slightly larger.
|
||||||
* In addition, the first file block stores the file header and is not used to store a buffer.
|
* In addition, the first file block stores the file header and is not used to store a buffer.
|
||||||
* @param bufferIndex buffer index
|
* @param bufferIndex buffer index
|
||||||
* @return file block index (=bufferIndex+1)
|
* @return file block index (=bufferIndex+1)
|
||||||
* @throws IOException
|
* @throws IOException if an I/O error occurs
|
||||||
*/
|
*/
|
||||||
private int seekBufferBlock(int bufferIndex) throws IOException {
|
private int seekBufferBlock(int bufferIndex) throws IOException {
|
||||||
// Perform long multiplication to support file sizes greater than 2-GBytes
|
// Perform long multiplication to support file sizes greater than 2-GBytes
|
||||||
// Add 1 to buffer index to obtain block index (first useable buffer, buffer#0, is
|
// Add 1 to buffer index to obtain block index (first usable buffer, buffer#0, is
|
||||||
// contained within block#1 since block#0 contains file header)
|
// contained within block#1 since block#0 contains file header)
|
||||||
int blockIndex = bufferIndex + 1;
|
int blockIndex = bufferIndex + 1;
|
||||||
long offset = (long) blockIndex * (long) blockSize;
|
long offset = (long) blockIndex * (long) blockSize;
|
||||||
@@ -408,11 +415,13 @@ public class LocalBufferFile implements BufferFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set random access file (raf) position to the specified file block and offset
|
* Set the random access file position to the specified file block and offset within that
|
||||||
* within that block. NOTE: block#0 contains the file header.
|
* block.
|
||||||
|
*
|
||||||
|
* <p>NOTE: block#0 contains the file header.
|
||||||
* @param blockIndex block index
|
* @param blockIndex block index
|
||||||
* @param offsetWithinBlock offset within file block
|
* @param offsetWithinBlock offset within file block
|
||||||
* @throws IOException
|
* @throws IOException if there is an exception reading the file
|
||||||
*/
|
*/
|
||||||
private void seekBlock(int blockIndex, int offsetWithinBlock) throws IOException {
|
private void seekBlock(int blockIndex, int offsetWithinBlock) throws IOException {
|
||||||
// Perform long multiplication to support file sizes greater than 2-GBytes
|
// Perform long multiplication to support file sizes greater than 2-GBytes
|
||||||
@@ -422,7 +431,7 @@ public class LocalBufferFile implements BufferFile {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Read file header and initialize the user parameter and free buffer index lists.
|
* Read file header and initialize the user parameter and free buffer index lists.
|
||||||
* @throws IOException if an I/O error occurs while reading file
|
* @throws IOException if an I/O error occurs
|
||||||
*/
|
*/
|
||||||
private void readHeader() throws IOException {
|
private void readHeader() throws IOException {
|
||||||
|
|
||||||
@@ -437,7 +446,7 @@ public class LocalBufferFile implements BufferFile {
|
|||||||
// Read file ID
|
// Read file ID
|
||||||
fileId = raf.readLong();
|
fileId = raf.readLong();
|
||||||
|
|
||||||
// Check file format version
|
// Check file format version
|
||||||
int headerFormatVersion = raf.readInt();
|
int headerFormatVersion = raf.readInt();
|
||||||
if (headerFormatVersion != HEADER_FORMAT_VERSION) {
|
if (headerFormatVersion != HEADER_FORMAT_VERSION) {
|
||||||
throw new IOException("Unrecognized file format");
|
throw new IOException("Unrecognized file format");
|
||||||
@@ -466,9 +475,8 @@ public class LocalBufferFile implements BufferFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Store the user parameter and free buffer index lists and write the
|
* Store the user parameter and free buffer index lists and write the file header.
|
||||||
* file header.
|
* @throws IOException if an I/O error occurs
|
||||||
* @throws IOException if an I/O error occurs while writing file
|
|
||||||
*/
|
*/
|
||||||
private void writeHeader() throws IOException {
|
private void writeHeader() throws IOException {
|
||||||
|
|
||||||
@@ -518,7 +526,7 @@ public class LocalBufferFile implements BufferFile {
|
|||||||
while (nextIndex >= 0) {
|
while (nextIndex >= 0) {
|
||||||
|
|
||||||
// Push index on stack
|
// Push index on stack
|
||||||
freeIndexList.add(new Integer(nextIndex));
|
freeIndexList.add(nextIndex);
|
||||||
|
|
||||||
// Read block to get next index
|
// Read block to get next index
|
||||||
seekBufferBlock(nextIndex);
|
seekBufferBlock(nextIndex);
|
||||||
@@ -541,9 +549,9 @@ public class LocalBufferFile implements BufferFile {
|
|||||||
/**
|
/**
|
||||||
* Update a storage block as free and link to the next free block.
|
* Update a storage block as free and link to the next free block.
|
||||||
* @param index block index of free block
|
* @param index block index of free block
|
||||||
* @param nextFreeIndex block index of next free block, a -1 should be
|
* @param nextFreeIndex block index of next free block, a -1 should be specified to mark the
|
||||||
* specified to mark the end of the linked list.
|
* end of the linked list.
|
||||||
* @throws IOException thrown if an IO error occurs
|
* @throws IOException if an I/O error occurs
|
||||||
*/
|
*/
|
||||||
void putFreeBlock(int index, int nextFreeIndex) throws IOException {
|
void putFreeBlock(int index, int nextFreeIndex) throws IOException {
|
||||||
|
|
||||||
@@ -598,8 +606,8 @@ public class LocalBufferFile implements BufferFile {
|
|||||||
/**
|
/**
|
||||||
* Generate a BufferFileBlock instance which corresponds to the specified DataBuffer
|
* Generate a BufferFileBlock instance which corresponds to the specified DataBuffer
|
||||||
* based upon LocalBufferFile block usage. This should generally not be used for writing
|
* based upon LocalBufferFile block usage. This should generally not be used for writing
|
||||||
* empty blocks since they will not be properly linked which is normally handled during
|
* empty blocks since they will not be properly linked which is normally handled during
|
||||||
* header flush which is performed by BufferFile close on files being written.
|
* header flush which is performed by BufferFile close on files being written.
|
||||||
* @param buf the data buffer to be converted
|
* @param buf the data buffer to be converted
|
||||||
* @param bufferSize data buffer size used for integrity check and generating empty buffer
|
* @param bufferSize data buffer size used for integrity check and generating empty buffer
|
||||||
* @return BufferFileBlock instance.
|
* @return BufferFileBlock instance.
|
||||||
@@ -655,7 +663,7 @@ public class LocalBufferFile implements BufferFile {
|
|||||||
else if (data.length != bufferSize) {
|
else if (data.length != bufferSize) {
|
||||||
throw new IllegalArgumentException("Bad buffer size");
|
throw new IllegalArgumentException("Bad buffer size");
|
||||||
}
|
}
|
||||||
// Non-empty Buffer - read data
|
// Non-empty Buffer - read data
|
||||||
raf.readFully(data);
|
raf.readFully(data);
|
||||||
}
|
}
|
||||||
buf.setDirty(false);
|
buf.setDirty(false);
|
||||||
@@ -716,7 +724,8 @@ public class LocalBufferFile implements BufferFile {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Truncate the buffer file length to the specified index count.
|
* Truncate the buffer file length to the specified index count.
|
||||||
* @param indexCount
|
* @param indexCount the index count
|
||||||
|
* @throws IOException if an I/O error occurs
|
||||||
*/
|
*/
|
||||||
void truncate(int indexCount) throws IOException {
|
void truncate(int indexCount) throws IOException {
|
||||||
|
|
||||||
@@ -802,6 +811,7 @@ public class LocalBufferFile implements BufferFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* True if this is a temporary buffer file
|
||||||
* @return true if this is a temporary buffer file
|
* @return true if this is a temporary buffer file
|
||||||
*/
|
*/
|
||||||
boolean isTemporary() {
|
boolean isTemporary() {
|
||||||
@@ -809,6 +819,7 @@ public class LocalBufferFile implements BufferFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* True if buffer file is closed
|
||||||
* @return true if buffer file is closed
|
* @return true if buffer file is closed
|
||||||
*/
|
*/
|
||||||
boolean isClosed() {
|
boolean isClosed() {
|
||||||
@@ -875,9 +886,8 @@ public class LocalBufferFile implements BufferFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clone this buffer file to the specified file. The file must not
|
* Clone this buffer file to the specified file. The file must not already exist. If the
|
||||||
* already exist. If the operation is cancelled or an error occurs
|
* operation is cancelled or an error occurs the file is not created.
|
||||||
* the file is not created.
|
|
||||||
* @param destinationFile destination file
|
* @param destinationFile destination file
|
||||||
* @param monitor progress monitor
|
* @param monitor progress monitor
|
||||||
* @throws IOException if IO error occurs.
|
* @throws IOException if IO error occurs.
|
||||||
@@ -906,7 +916,211 @@ public class LocalBufferFile implements BufferFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <code>LocalBufferInputBlockStream</code> provides an input BlockStream for
|
* Obtain a direct stream to read all blocks of this buffer file
|
||||||
|
* @return input block stream
|
||||||
|
* @throws IOException if there is an exception creating the stream
|
||||||
|
*/
|
||||||
|
public InputBlockStream getInputBlockStream() throws IOException {
|
||||||
|
return inputBlockStreamFactory.createInputBlockStream(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtain a direct stream to write blocks to this buffer file
|
||||||
|
* @param blockCount number of blocks to be transferred
|
||||||
|
* @return output block stream
|
||||||
|
* @throws IOException if an I/O error occurs
|
||||||
|
*/
|
||||||
|
public OutputBlockStream getOutputBlockStream(int blockCount) throws IOException {
|
||||||
|
return new LocalOutputBlockStream(blockCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory method for generating the appropriate type of {@link InputBlockStream}
|
||||||
|
* for the specified read-only bufferFile. Input stream may not supply header block in which case
|
||||||
|
* free list and file parameters may need to be set separately.
|
||||||
|
* @param bufferFile buffer file opened read-only
|
||||||
|
* @return input block stream object
|
||||||
|
* @throws IOException if an I/O error occurs
|
||||||
|
*/
|
||||||
|
private static InputBlockStream getInputBlockStream(BufferFile bufferFile) throws IOException {
|
||||||
|
// This method is used so we can utilize a package method and avoid putting
|
||||||
|
// it on the BufferFile interface
|
||||||
|
if (bufferFile instanceof BufferFileAdapter) {
|
||||||
|
return ((BufferFileAdapter) bufferFile).getInputBlockStream();
|
||||||
|
}
|
||||||
|
if (bufferFile instanceof LocalBufferFile) {
|
||||||
|
return ((LocalBufferFile) bufferFile).getInputBlockStream();
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Unsupported buffer file implementation: " + bufferFile.getClass().getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory method for generating the appropriate type of {@link InputBlockStream}
|
||||||
|
* for the specified read-only bufferFile with an optional changeMap used
|
||||||
|
* to select which buffer should be transferred. Input stream may not supply header block
|
||||||
|
* in which case free list and file parameters may need to be set separately.
|
||||||
|
* @param bufferFile buffer file opened read-only
|
||||||
|
* @return input block stream object
|
||||||
|
* @throws IOException if an I/O error occurs
|
||||||
|
*/
|
||||||
|
private static InputBlockStream getInputBlockStream(BufferFile bufferFile, ChangeMap changeMap)
|
||||||
|
throws IOException {
|
||||||
|
if (changeMap == null) {
|
||||||
|
return getInputBlockStream(bufferFile);
|
||||||
|
}
|
||||||
|
// This method is used so we can utilize a package method and avoid putting
|
||||||
|
// it on the BufferFile interface
|
||||||
|
if (bufferFile instanceof ManagedBufferFileAdapter) {
|
||||||
|
return ((ManagedBufferFileAdapter) bufferFile).getInputBlockStream(changeMap.getData());
|
||||||
|
}
|
||||||
|
if (bufferFile instanceof LocalManagedBufferFile) {
|
||||||
|
return ((LocalManagedBufferFile) bufferFile).getInputBlockStream(changeMap.getData());
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Unsupported buffer file implementation: " + bufferFile.getClass().getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory method for generating the appropriate type of {@link OutputBlockStream}
|
||||||
|
* for the specified write-able bufferFile.
|
||||||
|
* @param bufferFile write-able buffer file
|
||||||
|
* @param blockCount number of blocks to be written. This should be available from
|
||||||
|
* the corresponding {@link InputBlockStream}.
|
||||||
|
* @return output block stream object
|
||||||
|
* @throws IOException if an I/O error occurs
|
||||||
|
*/
|
||||||
|
static OutputBlockStream getOutputBlockStream(BufferFile bufferFile, int blockCount)
|
||||||
|
throws IOException {
|
||||||
|
// This method is used so we can utilize a package method and avoid putting
|
||||||
|
// it on the BufferFile interface
|
||||||
|
if (bufferFile instanceof BufferFileAdapter) {
|
||||||
|
return ((BufferFileAdapter) bufferFile).getOutputBlockStream(blockCount);
|
||||||
|
}
|
||||||
|
if (bufferFile instanceof LocalBufferFile) {
|
||||||
|
return ((LocalBufferFile) bufferFile).getOutputBlockStream(blockCount);
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Unsupported buffer file implementation: " + bufferFile.getClass().getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy the complete content of a specified srcFile into a destFile excluding file ID. Both
|
||||||
|
* files remain open.
|
||||||
|
* @param srcFile open buffer file
|
||||||
|
* @param destFile empty buffer file which is open for writing.
|
||||||
|
* @param changeMap optional change map which indicates those buffers which must be copied.
|
||||||
|
* Any buffer index outside the range of the change map will also be copied.
|
||||||
|
* @param monitor progress monitor
|
||||||
|
* @throws IOException if IO error occurs.
|
||||||
|
* @throws CancelledException if the monitor cancels the operation.
|
||||||
|
*/
|
||||||
|
public static void copyFile(BufferFile srcFile, BufferFile destFile, ChangeMap changeMap,
|
||||||
|
TaskMonitor monitor) throws IOException, CancelledException {
|
||||||
|
if (destFile.isReadOnly()) {
|
||||||
|
throw new IOException("File is read-only");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (srcFile.getBufferSize() != destFile.getBufferSize()) {
|
||||||
|
throw new IOException("Buffer sizes differ");
|
||||||
|
}
|
||||||
|
|
||||||
|
monitor = TaskMonitor.dummyIfNull(monitor);
|
||||||
|
|
||||||
|
int srcBlockCnt;
|
||||||
|
boolean headerTransferRequired;
|
||||||
|
|
||||||
|
try (InputBlockStream in = getInputBlockStream(srcFile, changeMap)) {
|
||||||
|
headerTransferRequired = !in.includesHeaderBlock();
|
||||||
|
srcBlockCnt = in.getBlockCount();
|
||||||
|
monitor.initialize(srcBlockCnt + 2);
|
||||||
|
try (OutputBlockStream out = getOutputBlockStream(destFile, in.getBlockCount())) {
|
||||||
|
completeBlockStreamTransfer(in, out, monitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
// circumvent other exceptions if cancelled
|
||||||
|
monitor.checkCanceled();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (headerTransferRequired) {
|
||||||
|
destFile.clearParameters();
|
||||||
|
String[] parmNames = srcFile.getParameterNames();
|
||||||
|
for (String name : parmNames) {
|
||||||
|
destFile.setParameter(name, srcFile.getParameter(name));
|
||||||
|
}
|
||||||
|
monitor.setProgress(srcBlockCnt + 1);
|
||||||
|
|
||||||
|
// Copy free index list
|
||||||
|
destFile.setFreeIndexes(srcFile.getFreeIndexes());
|
||||||
|
}
|
||||||
|
monitor.setProgress(srcBlockCnt + 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform a complete block stream transfer from in to out
|
||||||
|
* @param in input block stream
|
||||||
|
* @param out output block stream
|
||||||
|
* @param monitor progress and cancel monitor
|
||||||
|
* @throws CancelledException the the operation is cancelled
|
||||||
|
* @throws IOException if an I/O error occurs
|
||||||
|
*/
|
||||||
|
static void completeBlockStreamTransfer(InputBlockStream in, OutputBlockStream out,
|
||||||
|
TaskMonitor monitor) throws CancelledException, IOException {
|
||||||
|
int count = 0;
|
||||||
|
try (BlockStreamCancelMonitor cancelMonitor =
|
||||||
|
new BlockStreamCancelMonitor(monitor, in, out)) {
|
||||||
|
int srcBlockCnt = in.getBlockCount();
|
||||||
|
BufferFileBlock block;
|
||||||
|
while ((block = in.readBlock()) != null) {
|
||||||
|
monitor.checkCanceled();
|
||||||
|
out.writeBlock(block);
|
||||||
|
monitor.setProgress(count++);
|
||||||
|
}
|
||||||
|
if (count != srcBlockCnt) {
|
||||||
|
throw new IOException("unexpected block transfer count");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to remove all pre-save files.
|
||||||
|
* Those still open by an existing process should
|
||||||
|
* not be removed by the operating system.
|
||||||
|
* @param dir data directory containing pre-save files
|
||||||
|
* @param beforeNow if not 0, file mod time must be less than the specified time
|
||||||
|
*/
|
||||||
|
public static void cleanupOldPreSaveFiles(File dir, long beforeNow) {
|
||||||
|
File[] oldFiles = dir.listFiles(new BufferFileFilter(null, PRESAVE_FILE_EXT));
|
||||||
|
if (oldFiles == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (File oldFile : oldFiles) {
|
||||||
|
if ((beforeNow == 0 || oldFile.lastModified() < beforeNow) && oldFile.delete()) {
|
||||||
|
Msg.info(LocalBufferFile.class, "Removed old presave file: " + oldFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the recommended buffer size given a target buffer size.
|
||||||
|
* @param requestedBufferSize target buffer size
|
||||||
|
* @return recommended buffer size
|
||||||
|
*/
|
||||||
|
static int getRecommendedBufferSize(int requestedBufferSize) {
|
||||||
|
int size = (requestedBufferSize + BUFFER_PREFIX_SIZE) & -MINIMUM_BLOCK_SIZE;
|
||||||
|
if (size <= 0) {
|
||||||
|
size = MINIMUM_BLOCK_SIZE;
|
||||||
|
}
|
||||||
|
return size - BUFFER_PREFIX_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=================================================================================================
|
||||||
|
// Inner Classes
|
||||||
|
//=================================================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <code>LocalBufferInputBlockStream</code> provides an input BlockStream for
|
||||||
* transferring the entire file content associated with a read-only buffer
|
* transferring the entire file content associated with a read-only buffer
|
||||||
* file use a buffer-based transfer.
|
* file use a buffer-based transfer.
|
||||||
*/
|
*/
|
||||||
@@ -917,7 +1131,7 @@ public class LocalBufferFile implements BufferFile {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct input block stream for this buffer file.
|
* Construct input block stream for this buffer file.
|
||||||
* @throws IOException
|
* @throws IOException if an I/O error occurs
|
||||||
*/
|
*/
|
||||||
LocalBufferInputBlockStream() throws IOException {
|
LocalBufferInputBlockStream() throws IOException {
|
||||||
if (!isReadOnly()) {
|
if (!isReadOnly()) {
|
||||||
@@ -977,10 +1191,10 @@ public class LocalBufferFile implements BufferFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <code>LocalFileInputBlockStream</code> provides an input BlockStream for
|
* <code>LocalFileInputBlockStream</code> provides an input BlockStream for
|
||||||
* transferring the entire file content associated with a read-only file.
|
* transferring the entire file content associated with a read-only file.
|
||||||
* This implementation reads the data directly from a single local file
|
* This implementation reads the data directly from a single local file
|
||||||
* and must not be used when performing version reconstruction or
|
* and must not be used when performing version reconstruction or
|
||||||
* change-map driven streams.
|
* change-map driven streams.
|
||||||
*/
|
*/
|
||||||
private class LocalFileInputBlockStream implements InputBlockStream {
|
private class LocalFileInputBlockStream implements InputBlockStream {
|
||||||
@@ -991,7 +1205,7 @@ public class LocalBufferFile implements BufferFile {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct input block stream for entire file
|
* Construct input block stream for entire file
|
||||||
* @throws IOException
|
* @throws IOException if an I/O error occurs
|
||||||
*/
|
*/
|
||||||
LocalFileInputBlockStream() throws IOException {
|
LocalFileInputBlockStream() throws IOException {
|
||||||
if (!readOnly) {
|
if (!readOnly) {
|
||||||
@@ -1053,7 +1267,7 @@ public class LocalBufferFile implements BufferFile {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The <code>bufferIndexList</code> contains the DataBuffer indexes
|
* The <code>bufferIndexList</code> contains the DataBuffer indexes
|
||||||
* which are to be transferred. Buffer index values plus 1 equal the
|
* which are to be transferred. Buffer index values plus 1 equal the
|
||||||
* file block index.
|
* file block index.
|
||||||
*/
|
*/
|
||||||
private List<Integer> bufferIndexList;
|
private List<Integer> bufferIndexList;
|
||||||
@@ -1067,11 +1281,11 @@ public class LocalBufferFile implements BufferFile {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct input block stream for specific block indexes
|
* Construct input block stream for specific block indexes
|
||||||
* within the file based upon a changeMap. The head buffer
|
* within the file based upon a changeMap. The head buffer
|
||||||
* will never be included in the transfer.
|
* will never be included in the transfer.
|
||||||
* @param changeMapData ChangeMap data which is used in determining which
|
* @param changeMapData ChangeMap data which is used in determining which
|
||||||
* buffers should be streamed
|
* buffers should be streamed
|
||||||
* @throws IOException
|
* @throws IOException if an I/O error occurs
|
||||||
*/
|
*/
|
||||||
LocalRandomInputBlockStream(byte[] changeMapData) throws IOException {
|
LocalRandomInputBlockStream(byte[] changeMapData) throws IOException {
|
||||||
if (!readOnly) {
|
if (!readOnly) {
|
||||||
@@ -1141,7 +1355,7 @@ public class LocalBufferFile implements BufferFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <code>LocalOutputBlockStream</code> provides an OutputBlockStream for
|
* <code>LocalOutputBlockStream</code> provides an OutputBlockStream for
|
||||||
* updating specific buffers of a non-read-only file.
|
* updating specific buffers of a non-read-only file.
|
||||||
*/
|
*/
|
||||||
class LocalOutputBlockStream implements OutputBlockStream {
|
class LocalOutputBlockStream implements OutputBlockStream {
|
||||||
@@ -1230,187 +1444,13 @@ public class LocalBufferFile implements BufferFile {
|
|||||||
public int getBlockSize() {
|
public int getBlockSize() {
|
||||||
return blockSize;
|
return blockSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtain a direct stream to read all blocks of this buffer file
|
|
||||||
* @return input block stream
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
public InputBlockStream getInputBlockStream() throws IOException {
|
|
||||||
if (!readOnly) {
|
|
||||||
throw new IOException("Read stream only permitted on read-only buffer file");
|
|
||||||
}
|
|
||||||
return new LocalFileInputBlockStream();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtain a direct stream to write blocks to this buffer file
|
|
||||||
* @param blockCount number of blocks to be transferred
|
|
||||||
* @return output block stream
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
public OutputBlockStream getOutputBlockStream(int blockCount) throws IOException {
|
|
||||||
return new LocalOutputBlockStream(blockCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Factory method for generating the appropriate type of {@link InputBlockStream}
|
|
||||||
* for the specified read-only bufferFile. Input stream may not supply header block in which case
|
|
||||||
* free list and file parameters may need to be set separately.
|
|
||||||
* @param bufferFile buffer file opened read-only
|
|
||||||
* @return input block stream object
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
private static InputBlockStream getInputBlockStream(BufferFile bufferFile) throws IOException {
|
|
||||||
// This method is used so we can utilize a package method and avoid putting
|
|
||||||
// it on the BufferFile interface
|
|
||||||
if (bufferFile instanceof BufferFileAdapter) {
|
|
||||||
return ((BufferFileAdapter) bufferFile).getInputBlockStream();
|
|
||||||
}
|
|
||||||
if (bufferFile instanceof LocalBufferFile) {
|
|
||||||
return ((LocalBufferFile) bufferFile).getInputBlockStream();
|
|
||||||
}
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Unsupported buffer file implementation: " + bufferFile.getClass().getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Factory method for generating the appropriate type of {@link InputBlockStream}
|
|
||||||
* for the specified read-only bufferFile with an optional changeMap used
|
|
||||||
* to select which buffer should be transferred. Input stream may not supply header block
|
|
||||||
* in which case free list and file parameters may need to be set separately.
|
|
||||||
* @param bufferFile buffer file opened read-only
|
|
||||||
* @return input block stream object
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
private static InputBlockStream getInputBlockStream(BufferFile bufferFile, ChangeMap changeMap)
|
|
||||||
throws IOException {
|
|
||||||
if (changeMap == null) {
|
|
||||||
return getInputBlockStream(bufferFile);
|
|
||||||
}
|
|
||||||
// This method is used so we can utilize a package method and avoid putting
|
|
||||||
// it on the BufferFile interface
|
|
||||||
if (bufferFile instanceof ManagedBufferFileAdapter) {
|
|
||||||
return ((ManagedBufferFileAdapter) bufferFile).getInputBlockStream(changeMap.getData());
|
|
||||||
}
|
|
||||||
if (bufferFile instanceof LocalManagedBufferFile) {
|
|
||||||
return ((LocalManagedBufferFile) bufferFile).getInputBlockStream(changeMap.getData());
|
|
||||||
}
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Unsupported buffer file implementation: " + bufferFile.getClass().getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Factory method for generating the appropriate type of {@link OutputBlockStream}
|
|
||||||
* for the specified write-able bufferFile.
|
|
||||||
* @param bufferFile write-able buffer file
|
|
||||||
* @param blockCount number of blocks to be written. This should be available from
|
|
||||||
* the corresponding {@link InputBlockStream}.
|
|
||||||
* @return output block stream object
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
static OutputBlockStream getOutputBlockStream(BufferFile bufferFile, int blockCount)
|
|
||||||
throws IOException {
|
|
||||||
// This method is used so we can utilize a package method and avoid putting
|
|
||||||
// it on the BufferFile interface
|
|
||||||
if (bufferFile instanceof BufferFileAdapter) {
|
|
||||||
return ((BufferFileAdapter) bufferFile).getOutputBlockStream(blockCount);
|
|
||||||
}
|
|
||||||
if (bufferFile instanceof LocalBufferFile) {
|
|
||||||
return ((LocalBufferFile) bufferFile).getOutputBlockStream(blockCount);
|
|
||||||
}
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Unsupported buffer file implementation: " + bufferFile.getClass().getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copy the complete content of a specfied srcFile into a destFile
|
|
||||||
* excluding file ID. Both files remain open.
|
|
||||||
* @param srcFile open buffer file
|
|
||||||
* @param destFile empty buffer file which is open for writing.
|
|
||||||
* @param changeMap optional change map which indicates those buffers which must be copied.
|
|
||||||
* Any buffer index outside the range of the change map will also be copied.
|
|
||||||
* @param monitor progress monitor
|
|
||||||
* @throws IOException if IO error occurs.
|
|
||||||
* @throws CancelledException if the monitor cancels the operation.
|
|
||||||
*/
|
|
||||||
public static void copyFile(BufferFile srcFile, BufferFile destFile, ChangeMap changeMap,
|
|
||||||
TaskMonitor monitor) throws IOException, CancelledException {
|
|
||||||
if (destFile.isReadOnly()) {
|
|
||||||
throw new IOException("File is read-only");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (srcFile.getBufferSize() != destFile.getBufferSize()) {
|
|
||||||
throw new IOException("Buffer sizes differ");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (monitor == null) {
|
|
||||||
monitor = TaskMonitorAdapter.DUMMY_MONITOR;
|
|
||||||
}
|
|
||||||
|
|
||||||
int srcBlockCnt;
|
|
||||||
boolean headerTransferRequired;
|
|
||||||
|
|
||||||
try (InputBlockStream in = getInputBlockStream(srcFile, changeMap)) {
|
|
||||||
headerTransferRequired = !in.includesHeaderBlock();
|
|
||||||
srcBlockCnt = in.getBlockCount();
|
|
||||||
monitor.initialize(srcBlockCnt + 2);
|
|
||||||
try (OutputBlockStream out = getOutputBlockStream(destFile, in.getBlockCount())) {
|
|
||||||
completeBlockStreamTransfer(in, out, monitor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
// circumvent other exceptions if cancelled
|
|
||||||
monitor.checkCanceled();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (headerTransferRequired) {
|
|
||||||
destFile.clearParameters();
|
|
||||||
String[] parmNames = srcFile.getParameterNames();
|
|
||||||
for (String name : parmNames) {
|
|
||||||
destFile.setParameter(name, srcFile.getParameter(name));
|
|
||||||
}
|
|
||||||
monitor.setProgress(srcBlockCnt + 1);
|
|
||||||
|
|
||||||
// Copy free index list
|
|
||||||
destFile.setFreeIndexes(srcFile.getFreeIndexes());
|
|
||||||
}
|
|
||||||
monitor.setProgress(srcBlockCnt + 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform a complete block stream transfer from in to out
|
|
||||||
* @param in input block stream
|
|
||||||
* @param out output block stream
|
|
||||||
* @param monitor progress and cancel monitor
|
|
||||||
* @throws CancelledException
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
static void completeBlockStreamTransfer(InputBlockStream in, OutputBlockStream out,
|
|
||||||
TaskMonitor monitor) throws CancelledException, IOException {
|
|
||||||
int count = 0;
|
|
||||||
try (BlockStreamCancelMonitor cancelMonitor =
|
|
||||||
new BlockStreamCancelMonitor(monitor, in, out)) {
|
|
||||||
int srcBlockCnt = in.getBlockCount();
|
|
||||||
BufferFileBlock block;
|
|
||||||
while ((block = in.readBlock()) != null) {
|
|
||||||
monitor.checkCanceled();
|
|
||||||
out.writeBlock(block);
|
|
||||||
monitor.setProgress(count++);
|
|
||||||
}
|
|
||||||
if (count != srcBlockCnt) {
|
|
||||||
throw new IOException("unexpected block transfer count");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <code>BlockStreamCancelMonitor</code> is used to close associated BlockStreams
|
* <code>BlockStreamCancelMonitor</code> is used to close associated BlockStreams
|
||||||
* when a TaskMonitor is cancelled
|
* when a TaskMonitor is cancelled
|
||||||
*/
|
*/
|
||||||
static class BlockStreamCancelMonitor implements Closeable, CancelledListener {
|
private static class BlockStreamCancelMonitor implements Closeable, CancelledListener {
|
||||||
|
|
||||||
private TaskMonitor monitor;
|
private TaskMonitor monitor;
|
||||||
private BlockStream[] blockStreams;
|
private BlockStream[] blockStreams;
|
||||||
@@ -1467,45 +1507,32 @@ public class LocalBufferFile implements BufferFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempt to remove all pre-save files.
|
* A simple interface that allows for dependency injection
|
||||||
* Those still open by an existing process should
|
|
||||||
* not be removed by the operating system.
|
|
||||||
* @param dir data directory containing presave files
|
|
||||||
* @param beforeNow if not 0, file mod time must be less than the specified time
|
|
||||||
*/
|
*/
|
||||||
public static void cleanupOldPreSaveFiles(File dir, long beforeNow) {
|
public static interface InputBlockStreamFactory {
|
||||||
File[] oldFiles = dir.listFiles(new BufferFileFilter(null, PRESAVE_FILE_EXT));
|
public InputBlockStream createInputBlockStream(LocalBufferFile bf) throws IOException;
|
||||||
if (oldFiles == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (File oldFile : oldFiles) {
|
|
||||||
if ((beforeNow == 0 || oldFile.lastModified() < beforeNow) &&
|
|
||||||
oldFile.delete()) {
|
|
||||||
Msg.info(LocalBufferFile.class, "Removed old presave file: " + oldFile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the recommended buffer size given a target buffer size.
|
* A factory to supply the default implementation for create an {@link InputBlockStream}
|
||||||
* @param requestedBufferSize target buffer size
|
|
||||||
* @return recommended buffer size
|
|
||||||
*/
|
*/
|
||||||
static int getRecommendedBufferSize(int requestedBufferSize) {
|
private static class DefaultInputBlockStreamFactory implements InputBlockStreamFactory {
|
||||||
int size = (requestedBufferSize + BUFFER_PREFIX_SIZE) & -MINIMUM_BLOCK_SIZE;
|
@Override
|
||||||
if (size <= 0) {
|
public InputBlockStream createInputBlockStream(LocalBufferFile bf) throws IOException {
|
||||||
size = MINIMUM_BLOCK_SIZE;
|
if (!bf.readOnly) {
|
||||||
|
throw new IOException("Read stream only permitted on read-only buffer file");
|
||||||
|
}
|
||||||
|
return bf.new LocalFileInputBlockStream();
|
||||||
}
|
}
|
||||||
return size - BUFFER_PREFIX_SIZE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// private void checkSameContent(BufferFile expectedBf, BufferFile inspectedBf) throws IOException {
|
// private void checkSameContent(BufferFile expectedBf, BufferFile inspectedBf) throws IOException {
|
||||||
//
|
//
|
||||||
// //assertEquals(inspectedBf.getIndexCount(), expectedBf.getIndexCount());
|
// //assertEquals(inspectedBf.getIndexCount(), expectedBf.getIndexCount());
|
||||||
// if(inspectedBf.getIndexCount() != expectedBf.getIndexCount()) {
|
// if(inspectedBf.getIndexCount() != expectedBf.getIndexCount()) {
|
||||||
// System.err.println("Buffer count mismatch following update");
|
// System.err.println("Buffer count mismatch following update");
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// int[] vFreeList = inspectedBf.getFreeIndexes();
|
// int[] vFreeList = inspectedBf.getFreeIndexes();
|
||||||
// int[] pFreeList = inspectedBf.getFreeIndexes();
|
// int[] pFreeList = inspectedBf.getFreeIndexes();
|
||||||
// Arrays.sort(vFreeList);
|
// Arrays.sort(vFreeList);
|
||||||
@@ -1517,13 +1544,13 @@ public class LocalBufferFile implements BufferFile {
|
|||||||
// if (!Arrays.equals(expectedBf.getParameterNames(), inspectedBf.getParameterNames())) {
|
// if (!Arrays.equals(expectedBf.getParameterNames(), inspectedBf.getParameterNames())) {
|
||||||
// System.err.println("Parameter list mismatch following update");
|
// System.err.println("Parameter list mismatch following update");
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// for (String name : expectedBf.getParameterNames()) {
|
// for (String name : expectedBf.getParameterNames()) {
|
||||||
// if (expectedBf.getParameter(name) != inspectedBf.getParameter(name)) {
|
// if (expectedBf.getParameter(name) != inspectedBf.getParameter(name)) {
|
||||||
// System.err.println("Parameter " + name + " mismatch following update");
|
// System.err.println("Parameter " + name + " mismatch following update");
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// DataBuffer pbuf = new DataBuffer();
|
// DataBuffer pbuf = new DataBuffer();
|
||||||
// DataBuffer vbuf = new DataBuffer();
|
// DataBuffer vbuf = new DataBuffer();
|
||||||
// int cnt = inspectedBf.getIndexCount();
|
// int cnt = inspectedBf.getIndexCount();
|
||||||
@@ -1531,7 +1558,7 @@ public class LocalBufferFile implements BufferFile {
|
|||||||
// checkSameContent(i, expectedBf.get(vbuf, i), inspectedBf.get(pbuf, i));
|
// checkSameContent(i, expectedBf.get(vbuf, i), inspectedBf.get(pbuf, i));
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// private void checkSameContent(int index, DataBuffer expectedBuf, DataBuffer inspectedBuf) {
|
// private void checkSameContent(int index, DataBuffer expectedBuf, DataBuffer inspectedBuf) {
|
||||||
// if (expectedBuf.isEmpty() != inspectedBuf.isEmpty()) {
|
// if (expectedBuf.isEmpty() != inspectedBuf.isEmpty()) {
|
||||||
// System.err.println("Buffer " + index + " empty flag mismatch following update");
|
// System.err.println("Buffer " + index + " empty flag mismatch following update");
|
||||||
|
|||||||
@@ -27,14 +27,17 @@ import javax.swing.table.TableColumn;
|
|||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import docking.test.AbstractDockingTest;
|
||||||
import docking.widgets.table.*;
|
import docking.widgets.table.*;
|
||||||
import docking.widgets.table.constraint.ColumnConstraint;
|
import docking.widgets.table.constraint.ColumnConstraint;
|
||||||
import docking.widgets.table.constraint.MappedColumnConstraint;
|
import docking.widgets.table.constraint.MappedColumnConstraint;
|
||||||
import docking.widgets.table.constraint.dialog.*;
|
import docking.widgets.table.constraint.dialog.*;
|
||||||
import docking.widgets.table.constraint.provider.*;
|
import docking.widgets.table.constraint.provider.*;
|
||||||
import ghidra.framework.options.SaveState;
|
import ghidra.framework.options.SaveState;
|
||||||
import mockit.Mock;
|
import ghidra.util.Msg;
|
||||||
import mockit.MockUp;
|
import ghidra.util.classfinder.ClassSearcher;
|
||||||
|
import ghidra.util.exception.CancelledException;
|
||||||
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This test performs operations on swing components in the test thread. I believe this is ok
|
* This test performs operations on swing components in the test thread. I believe this is ok
|
||||||
@@ -42,29 +45,17 @@ import mockit.MockUp;
|
|||||||
* involved. If this test has displays intermittent failures, then more work will be needed to
|
* involved. If this test has displays intermittent failures, then more work will be needed to
|
||||||
* fix the threading when accessing swing components.
|
* fix the threading when accessing swing components.
|
||||||
*/
|
*/
|
||||||
public class ColumnTableFilterTest {
|
public class ColumnTableFilterTest extends AbstractDockingTest {
|
||||||
private SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("MM/dd/yyyy");
|
private SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("MM/dd/yyyy");
|
||||||
private RowObjectFilterModel<Integer> tableModel;
|
private RowObjectFilterModel<Integer> tableModel;
|
||||||
private GTable gTable;
|
private GTable gTable;
|
||||||
private ColumnFilterDialogModel<Integer> filterModel;
|
private ColumnFilterDialogModel<Integer> filterModel;
|
||||||
private List<ColumnConstraint<?>> allConstraints;
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() throws Exception {
|
||||||
allConstraints = loadConstraints();
|
|
||||||
// using a mock up to load discoverable column filters without performing a class search.
|
ClassSearcher.search(TaskMonitor.DUMMY);
|
||||||
new MockUp<DiscoverableTableUtils>() {
|
|
||||||
@Mock
|
|
||||||
public List<ColumnConstraint<?>> getColumnConstraints(Class<?> columnType) {
|
|
||||||
List<ColumnConstraint<?>> matches = new ArrayList<>();
|
|
||||||
for (ColumnConstraint<?> columnConstraint : allConstraints) {
|
|
||||||
if (columnConstraint.getColumnType().equals(columnType)) {
|
|
||||||
matches.add(columnConstraint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return matches;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
tableModel = createTableModel();
|
tableModel = createTableModel();
|
||||||
gTable = new GTable(tableModel);
|
gTable = new GTable(tableModel);
|
||||||
filterModel = new ColumnFilterDialogModel<>(tableModel, gTable.getColumnModel(), null);
|
filterModel = new ColumnFilterDialogModel<>(tableModel, gTable.getColumnModel(), null);
|
||||||
|
|||||||
@@ -23,13 +23,13 @@ import java.io.IOException;
|
|||||||
import org.junit.*;
|
import org.junit.*;
|
||||||
|
|
||||||
import db.buffers.*;
|
import db.buffers.*;
|
||||||
|
import db.buffers.LocalBufferFile.InputBlockStreamFactory;
|
||||||
import generic.test.AbstractGenericTest;
|
import generic.test.AbstractGenericTest;
|
||||||
import ghidra.framework.store.local.LocalFileSystem;
|
import ghidra.framework.store.local.LocalFileSystem;
|
||||||
import ghidra.framework.store.local.LocalFolderItem;
|
import ghidra.framework.store.local.LocalFolderItem;
|
||||||
import ghidra.util.InvalidNameException;
|
import ghidra.util.InvalidNameException;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
import mockit.*;
|
|
||||||
import utilities.util.FileUtilities;
|
import utilities.util.FileUtilities;
|
||||||
|
|
||||||
public class VersionFailureRecoveryTest extends AbstractGenericTest {
|
public class VersionFailureRecoveryTest extends AbstractGenericTest {
|
||||||
@@ -65,7 +65,7 @@ public class VersionFailureRecoveryTest extends AbstractGenericTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testAddToVersionControlFailure() {
|
public void testAddToVersionControlFailure() {
|
||||||
|
|
||||||
new FakeBadBufferFile(); // setup for mocking
|
setInstanceField("inputBlockStreamFactory", LocalBufferFile.class, factory);
|
||||||
|
|
||||||
LocalBufferFile fakeBadBufferFile = null;
|
LocalBufferFile fakeBadBufferFile = null;
|
||||||
try {
|
try {
|
||||||
@@ -99,18 +99,10 @@ public class VersionFailureRecoveryTest extends AbstractGenericTest {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class FakeBadBufferFile extends MockUp<LocalBufferFile> {
|
private InputBlockStreamFactory factory = new InputBlockStreamFactory() {
|
||||||
|
|
||||||
@Mock
|
|
||||||
public int getIndexCount() {
|
|
||||||
return 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
public InputBlockStream getInputBlockStream(Invocation invocation) {
|
|
||||||
|
|
||||||
LocalBufferFile bufferFile = invocation.getInvokedInstance();
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputBlockStream createInputBlockStream(LocalBufferFile bf) throws IOException {
|
||||||
return new InputBlockStream() {
|
return new InputBlockStream() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -125,7 +117,7 @@ public class VersionFailureRecoveryTest extends AbstractGenericTest {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getBlockSize() {
|
public int getBlockSize() {
|
||||||
return bufferFile.getBufferSize();
|
return bf.getBufferSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -135,10 +127,55 @@ public class VersionFailureRecoveryTest extends AbstractGenericTest {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getBlockCount() {
|
public int getBlockCount() {
|
||||||
return bufferFile.getIndexCount();
|
return bf.getIndexCount();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
private class FakeBadBufferFile extends LocalBufferFile {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getIndexCount() {
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputBlockStream getInputBlockStream() {
|
||||||
|
|
||||||
|
LocalBufferFile bufferFile = null;
|
||||||
|
|
||||||
|
return new InputBlockStream() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean includesHeaderBlock() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBlockSize() {
|
||||||
|
return bufferFile.getBufferSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BufferFileBlock readBlock() throws IOException {
|
||||||
|
throw new IOException("forced block read failure");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBlockCount() {
|
||||||
|
return bufferFile.getIndexCount();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}*/
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user