Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
b6ad6d6a
提交
b6ad6d6a
authored
9月 19, 2011
作者:
Thomas Mueller
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Improved compatibility with the Java 7 FileSystem abstraction.
上级
fa398730
全部展开
隐藏空白字符变更
内嵌
并排
正在显示
49 个修改的文件
包含
1885 行增加
和
1910 行删除
+1885
-1910
advanced.html
h2/src/docsrc/html/advanced.html
+1
-1
BackupCommand.java
h2/src/main/org/h2/command/dml/BackupCommand.java
+2
-2
ConnectionInfo.java
h2/src/main/org/h2/engine/ConnectionInfo.java
+3
-3
Database.java
h2/src/main/org/h2/engine/Database.java
+2
-3
CipherFactory.java
h2/src/main/org/h2/security/CipherFactory.java
+1
-1
Data.java
h2/src/main/org/h2/store/Data.java
+3
-3
FileLister.java
h2/src/main/org/h2/store/FileLister.java
+3
-5
FileStore.java
h2/src/main/org/h2/store/FileStore.java
+9
-8
FileBase.java
h2/src/main/org/h2/store/fs/FileBase.java
+71
-0
FileChannelInputStream.java
h2/src/main/org/h2/store/fs/FileChannelInputStream.java
+14
-12
FileChannelOutputStream.java
h2/src/main/org/h2/store/fs/FileChannelOutputStream.java
+16
-14
FileObject.java
h2/src/main/org/h2/store/fs/FileObject.java
+0
-81
FileObjectDisk.java
h2/src/main/org/h2/store/fs/FileObjectDisk.java
+0
-82
FileObjectMem.java
h2/src/main/org/h2/store/fs/FileObjectMem.java
+0
-68
FileObjectMemData.java
h2/src/main/org/h2/store/fs/FileObjectMemData.java
+0
-312
FileObjectNio.java
h2/src/main/org/h2/store/fs/FileObjectNio.java
+0
-104
FileObjectNioMapped.java
h2/src/main/org/h2/store/fs/FileObjectNioMapped.java
+0
-208
FileObjectRec.java
h2/src/main/org/h2/store/fs/FileObjectRec.java
+0
-70
FileObjectSplit.java
h2/src/main/org/h2/store/fs/FileObjectSplit.java
+0
-161
FileObjectZip.java
h2/src/main/org/h2/store/fs/FileObjectZip.java
+0
-111
FilePath.java
h2/src/main/org/h2/store/fs/FilePath.java
+6
-5
FilePathDisk.java
h2/src/main/org/h2/store/fs/FilePathDisk.java
+88
-7
FilePathMem.java
h2/src/main/org/h2/store/fs/FilePathMem.java
+395
-16
FilePathNio.java
h2/src/main/org/h2/store/fs/FilePathNio.java
+77
-2
FilePathNioMapped.java
h2/src/main/org/h2/store/fs/FilePathNioMapped.java
+216
-2
FilePathRec.java
h2/src/main/org/h2/store/fs/FilePathRec.java
+70
-2
FilePathSplit.java
h2/src/main/org/h2/store/fs/FilePathSplit.java
+164
-20
FilePathWrapper.java
h2/src/main/org/h2/store/fs/FilePathWrapper.java
+7
-6
FilePathZip.java
h2/src/main/org/h2/store/fs/FilePathZip.java
+106
-5
FileUtils.java
h2/src/main/org/h2/store/fs/FileUtils.java
+47
-13
Backup.java
h2/src/main/org/h2/tools/Backup.java
+3
-4
ValueLob.java
h2/src/main/org/h2/value/ValueLob.java
+4
-4
TestCases.java
h2/src/test/org/h2/test/db/TestCases.java
+3
-4
TestLinkedTable.java
h2/src/test/org/h2/test/db/TestLinkedTable.java
+1
-2
TestLob.java
h2/src/test/org/h2/test/db/TestLob.java
+13
-17
TestOpenClose.java
h2/src/test/org/h2/test/db/TestOpenClose.java
+6
-5
TestClearReferences.java
h2/src/test/org/h2/test/unit/TestClearReferences.java
+1
-1
TestFileLockSerialized.java
h2/src/test/org/h2/test/unit/TestFileLockSerialized.java
+2
-3
TestFileSystem.java
h2/src/test/org/h2/test/unit/TestFileSystem.java
+54
-40
TestPageStoreCoverage.java
h2/src/test/org/h2/test/unit/TestPageStoreCoverage.java
+3
-3
TestRecovery.java
h2/src/test/org/h2/test/unit/TestRecovery.java
+5
-4
FileDebug.java
h2/src/test/org/h2/test/utils/FileDebug.java
+0
-92
FilePathDebug.java
h2/src/test/org/h2/test/utils/FilePathDebug.java
+96
-10
FileObjectCrypt.java
h2/src/tools/org/h2/dev/fs/FileObjectCrypt.java
+0
-242
FileObjectZip2.java
h2/src/tools/org/h2/dev/fs/FileObjectZip2.java
+0
-121
FilePathCrypt.java
h2/src/tools/org/h2/dev/fs/FilePathCrypt.java
+260
-11
FilePathZip2.java
h2/src/tools/org/h2/dev/fs/FilePathZip2.java
+121
-8
FileShell.java
h2/src/tools/org/h2/dev/fs/FileShell.java
+9
-9
FtpServer.java
h2/src/tools/org/h2/dev/ftp/server/FtpServer.java
+3
-3
没有找到文件。
h2/src/docsrc/html/advanced.html
浏览文件 @
b6ad6d6a
...
...
@@ -1483,7 +1483,7 @@ As an example, to use the the <code>nio</code> file system, use the following da
<code>
jdbc:h2:nio:~/test
</code>
.
</p>
<p>
To register a new file system, extend the classes
<code>
org.h2.store.fs.FilePath, File
Object
</code>
,
To register a new file system, extend the classes
<code>
org.h2.store.fs.FilePath, File
Base
</code>
,
and call the method
<code>
FilePath.register
</code>
before using it.
</p>
<p>
...
...
h2/src/main/org/h2/command/dml/BackupCommand.java
浏览文件 @
b6ad6d6a
...
...
@@ -101,8 +101,8 @@ public class BackupCommand extends Prepared {
}
private
static
void
backupFile
(
ZipOutputStream
out
,
String
base
,
String
fn
)
throws
IOException
{
String
f
=
FileUtils
.
getCanonic
alPath
(
fn
);
base
=
FileUtils
.
getCanonic
alPath
(
base
);
String
f
=
FileUtils
.
toRe
alPath
(
fn
);
base
=
FileUtils
.
toRe
alPath
(
base
);
if
(!
f
.
startsWith
(
base
))
{
DbException
.
throwInternalError
(
f
+
" does not start with "
+
base
);
}
...
...
h2/src/main/org/h2/engine/ConnectionInfo.java
浏览文件 @
b6ad6d6a
...
...
@@ -159,7 +159,7 @@ public class ConnectionInfo implements Cloneable {
*/
public
void
setBaseDir
(
String
dir
)
{
if
(
persistent
)
{
String
absDir
=
FileUtils
.
unwrap
(
FileUtils
.
getCanonic
alPath
(
dir
));
String
absDir
=
FileUtils
.
unwrap
(
FileUtils
.
toRe
alPath
(
dir
));
boolean
absolute
=
FileUtils
.
isAbsolute
(
name
);
String
n
;
String
prefix
=
null
;
...
...
@@ -170,7 +170,7 @@ public class ConnectionInfo implements Cloneable {
prefix
=
name
.
substring
(
0
,
name
.
length
()
-
n
.
length
());
n
=
dir
+
SysProperties
.
FILE_SEPARATOR
+
n
;
}
String
normalizedName
=
FileUtils
.
unwrap
(
FileUtils
.
getCanonic
alPath
(
n
));
String
normalizedName
=
FileUtils
.
unwrap
(
FileUtils
.
toRe
alPath
(
n
));
if
(
normalizedName
.
equals
(
absDir
)
||
!
normalizedName
.
startsWith
(
absDir
))
{
throw
DbException
.
get
(
ErrorCode
.
IO_EXCEPTION_1
,
normalizedName
+
" outside "
+
absDir
);
...
...
@@ -364,7 +364,7 @@ public class ConnectionInfo implements Cloneable {
if
(
persistent
)
{
if
(
nameNormalized
==
null
)
{
String
suffix
=
Constants
.
SUFFIX_PAGE_FILE
;
String
n
=
FileUtils
.
getCanonic
alPath
(
name
+
suffix
);
String
n
=
FileUtils
.
toRe
alPath
(
name
+
suffix
);
String
fileName
=
FileUtils
.
getName
(
n
);
if
(
fileName
.
length
()
<
suffix
.
length
()
+
1
)
{
throw
DbException
.
get
(
ErrorCode
.
INVALID_DATABASE_NAME_1
,
name
);
...
...
h2/src/main/org/h2/engine/Database.java
浏览文件 @
b6ad6d6a
...
...
@@ -1348,7 +1348,7 @@ public class Database implements DataHandler {
public
String
getDatabasePath
()
{
if
(
persistent
)
{
return
FileUtils
.
getCanonic
alPath
(
databaseName
);
return
FileUtils
.
toRe
alPath
(
databaseName
);
}
return
null
;
}
...
...
@@ -1477,8 +1477,7 @@ public class Database implements DataHandler {
private
void
deleteOldTempFiles
()
{
String
path
=
FileUtils
.
getParent
(
databaseName
);
String
[]
list
=
FileUtils
.
listFiles
(
path
);
for
(
String
name
:
list
)
{
for
(
String
name
:
FileUtils
.
newDirectoryStream
(
path
))
{
if
(
name
.
endsWith
(
Constants
.
SUFFIX_TEMP_FILE
)
&&
name
.
startsWith
(
databaseName
))
{
// can't always delete the files, they may still be open
FileUtils
.
tryDelete
(
name
);
...
...
h2/src/main/org/h2/security/CipherFactory.java
浏览文件 @
b6ad6d6a
...
...
@@ -244,7 +244,7 @@ public class CipherFactory {
throw
DbException
.
convertToIOException
(
e
);
}
}
String
absolutePath
=
FileUtils
.
getCanonic
alPath
(
fileName
);
String
absolutePath
=
FileUtils
.
toRe
alPath
(
fileName
);
System
.
setProperty
(
KEYSTORE_KEY
,
absolutePath
);
}
if
(
p
.
getProperty
(
KEYSTORE_PASSWORD_KEY
)
==
null
)
{
...
...
h2/src/main/org/h2/store/Data.java
浏览文件 @
b6ad6d6a
...
...
@@ -90,7 +90,7 @@ public class Data {
/**
* The data itself.
*/
pr
otected
byte
[]
data
;
pr
ivate
byte
[]
data
;
/**
* The current write or read position.
...
...
@@ -102,7 +102,7 @@ public class Data {
*/
private
final
DataHandler
handler
;
pr
otected
Data
(
DataHandler
handler
,
byte
[]
data
)
{
pr
ivate
Data
(
DataHandler
handler
,
byte
[]
data
)
{
this
.
handler
=
handler
;
this
.
data
=
data
;
}
...
...
@@ -1131,7 +1131,7 @@ public class Data {
* @param x the value
* @return the len
*/
p
ublic
static
int
getVarIntLen
(
int
x
)
{
p
rivate
static
int
getVarIntLen
(
int
x
)
{
if
((
x
&
(-
1
<<
7
))
==
0
)
{
return
1
;
}
else
if
((
x
&
(-
1
<<
14
))
==
0
)
{
...
...
h2/src/main/org/h2/store/FileLister.java
浏览文件 @
b6ad6d6a
...
...
@@ -58,7 +58,7 @@ public class FileLister {
if
(
dir
==
null
||
dir
.
equals
(
""
))
{
return
"."
;
}
return
FileUtils
.
getCanonic
alPath
(
dir
);
return
FileUtils
.
toRe
alPath
(
dir
);
}
/**
...
...
@@ -74,10 +74,8 @@ public class FileLister {
public
static
ArrayList
<
String
>
getDatabaseFiles
(
String
dir
,
String
db
,
boolean
all
)
{
ArrayList
<
String
>
files
=
New
.
arrayList
();
// for Windows, File.getCanonicalPath("...b.") returns just "...b"
String
start
=
db
==
null
?
null
:
(
FileUtils
.
getCanonicalPath
(
dir
+
"/"
+
db
)
+
"."
);
String
[]
list
=
FileUtils
.
listFiles
(
dir
);
for
(
int
i
=
0
;
list
!=
null
&&
i
<
list
.
length
;
i
++)
{
String
f
=
list
[
i
];
String
start
=
db
==
null
?
null
:
(
FileUtils
.
toRealPath
(
dir
+
"/"
+
db
)
+
"."
);
for
(
String
f
:
FileUtils
.
newDirectoryStream
(
dir
))
{
boolean
ok
=
false
;
if
(
f
.
endsWith
(
Constants
.
SUFFIX_LOBS_DIRECTORY
))
{
if
(
start
==
null
||
f
.
startsWith
(
start
))
{
...
...
h2/src/main/org/h2/store/FileStore.java
浏览文件 @
b6ad6d6a
...
...
@@ -8,12 +8,13 @@ package org.h2.store;
import
java.io.IOException
;
import
java.lang.ref.Reference
;
import
java.nio.ByteBuffer
;
import
java.nio.channels.FileChannel
;
import
org.h2.constant.ErrorCode
;
import
org.h2.constant.SysProperties
;
import
org.h2.engine.Constants
;
import
org.h2.message.DbException
;
import
org.h2.security.SecureFileStore
;
import
org.h2.store.fs.FileObject
;
import
org.h2.store.fs.FileUtils
;
import
org.h2.util.TempFileDeleter
;
import
org.h2.util.Utils
;
...
...
@@ -46,7 +47,7 @@ public class FileStore {
*/
protected
DataHandler
handler
;
private
File
Object
file
;
private
File
Channel
file
;
private
long
filePos
;
private
long
fileLength
;
private
Reference
<?>
autoDeleteReference
;
...
...
@@ -78,7 +79,7 @@ public class FileStore {
}
else
{
FileUtils
.
createDirectories
(
FileUtils
.
getParent
(
name
));
}
file
=
FileUtils
.
open
FileObject
(
name
,
mode
);
file
=
FileUtils
.
open
(
name
,
mode
);
if
(
exists
)
{
fileLength
=
file
.
size
();
}
...
...
@@ -272,7 +273,7 @@ public class FileStore {
}
checkPowerOff
();
try
{
file
.
readFully
(
b
,
off
,
len
);
FileUtils
.
readFully
(
file
,
ByteBuffer
.
wrap
(
b
,
off
,
len
)
);
}
catch
(
IOException
e
)
{
throw
DbException
.
convertIOException
(
e
,
name
);
}
...
...
@@ -323,11 +324,11 @@ public class FileStore {
checkWritingAllowed
();
checkPowerOff
();
try
{
file
.
write
(
b
,
off
,
len
);
FileUtils
.
writeFully
(
file
,
ByteBuffer
.
wrap
(
b
,
off
,
len
)
);
}
catch
(
IOException
e
)
{
if
(
freeUpDiskSpace
())
{
try
{
file
.
write
(
b
,
off
,
len
);
FileUtils
.
writeFully
(
file
,
ByteBuffer
.
wrap
(
b
,
off
,
len
)
);
}
catch
(
IOException
e2
)
{
throw
DbException
.
convertIOException
(
e2
,
name
);
}
...
...
@@ -362,7 +363,7 @@ public class FileStore {
if
(
newLength
>
fileLength
)
{
long
pos
=
filePos
;
file
.
position
(
newLength
-
1
);
file
.
write
(
new
byte
[
1
],
0
,
1
);
FileUtils
.
writeFully
(
file
,
ByteBuffer
.
wrap
(
new
byte
[
1
])
);
file
.
position
(
pos
);
}
else
{
file
.
truncate
(
newLength
);
...
...
@@ -468,7 +469,7 @@ public class FileStore {
*/
public
void
openFile
()
throws
IOException
{
if
(
file
==
null
)
{
file
=
FileUtils
.
open
FileObject
(
name
,
mode
);
file
=
FileUtils
.
open
(
name
,
mode
);
file
.
position
(
filePos
);
}
}
...
...
h2/src/main/org/h2/store/fs/FileBase.java
0 → 100644
浏览文件 @
b6ad6d6a
package
org
.
h2
.
store
.
fs
;
import
java.io.IOException
;
import
java.nio.ByteBuffer
;
import
java.nio.MappedByteBuffer
;
import
java.nio.channels.FileChannel
;
import
java.nio.channels.FileLock
;
import
java.nio.channels.ReadableByteChannel
;
import
java.nio.channels.WritableByteChannel
;
/**
* The base class for file implementations.
*/
public
abstract
class
FileBase
extends
FileChannel
{
public
void
force
(
boolean
metaData
)
throws
IOException
{
// ignore
}
public
FileLock
lock
(
long
position
,
long
size
,
boolean
shared
)
throws
IOException
{
throw
new
UnsupportedOperationException
();
}
public
MappedByteBuffer
map
(
MapMode
mode
,
long
position
,
long
size
)
throws
IOException
{
throw
new
UnsupportedOperationException
();
}
public
abstract
long
position
()
throws
IOException
;
public
abstract
FileChannel
position
(
long
newPosition
)
throws
IOException
;
public
abstract
int
read
(
ByteBuffer
dst
)
throws
IOException
;
public
int
read
(
ByteBuffer
dst
,
long
position
)
throws
IOException
{
throw
new
UnsupportedOperationException
();
}
public
long
read
(
ByteBuffer
[]
dsts
,
int
offset
,
int
length
)
throws
IOException
{
throw
new
UnsupportedOperationException
();
}
public
abstract
long
size
()
throws
IOException
;
public
long
transferFrom
(
ReadableByteChannel
src
,
long
position
,
long
count
)
throws
IOException
{
throw
new
UnsupportedOperationException
();
}
public
long
transferTo
(
long
position
,
long
count
,
WritableByteChannel
target
)
throws
IOException
{
throw
new
UnsupportedOperationException
();
}
public
abstract
FileChannel
truncate
(
long
size
)
throws
IOException
;
public
FileLock
tryLock
(
long
position
,
long
size
,
boolean
shared
)
throws
IOException
{
throw
new
UnsupportedOperationException
();
}
public
abstract
int
write
(
ByteBuffer
src
)
throws
IOException
;
public
int
write
(
ByteBuffer
src
,
long
position
)
throws
IOException
{
throw
new
UnsupportedOperationException
();
}
public
long
write
(
ByteBuffer
[]
srcs
,
int
offset
,
int
length
)
throws
IOException
{
throw
new
UnsupportedOperationException
();
}
protected
void
implCloseChannel
()
throws
IOException
{
// ignore
}
}
h2/src/main/org/h2/store/fs/File
Object
InputStream.java
→
h2/src/main/org/h2/store/fs/File
Channel
InputStream.java
浏览文件 @
b6ad6d6a
...
...
@@ -8,29 +8,31 @@ package org.h2.store.fs;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.nio.ByteBuffer
;
import
java.nio.channels.FileChannel
;
/**
* Allows to read from a file
object
like an input stream.
* Allows to read from a file
channel
like an input stream.
*/
public
class
File
Object
InputStream
extends
InputStream
{
public
class
File
Channel
InputStream
extends
InputStream
{
private
File
Object
file
;
private
File
Channel
channel
;
private
byte
[]
buffer
=
{
0
};
/**
* Create a new file object input stream from the file
object
.
* Create a new file object input stream from the file
channel
.
*
* @param
file the file object
* @param
channel the file channel
*/
public
File
ObjectInputStream
(
FileObject
file
)
{
this
.
file
=
file
;
public
File
ChannelInputStream
(
FileChannel
channel
)
{
this
.
channel
=
channel
;
}
public
int
read
()
throws
IOException
{
if
(
file
.
position
()
>=
file
.
size
())
{
if
(
channel
.
position
()
>=
channel
.
size
())
{
return
-
1
;
}
file
.
readFully
(
buffer
,
0
,
1
);
FileUtils
.
readFully
(
channel
,
ByteBuffer
.
wrap
(
buffer
)
);
return
buffer
[
0
]
&
0xff
;
}
...
...
@@ -39,15 +41,15 @@ public class FileObjectInputStream extends InputStream {
}
public
int
read
(
byte
[]
b
,
int
off
,
int
len
)
throws
IOException
{
if
(
file
.
position
()
+
len
<
file
.
size
())
{
file
.
readFully
(
b
,
off
,
len
);
if
(
channel
.
position
()
+
len
<
channel
.
size
())
{
FileUtils
.
readFully
(
channel
,
ByteBuffer
.
wrap
(
b
,
off
,
len
)
);
return
len
;
}
return
super
.
read
(
b
,
off
,
len
);
}
public
void
close
()
throws
IOException
{
file
.
close
();
channel
.
close
();
}
}
h2/src/main/org/h2/store/fs/File
Object
OutputStream.java
→
h2/src/main/org/h2/store/fs/File
Channel
OutputStream.java
浏览文件 @
b6ad6d6a
...
...
@@ -8,46 +8,48 @@ package org.h2.store.fs;
import
java.io.IOException
;
import
java.io.OutputStream
;
import
java.nio.ByteBuffer
;
import
java.nio.channels.FileChannel
;
/**
* Allows to write to a file
object
like an output stream.
* Allows to write to a file
channel
like an output stream.
*/
public
class
File
Object
OutputStream
extends
OutputStream
{
public
class
File
Channel
OutputStream
extends
OutputStream
{
private
File
Object
file
;
private
File
Channel
channel
;
private
byte
[]
buffer
=
{
0
};
/**
* Create a new file object output stream from the file
object
.
* Create a new file object output stream from the file
channel
.
*
* @param
file the file object
* @param
channel the file channel
* @param append true for append mode, false for truncate and overwrite
*/
public
File
ObjectOutputStream
(
FileObject
file
,
boolean
append
)
throws
IOException
{
this
.
file
=
file
;
public
File
ChannelOutputStream
(
FileChannel
channel
,
boolean
append
)
throws
IOException
{
this
.
channel
=
channel
;
if
(
append
)
{
file
.
position
(
file
.
size
());
channel
.
position
(
channel
.
size
());
}
else
{
file
.
position
(
0
);
file
.
truncate
(
0
);
channel
.
position
(
0
);
channel
.
truncate
(
0
);
}
}
public
void
write
(
int
b
)
throws
IOException
{
buffer
[
0
]
=
(
byte
)
b
;
file
.
write
(
buffer
,
0
,
1
);
FileUtils
.
writeFully
(
channel
,
ByteBuffer
.
wrap
(
buffer
)
);
}
public
void
write
(
byte
[]
b
)
throws
IOException
{
file
.
write
(
b
,
0
,
b
.
length
);
FileUtils
.
writeFully
(
channel
,
ByteBuffer
.
wrap
(
b
)
);
}
public
void
write
(
byte
[]
b
,
int
off
,
int
len
)
throws
IOException
{
file
.
write
(
b
,
off
,
len
);
FileUtils
.
writeFully
(
channel
,
ByteBuffer
.
wrap
(
b
,
off
,
len
)
);
}
public
void
close
()
throws
IOException
{
file
.
close
();
channel
.
close
();
}
}
h2/src/main/org/h2/store/fs/FileObject.java
deleted
100644 → 0
浏览文件 @
fa398730
/*
* Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License,
* Version 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package
org
.
h2
.
store
.
fs
;
import
java.io.IOException
;
import
java.nio.channels.FileLock
;
/**
* This interface represents a random access file.
*/
public
interface
FileObject
{
/**
* Get the length of the file.
*
* @return the length
*/
long
size
()
throws
IOException
;
/**
* Close the file.
*/
void
close
()
throws
IOException
;
/**
* Read from the file.
* @param b the byte array
* @param off the offset
* @param len the number of bytes
*/
void
readFully
(
byte
[]
b
,
int
off
,
int
len
)
throws
IOException
;
/**
* Go to the specified position in the file.
*
* @param pos the new position
*/
void
position
(
long
pos
)
throws
IOException
;
/**
* Write to the file.
*
* @param b the byte array
* @param off the offset
* @param len the number of bytes
*/
void
write
(
byte
[]
b
,
int
off
,
int
len
)
throws
IOException
;
/**
* Get the file pointer.
*
* @return the current file pointer
*/
long
position
()
throws
IOException
;
/**
* Force changes to the physical location (sync).
*
* @param metaData whether the file metadata should be written as well
*/
void
force
(
boolean
metaData
)
throws
IOException
;
/**
* Change the length of the file.
*
* @param newLength the new length
*/
void
truncate
(
long
newLength
)
throws
IOException
;
/**
* Try to lock the file exclusively.
*
* @return a lock object if successful, or null if not
*/
FileLock
tryLock
()
throws
IOException
;
}
h2/src/main/org/h2/store/fs/FileObjectDisk.java
deleted
100644 → 0
浏览文件 @
fa398730
/*
* Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License,
* Version 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package
org
.
h2
.
store
.
fs
;
import
java.io.FileNotFoundException
;
import
java.io.IOException
;
import
java.io.RandomAccessFile
;
import
java.nio.channels.FileLock
;
import
org.h2.constant.SysProperties
;
/**
* This class extends a java.io.RandomAccessFile.
*/
public
class
FileObjectDisk
implements
FileObject
{
private
final
RandomAccessFile
file
;
private
final
String
name
;
FileObjectDisk
(
String
fileName
,
String
mode
)
throws
FileNotFoundException
{
this
.
file
=
new
RandomAccessFile
(
fileName
,
mode
);
this
.
name
=
fileName
;
}
public
void
force
(
boolean
metaData
)
throws
IOException
{
String
m
=
SysProperties
.
SYNC_METHOD
;
if
(
""
.
equals
(
m
))
{
// do nothing
}
else
if
(
"sync"
.
equals
(
m
))
{
file
.
getFD
().
sync
();
}
else
if
(
"force"
.
equals
(
m
))
{
file
.
getChannel
().
force
(
true
);
}
else
if
(
"forceFalse"
.
equals
(
m
))
{
file
.
getChannel
().
force
(
false
);
}
else
{
file
.
getFD
().
sync
();
}
}
public
void
truncate
(
long
newLength
)
throws
IOException
{
if
(
newLength
<
file
.
length
())
{
// some implementations actually only support truncate
file
.
setLength
(
newLength
);
}
}
public
synchronized
FileLock
tryLock
()
throws
IOException
{
return
file
.
getChannel
().
tryLock
();
}
public
void
close
()
throws
IOException
{
file
.
close
();
}
public
long
position
()
throws
IOException
{
return
file
.
getFilePointer
();
}
public
long
size
()
throws
IOException
{
return
file
.
length
();
}
public
void
readFully
(
byte
[]
b
,
int
off
,
int
len
)
throws
IOException
{
file
.
readFully
(
b
,
off
,
len
);
}
public
void
position
(
long
pos
)
throws
IOException
{
file
.
seek
(
pos
);
}
public
void
write
(
byte
[]
b
,
int
off
,
int
len
)
throws
IOException
{
file
.
write
(
b
,
off
,
len
);
}
public
String
toString
()
{
return
name
;
}
}
h2/src/main/org/h2/store/fs/FileObjectMem.java
deleted
100644 → 0
浏览文件 @
fa398730
/*
* Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License,
* Version 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package
org
.
h2
.
store
.
fs
;
import
java.io.IOException
;
import
java.nio.channels.FileLock
;
/**
* This class represents an in-memory file.
*/
public
class
FileObjectMem
implements
FileObject
{
private
final
FileObjectMemData
data
;
private
final
boolean
readOnly
;
private
long
pos
;
FileObjectMem
(
FileObjectMemData
data
,
boolean
readOnly
)
{
this
.
data
=
data
;
this
.
readOnly
=
readOnly
;
}
public
long
size
()
{
return
data
.
length
();
}
public
void
truncate
(
long
newLength
)
throws
IOException
{
if
(
newLength
>=
size
())
{
return
;
}
data
.
touch
(
readOnly
);
pos
=
Math
.
min
(
pos
,
newLength
);
data
.
truncate
(
newLength
);
}
public
void
position
(
long
newPos
)
{
this
.
pos
=
(
int
)
newPos
;
}
public
void
write
(
byte
[]
b
,
int
off
,
int
len
)
throws
IOException
{
data
.
touch
(
readOnly
);
pos
=
data
.
readWrite
(
pos
,
b
,
off
,
len
,
true
);
}
public
void
readFully
(
byte
[]
b
,
int
off
,
int
len
)
throws
IOException
{
pos
=
data
.
readWrite
(
pos
,
b
,
off
,
len
,
false
);
}
public
long
position
()
{
return
pos
;
}
public
void
close
()
{
pos
=
0
;
}
public
void
force
(
boolean
metaData
)
throws
IOException
{
// do nothing
}
public
FileLock
tryLock
()
{
return
null
;
}
}
h2/src/main/org/h2/store/fs/FileObjectMemData.java
deleted
100644 → 0
浏览文件 @
fa398730
/*
* Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License,
* Version 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package
org
.
h2
.
store
.
fs
;
import
java.io.EOFException
;
import
java.io.IOException
;
import
java.util.LinkedHashMap
;
import
java.util.Map
;
import
org.h2.compress.CompressLZF
;
import
org.h2.util.MathUtils
;
/**
* This class contains the data of an in-memory random access file.
* Data compression using the LZF algorithm is supported as well.
*/
class
FileObjectMemData
{
private
static
final
int
CACHE_SIZE
=
8
;
private
static
final
int
BLOCK_SIZE_SHIFT
=
10
;
private
static
final
int
BLOCK_SIZE
=
1
<<
BLOCK_SIZE_SHIFT
;
private
static
final
int
BLOCK_SIZE_MASK
=
BLOCK_SIZE
-
1
;
private
static
final
CompressLZF
LZF
=
new
CompressLZF
();
private
static
final
byte
[]
BUFFER
=
new
byte
[
BLOCK_SIZE
*
2
];
private
static
final
byte
[]
COMPRESSED_EMPTY_BLOCK
;
private
static
final
Cache
<
CompressItem
,
CompressItem
>
COMPRESS_LATER
=
new
Cache
<
CompressItem
,
CompressItem
>(
CACHE_SIZE
);
private
String
name
;
private
final
boolean
compress
;
private
long
length
;
private
byte
[][]
data
;
private
long
lastModified
;
private
boolean
isReadOnly
;
private
volatile
boolean
locked
;
static
{
byte
[]
n
=
new
byte
[
BLOCK_SIZE
];
int
len
=
LZF
.
compress
(
n
,
BLOCK_SIZE
,
BUFFER
,
0
);
COMPRESSED_EMPTY_BLOCK
=
new
byte
[
len
];
System
.
arraycopy
(
BUFFER
,
0
,
COMPRESSED_EMPTY_BLOCK
,
0
,
len
);
}
/**
* This small cache compresses the data if an element leaves the cache.
*/
static
class
Cache
<
K
,
V
>
extends
LinkedHashMap
<
K
,
V
>
{
private
static
final
long
serialVersionUID
=
1L
;
private
int
size
;
Cache
(
int
size
)
{
super
(
size
,
(
float
)
0.75
,
true
);
this
.
size
=
size
;
}
protected
boolean
removeEldestEntry
(
Map
.
Entry
<
K
,
V
>
eldest
)
{
if
(
size
()
<
size
)
{
return
false
;
}
CompressItem
c
=
(
CompressItem
)
eldest
.
getKey
();
compress
(
c
.
data
,
c
.
page
);
return
true
;
}
}
/**
* Represents a compressed item.
*/
static
class
CompressItem
{
/**
* The file data.
*/
byte
[][]
data
;
/**
* The page to compress.
*/
int
page
;
public
int
hashCode
()
{
return
page
;
}
public
boolean
equals
(
Object
o
)
{
if
(
o
instanceof
CompressItem
)
{
CompressItem
c
=
(
CompressItem
)
o
;
return
c
.
data
==
data
&&
c
.
page
==
page
;
}
return
false
;
}
}
FileObjectMemData
(
String
name
,
boolean
compress
)
{
this
.
name
=
name
;
this
.
compress
=
compress
;
data
=
new
byte
[
0
][];
lastModified
=
System
.
currentTimeMillis
();
}
private
static
void
compressLater
(
byte
[][]
data
,
int
page
)
{
CompressItem
c
=
new
CompressItem
();
c
.
data
=
data
;
c
.
page
=
page
;
synchronized
(
LZF
)
{
COMPRESS_LATER
.
put
(
c
,
c
);
}
}
private
static
void
expand
(
byte
[][]
data
,
int
page
)
{
byte
[]
d
=
data
[
page
];
if
(
d
.
length
==
BLOCK_SIZE
)
{
return
;
}
byte
[]
out
=
new
byte
[
BLOCK_SIZE
];
if
(
d
!=
COMPRESSED_EMPTY_BLOCK
)
{
synchronized
(
LZF
)
{
LZF
.
expand
(
d
,
0
,
d
.
length
,
out
,
0
,
BLOCK_SIZE
);
}
}
data
[
page
]
=
out
;
}
/**
* Compress the data in a byte array.
*
* @param data the page array
* @param page which page to compress
*/
static
void
compress
(
byte
[][]
data
,
int
page
)
{
byte
[]
d
=
data
[
page
];
synchronized
(
LZF
)
{
int
len
=
LZF
.
compress
(
d
,
BLOCK_SIZE
,
BUFFER
,
0
);
if
(
len
<=
BLOCK_SIZE
)
{
d
=
new
byte
[
len
];
System
.
arraycopy
(
BUFFER
,
0
,
d
,
0
,
len
);
data
[
page
]
=
d
;
}
}
}
/**
* Update the last modified time.
*
* @param openReadOnly if the file was opened in read-only mode
*/
void
touch
(
boolean
openReadOnly
)
throws
IOException
{
if
(
isReadOnly
||
openReadOnly
)
{
throw
new
IOException
(
"Read only"
);
}
lastModified
=
System
.
currentTimeMillis
();
}
/**
* Get the file length.
*
* @return the length
*/
long
length
()
{
return
length
;
}
/**
* Truncate the file.
*
* @param newLength the new length
*/
void
truncate
(
long
newLength
)
{
changeLength
(
newLength
);
long
end
=
MathUtils
.
roundUpLong
(
newLength
,
BLOCK_SIZE
);
if
(
end
!=
newLength
)
{
int
lastPage
=
(
int
)
(
newLength
>>>
BLOCK_SIZE_SHIFT
);
expand
(
data
,
lastPage
);
byte
[]
d
=
data
[
lastPage
];
for
(
int
i
=
(
int
)
(
newLength
&
BLOCK_SIZE_MASK
);
i
<
BLOCK_SIZE
;
i
++)
{
d
[
i
]
=
0
;
}
if
(
compress
)
{
compressLater
(
data
,
lastPage
);
}
}
}
private
void
changeLength
(
long
len
)
{
length
=
len
;
len
=
MathUtils
.
roundUpLong
(
len
,
BLOCK_SIZE
);
int
blocks
=
(
int
)
(
len
>>>
BLOCK_SIZE_SHIFT
);
if
(
blocks
!=
data
.
length
)
{
byte
[][]
n
=
new
byte
[
blocks
][];
System
.
arraycopy
(
data
,
0
,
n
,
0
,
Math
.
min
(
data
.
length
,
n
.
length
));
for
(
int
i
=
data
.
length
;
i
<
blocks
;
i
++)
{
n
[
i
]
=
COMPRESSED_EMPTY_BLOCK
;
}
data
=
n
;
}
}
/**
* Read or write.
*
* @param pos the position
* @param b the byte array
* @param off the offset within the byte array
* @param len the number of bytes
* @param write true for writing
* @return the new position
*/
long
readWrite
(
long
pos
,
byte
[]
b
,
int
off
,
int
len
,
boolean
write
)
throws
IOException
{
long
end
=
pos
+
len
;
if
(
end
>
length
)
{
if
(
write
)
{
changeLength
(
end
);
}
else
{
if
(
len
==
0
)
{
return
pos
;
}
throw
new
EOFException
(
"File: "
+
name
);
}
}
while
(
len
>
0
)
{
int
l
=
(
int
)
Math
.
min
(
len
,
BLOCK_SIZE
-
(
pos
&
BLOCK_SIZE_MASK
));
int
page
=
(
int
)
(
pos
>>>
BLOCK_SIZE_SHIFT
);
expand
(
data
,
page
);
byte
[]
block
=
data
[
page
];
int
blockOffset
=
(
int
)
(
pos
&
BLOCK_SIZE_MASK
);
if
(
write
)
{
System
.
arraycopy
(
b
,
off
,
block
,
blockOffset
,
l
);
}
else
{
System
.
arraycopy
(
block
,
blockOffset
,
b
,
off
,
l
);
}
if
(
compress
)
{
compressLater
(
data
,
page
);
}
off
+=
l
;
pos
+=
l
;
len
-=
l
;
}
return
pos
;
}
/**
* Set the file name.
*
* @param name the name
*/
void
setName
(
String
name
)
{
this
.
name
=
name
;
}
/**
* Get the file name
*
* @return the name
*/
String
getName
()
{
return
name
;
}
/**
* Get the last modified time.
*
* @return the time
*/
long
getLastModified
()
{
return
lastModified
;
}
/**
* Check whether writing is allowed.
*
* @return true if it is
*/
boolean
canWrite
()
{
return
!
isReadOnly
;
}
/**
* Set the read-only flag.
*
* @return true
*/
boolean
setReadOnly
()
{
isReadOnly
=
true
;
return
true
;
}
/**
* Lock the file.
*
* @return if successful
*/
synchronized
boolean
tryLock
()
{
if
(
locked
)
{
return
false
;
}
locked
=
true
;
return
true
;
}
/**
* Unlock the file.
*/
public
synchronized
void
releaseLock
()
{
locked
=
false
;
}
}
h2/src/main/org/h2/store/fs/FileObjectNio.java
deleted
100644 → 0
浏览文件 @
fa398730
/*
* Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License,
* Version 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: Jan Kotek
*/
package
org
.
h2
.
store
.
fs
;
import
java.io.EOFException
;
import
java.io.IOException
;
import
java.io.RandomAccessFile
;
import
java.nio.ByteBuffer
;
import
java.nio.channels.FileChannel
;
import
java.nio.channels.FileLock
;
import
java.nio.channels.NonWritableChannelException
;
/**
* File which uses NIO FileChannel.
*/
public
class
FileObjectNio
implements
FileObject
{
private
final
String
name
;
private
final
RandomAccessFile
file
;
private
final
FileChannel
channel
;
private
long
length
;
FileObjectNio
(
String
fileName
,
String
mode
)
throws
IOException
{
this
.
name
=
fileName
;
file
=
new
RandomAccessFile
(
fileName
,
mode
);
channel
=
file
.
getChannel
();
length
=
file
.
length
();
}
public
void
close
()
throws
IOException
{
channel
.
close
();
file
.
close
();
}
public
long
position
()
throws
IOException
{
return
channel
.
position
();
}
public
long
size
()
throws
IOException
{
return
channel
.
size
();
}
public
void
readFully
(
byte
[]
b
,
int
off
,
int
len
)
throws
IOException
{
if
(
len
==
0
)
{
return
;
}
if
(
channel
.
position
()
+
len
>
length
)
{
throw
new
EOFException
();
}
ByteBuffer
buf
=
ByteBuffer
.
wrap
(
b
);
buf
.
position
(
off
);
buf
.
limit
(
off
+
len
);
channel
.
read
(
buf
);
}
public
void
position
(
long
pos
)
throws
IOException
{
channel
.
position
(
pos
);
}
public
void
truncate
(
long
newLength
)
throws
IOException
{
if
(
newLength
>=
channel
.
size
())
{
return
;
}
long
pos
=
channel
.
position
();
try
{
channel
.
truncate
(
newLength
);
}
catch
(
NonWritableChannelException
e
)
{
throw
new
IOException
(
"read only"
);
}
if
(
pos
>
newLength
)
{
pos
=
newLength
;
}
channel
.
position
(
pos
);
length
=
newLength
;
}
public
void
force
(
boolean
metaData
)
throws
IOException
{
channel
.
force
(
metaData
);
}
public
void
write
(
byte
[]
b
,
int
off
,
int
len
)
throws
IOException
{
ByteBuffer
buf
=
ByteBuffer
.
wrap
(
b
);
buf
.
position
(
off
);
buf
.
limit
(
off
+
len
);
try
{
channel
.
write
(
buf
);
}
catch
(
NonWritableChannelException
e
)
{
throw
new
IOException
(
"read only"
);
}
}
public
synchronized
FileLock
tryLock
()
throws
IOException
{
return
channel
.
tryLock
();
}
public
String
toString
()
{
return
name
;
}
}
h2/src/main/org/h2/store/fs/FileObjectNioMapped.java
deleted
100644 → 0
浏览文件 @
fa398730
/*
* Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License,
* Version 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: Jan Kotek
*/
package
org
.
h2
.
store
.
fs
;
import
java.io.EOFException
;
import
java.io.IOException
;
import
java.io.RandomAccessFile
;
import
java.lang.ref.WeakReference
;
import
java.lang.reflect.Method
;
import
java.nio.BufferUnderflowException
;
import
java.nio.MappedByteBuffer
;
import
java.nio.channels.FileLock
;
import
java.nio.channels.FileChannel.MapMode
;
import
org.h2.constant.SysProperties
;
/**
* FileObject which is using NIO MappedByteBuffer mapped to memory from file.
* The file size is limited to 2 GB.
*/
public
class
FileObjectNioMapped
implements
FileObject
{
private
static
final
long
GC_TIMEOUT_MS
=
10000
;
private
final
String
name
;
private
final
MapMode
mode
;
private
RandomAccessFile
file
;
private
MappedByteBuffer
mapped
;
/**
* The position within the file. Can't use the position of the mapped buffer
* because it doesn't support seeking past the end of the file.
*/
private
int
pos
;
FileObjectNioMapped
(
String
fileName
,
String
mode
)
throws
IOException
{
if
(
"r"
.
equals
(
mode
))
{
this
.
mode
=
MapMode
.
READ_ONLY
;
}
else
{
this
.
mode
=
MapMode
.
READ_WRITE
;
}
this
.
name
=
fileName
;
file
=
new
RandomAccessFile
(
fileName
,
mode
);
reMap
();
}
private
void
unMap
()
throws
IOException
{
if
(
mapped
==
null
)
{
return
;
}
// first write all data
mapped
.
force
();
// need to dispose old direct buffer, see bug
// http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4724038
boolean
useSystemGc
=
true
;
if
(
SysProperties
.
NIO_CLEANER_HACK
)
{
try
{
Method
cleanerMethod
=
mapped
.
getClass
().
getMethod
(
"cleaner"
);
cleanerMethod
.
setAccessible
(
true
);
Object
cleaner
=
cleanerMethod
.
invoke
(
mapped
);
if
(
cleaner
!=
null
)
{
Method
clearMethod
=
cleaner
.
getClass
().
getMethod
(
"clean"
);
clearMethod
.
invoke
(
cleaner
);
}
useSystemGc
=
false
;
}
catch
(
Throwable
e
)
{
// useSystemGc is already true
}
finally
{
mapped
=
null
;
}
}
if
(
useSystemGc
)
{
WeakReference
<
MappedByteBuffer
>
bufferWeakRef
=
new
WeakReference
<
MappedByteBuffer
>(
mapped
);
mapped
=
null
;
long
start
=
System
.
currentTimeMillis
();
while
(
bufferWeakRef
.
get
()
!=
null
)
{
if
(
System
.
currentTimeMillis
()
-
start
>
GC_TIMEOUT_MS
)
{
throw
new
IOException
(
"Timeout ("
+
GC_TIMEOUT_MS
+
" ms) reached while trying to GC mapped buffer"
);
}
System
.
gc
();
Thread
.
yield
();
}
}
}
/**
* Re-map byte buffer into memory, called when file size has changed or file
* was created.
*/
private
void
reMap
()
throws
IOException
{
int
oldPos
=
0
;
if
(
mapped
!=
null
)
{
oldPos
=
pos
;
unMap
();
}
long
length
=
file
.
length
();
checkFileSizeLimit
(
length
);
// maps new MappedByteBuffer; the old one is disposed during GC
mapped
=
file
.
getChannel
().
map
(
mode
,
0
,
length
);
int
limit
=
mapped
.
limit
();
int
capacity
=
mapped
.
capacity
();
if
(
limit
<
length
||
capacity
<
length
)
{
throw
new
IOException
(
"Unable to map: length="
+
limit
+
" capacity="
+
capacity
+
" length="
+
length
);
}
if
(
SysProperties
.
NIO_LOAD_MAPPED
)
{
mapped
.
load
();
}
this
.
pos
=
Math
.
min
(
oldPos
,
(
int
)
length
);
}
private
static
void
checkFileSizeLimit
(
long
length
)
throws
IOException
{
if
(
length
>
Integer
.
MAX_VALUE
)
{
throw
new
IOException
(
"File over 2GB is not supported yet when using this file system"
);
}
}
public
synchronized
void
close
()
throws
IOException
{
if
(
file
!=
null
)
{
unMap
();
file
.
close
();
file
=
null
;
}
}
public
long
position
()
{
return
pos
;
}
public
String
toString
()
{
return
"nioMapped:"
+
name
;
}
public
synchronized
long
size
()
throws
IOException
{
return
file
.
length
();
}
public
synchronized
void
readFully
(
byte
[]
b
,
int
off
,
int
len
)
throws
EOFException
{
try
{
mapped
.
position
(
pos
);
mapped
.
get
(
b
,
off
,
len
);
pos
+=
len
;
}
catch
(
IllegalArgumentException
e
)
{
EOFException
e2
=
new
EOFException
(
"EOF"
);
e2
.
initCause
(
e
);
throw
e2
;
}
catch
(
BufferUnderflowException
e
)
{
EOFException
e2
=
new
EOFException
(
"EOF"
);
e2
.
initCause
(
e
);
throw
e2
;
}
}
public
void
position
(
long
pos
)
throws
IOException
{
checkFileSizeLimit
(
pos
);
this
.
pos
=
(
int
)
pos
;
}
public
synchronized
void
truncate
(
long
newLength
)
throws
IOException
{
if
(
newLength
>=
size
())
{
return
;
}
setFileLength
(
newLength
);
}
public
synchronized
void
setFileLength
(
long
newLength
)
throws
IOException
{
checkFileSizeLimit
(
newLength
);
int
oldPos
=
pos
;
unMap
();
for
(
int
i
=
0
;;
i
++)
{
try
{
file
.
setLength
(
newLength
);
break
;
}
catch
(
IOException
e
)
{
if
(
i
>
16
||
e
.
toString
().
indexOf
(
"user-mapped section open"
)
<
0
)
{
throw
e
;
}
}
System
.
gc
();
}
reMap
();
pos
=
(
int
)
Math
.
min
(
newLength
,
oldPos
);
}
public
void
force
(
boolean
metaData
)
throws
IOException
{
mapped
.
force
();
file
.
getFD
().
sync
();
}
public
synchronized
void
write
(
byte
[]
b
,
int
off
,
int
len
)
throws
IOException
{
// check if need to expand file
if
(
mapped
.
capacity
()
<
pos
+
len
)
{
setFileLength
(
pos
+
len
);
}
mapped
.
position
(
pos
);
mapped
.
put
(
b
,
off
,
len
);
pos
+=
len
;
}
public
synchronized
FileLock
tryLock
()
throws
IOException
{
return
file
.
getChannel
().
tryLock
();
}
}
h2/src/main/org/h2/store/fs/FileObjectRec.java
deleted
100644 → 0
浏览文件 @
fa398730
/*
* Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License,
* Version 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package
org
.
h2
.
store
.
fs
;
import
java.io.IOException
;
import
java.nio.channels.FileLock
;
/**
* A file object that records all write operations and can re-play them.
*/
public
class
FileObjectRec
implements
FileObject
{
private
final
FilePathRec
fs
;
private
final
FileObject
file
;
private
final
String
name
;
FileObjectRec
(
FilePathRec
fs
,
FileObject
file
,
String
fileName
)
{
this
.
fs
=
fs
;
this
.
file
=
file
;
this
.
name
=
fileName
;
}
public
void
close
()
throws
IOException
{
file
.
close
();
}
public
long
position
()
throws
IOException
{
return
file
.
position
();
}
public
long
size
()
throws
IOException
{
return
file
.
size
();
}
public
void
readFully
(
byte
[]
b
,
int
off
,
int
len
)
throws
IOException
{
file
.
readFully
(
b
,
off
,
len
);
}
public
void
position
(
long
pos
)
throws
IOException
{
file
.
position
(
pos
);
}
public
void
truncate
(
long
newLength
)
throws
IOException
{
fs
.
log
(
Recorder
.
TRUNCATE
,
name
,
null
,
newLength
);
file
.
truncate
(
newLength
);
}
public
void
force
(
boolean
metaData
)
throws
IOException
{
file
.
force
(
metaData
);
}
public
void
write
(
byte
[]
b
,
int
off
,
int
len
)
throws
IOException
{
byte
[]
buff
=
b
;
if
(
off
!=
0
||
len
!=
b
.
length
)
{
buff
=
new
byte
[
len
];
System
.
arraycopy
(
b
,
off
,
buff
,
0
,
len
);
}
file
.
write
(
b
,
off
,
len
);
fs
.
log
(
Recorder
.
WRITE
,
name
,
buff
,
file
.
position
());
}
public
FileLock
tryLock
()
throws
IOException
{
return
file
.
tryLock
();
}
}
\ No newline at end of file
h2/src/main/org/h2/store/fs/FileObjectSplit.java
deleted
100644 → 0
浏览文件 @
fa398730
/*
* Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License,
* Version 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package
org
.
h2
.
store
.
fs
;
import
java.io.EOFException
;
import
java.io.IOException
;
import
java.nio.channels.FileLock
;
import
org.h2.message.DbException
;
/**
* A file that may be split into multiple smaller files.
*/
public
class
FileObjectSplit
implements
FileObject
{
private
final
FilePathSplit
file
;
private
final
String
mode
;
private
final
long
maxLength
;
private
FileObject
[]
list
;
private
long
filePointer
;
private
long
length
;
FileObjectSplit
(
FilePathSplit
file
,
String
mode
,
FileObject
[]
list
,
long
length
,
long
maxLength
)
{
this
.
file
=
file
;
this
.
mode
=
mode
;
this
.
list
=
list
;
this
.
length
=
length
;
this
.
maxLength
=
maxLength
;
}
public
void
close
()
throws
IOException
{
for
(
FileObject
f
:
list
)
{
f
.
close
();
}
}
public
long
position
()
{
return
filePointer
;
}
public
long
size
()
{
return
length
;
}
private
int
read
(
byte
[]
b
,
int
off
,
int
len
)
throws
IOException
{
long
offset
=
filePointer
%
maxLength
;
int
l
=
(
int
)
Math
.
min
(
len
,
maxLength
-
offset
);
FileObject
fo
=
getFileObject
();
fo
.
position
(
offset
);
fo
.
readFully
(
b
,
off
,
l
);
filePointer
+=
l
;
return
l
;
}
public
void
readFully
(
byte
[]
b
,
int
off
,
int
len
)
throws
IOException
{
if
(
filePointer
+
len
>
length
)
{
throw
new
EOFException
();
}
while
(
true
)
{
int
l
=
read
(
b
,
off
,
len
);
len
-=
l
;
if
(
len
<=
0
)
{
return
;
}
off
+=
l
;
}
}
public
void
position
(
long
pos
)
{
filePointer
=
pos
;
}
private
FileObject
getFileObject
()
throws
IOException
{
int
id
=
(
int
)
(
filePointer
/
maxLength
);
while
(
id
>=
list
.
length
)
{
int
i
=
list
.
length
;
FileObject
[]
newList
=
new
FileObject
[
i
+
1
];
System
.
arraycopy
(
list
,
0
,
newList
,
0
,
i
);
FilePath
f
=
file
.
getBase
(
i
);
newList
[
i
]
=
f
.
openFileObject
(
mode
);
list
=
newList
;
}
return
list
[
id
];
}
public
void
truncate
(
long
newLength
)
throws
IOException
{
if
(
newLength
>=
length
)
{
return
;
}
filePointer
=
Math
.
min
(
filePointer
,
newLength
);
int
newFileCount
=
1
+
(
int
)
(
newLength
/
maxLength
);
if
(
newFileCount
<
list
.
length
)
{
// delete some of the files
FileObject
[]
newList
=
new
FileObject
[
newFileCount
];
// delete backwards, so that truncating is somewhat transactional
for
(
int
i
=
list
.
length
-
1
;
i
>=
newFileCount
;
i
--)
{
// verify the file is writable
list
[
i
].
truncate
(
0
);
list
[
i
].
close
();
try
{
file
.
getBase
(
i
).
delete
();
}
catch
(
DbException
e
)
{
throw
DbException
.
convertToIOException
(
e
);
}
}
System
.
arraycopy
(
list
,
0
,
newList
,
0
,
newList
.
length
);
list
=
newList
;
}
long
size
=
newLength
-
maxLength
*
(
newFileCount
-
1
);
list
[
list
.
length
-
1
].
truncate
(
size
);
this
.
length
=
newLength
;
}
public
void
force
(
boolean
metaData
)
throws
IOException
{
for
(
FileObject
f
:
list
)
{
f
.
force
(
metaData
);
}
}
public
void
write
(
byte
[]
b
,
int
off
,
int
len
)
throws
IOException
{
if
(
filePointer
>=
length
&&
filePointer
>
maxLength
)
{
// may need to extend and create files
long
oldFilePointer
=
filePointer
;
long
x
=
length
-
(
length
%
maxLength
)
+
maxLength
;
for
(;
x
<
filePointer
;
x
+=
maxLength
)
{
if
(
x
>
length
)
{
position
(
x
-
1
);
writePart
(
new
byte
[
1
],
0
,
1
);
}
filePointer
=
oldFilePointer
;
}
}
while
(
true
)
{
int
l
=
writePart
(
b
,
off
,
len
);
len
-=
l
;
if
(
len
<=
0
)
{
return
;
}
off
+=
l
;
}
}
private
int
writePart
(
byte
[]
b
,
int
off
,
int
len
)
throws
IOException
{
long
offset
=
filePointer
%
maxLength
;
int
l
=
(
int
)
Math
.
min
(
len
,
maxLength
-
offset
);
FileObject
fo
=
getFileObject
();
fo
.
position
(
offset
);
fo
.
write
(
b
,
off
,
l
);
filePointer
+=
l
;
length
=
Math
.
max
(
length
,
filePointer
);
return
l
;
}
public
FileLock
tryLock
()
throws
IOException
{
return
list
[
0
].
tryLock
();
}
}
h2/src/main/org/h2/store/fs/FileObjectZip.java
deleted
100644 → 0
浏览文件 @
fa398730
/*
* Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License,
* Version 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package
org
.
h2
.
store
.
fs
;
import
java.io.EOFException
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.nio.channels.FileLock
;
import
java.util.zip.ZipEntry
;
import
java.util.zip.ZipFile
;
import
org.h2.util.IOUtils
;
/**
* The file is read from a stream. When reading from start to end, the same
* input stream is re-used, however when reading from end to start, a new input
* stream is opened for each request.
*/
public
class
FileObjectZip
implements
FileObject
{
private
static
final
byte
[]
SKIP_BUFFER
=
new
byte
[
1024
];
private
ZipFile
file
;
private
ZipEntry
entry
;
private
long
pos
;
private
InputStream
in
;
private
long
inPos
;
private
long
length
;
private
boolean
skipUsingRead
;
FileObjectZip
(
ZipFile
file
,
ZipEntry
entry
)
{
this
.
file
=
file
;
this
.
entry
=
entry
;
length
=
entry
.
getSize
();
}
public
void
close
()
{
// nothing to do
}
public
long
position
()
{
return
pos
;
}
public
long
size
()
{
return
length
;
}
public
void
readFully
(
byte
[]
b
,
int
off
,
int
len
)
throws
IOException
{
if
(
inPos
>
pos
)
{
if
(
in
!=
null
)
{
in
.
close
();
}
in
=
null
;
}
if
(
in
==
null
)
{
in
=
file
.
getInputStream
(
entry
);
inPos
=
0
;
}
if
(
inPos
<
pos
)
{
long
skip
=
pos
-
inPos
;
if
(!
skipUsingRead
)
{
try
{
IOUtils
.
skipFully
(
in
,
skip
);
}
catch
(
NullPointerException
e
)
{
// workaround for Android
skipUsingRead
=
true
;
}
}
if
(
skipUsingRead
)
{
while
(
skip
>
0
)
{
int
s
=
(
int
)
Math
.
min
(
SKIP_BUFFER
.
length
,
skip
);
s
=
in
.
read
(
SKIP_BUFFER
,
0
,
s
);
skip
-=
s
;
}
}
inPos
=
pos
;
}
int
l
=
IOUtils
.
readFully
(
in
,
b
,
off
,
len
);
if
(
l
!=
len
)
{
throw
new
EOFException
();
}
pos
+=
len
;
inPos
+=
len
;
}
public
void
position
(
long
newPos
)
{
this
.
pos
=
newPos
;
}
public
void
truncate
(
long
newLength
)
throws
IOException
{
throw
new
IOException
(
"File is read-only"
);
}
public
void
force
(
boolean
metaData
)
throws
IOException
{
// nothing to do
}
public
void
write
(
byte
[]
b
,
int
off
,
int
len
)
throws
IOException
{
throw
new
IOException
(
"File is read-only"
);
}
public
FileLock
tryLock
()
{
return
null
;
}
}
h2/src/main/org/h2/store/fs/FilePath.java
浏览文件 @
b6ad6d6a
...
...
@@ -9,6 +9,7 @@ package org.h2.store.fs;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.io.OutputStream
;
import
java.nio.channels.FileChannel
;
import
java.util.Collections
;
import
java.util.List
;
import
java.util.Map
;
...
...
@@ -142,18 +143,18 @@ public abstract class FilePath {
public
abstract
void
delete
();
/**
* List the files in the given directory.
* List the files
and directories
in the given directory.
*
* @return the list of fully qualified file names
*/
public
abstract
List
<
FilePath
>
listFiles
();
public
abstract
List
<
FilePath
>
newDirectoryStream
();
/**
* Normalize a file name.
*
* @return the normalized file name
*/
public
abstract
FilePath
getCanonic
alPath
();
public
abstract
FilePath
toRe
alPath
();
/**
* Get the parent directory of a file or directory.
...
...
@@ -220,7 +221,7 @@ public abstract class FilePath {
* @param mode the access mode. Supported are r, rw, rws, rwd
* @return the file object
*/
public
abstract
File
Object
openFileObject
(
String
mode
)
throws
IOException
;
public
abstract
File
Channel
open
(
String
mode
)
throws
IOException
;
/**
* Create an input stream to read from the file.
...
...
@@ -253,7 +254,7 @@ public abstract class FilePath {
getNextTempFileNamePart
(
true
);
continue
;
}
p
.
open
FileObject
(
"rw"
).
close
();
p
.
open
(
"rw"
).
close
();
return
p
;
}
}
...
...
h2/src/main/org/h2/store/fs/FilePathDisk.java
浏览文件 @
b6ad6d6a
...
...
@@ -15,6 +15,9 @@ import java.io.InputStream;
import
java.io.OutputStream
;
import
java.io.RandomAccessFile
;
import
java.net.URL
;
import
java.nio.ByteBuffer
;
import
java.nio.channels.FileChannel
;
import
java.nio.channels.FileLock
;
import
java.util.ArrayList
;
import
java.util.List
;
import
org.h2.constant.ErrorCode
;
...
...
@@ -146,7 +149,7 @@ public class FilePathDisk extends FilePath {
throw
DbException
.
get
(
ErrorCode
.
FILE_DELETE_FAILED_1
,
name
);
}
public
List
<
FilePath
>
listFiles
()
{
public
List
<
FilePath
>
newDirectoryStream
()
{
ArrayList
<
FilePath
>
list
=
New
.
arrayList
();
File
f
=
new
File
(
name
);
try
{
...
...
@@ -175,7 +178,7 @@ public class FilePathDisk extends FilePath {
return
f
.
setReadOnly
();
}
public
FilePathDisk
getCanonic
alPath
()
{
public
FilePathDisk
toRe
alPath
()
{
try
{
String
fileName
=
new
File
(
name
).
getCanonicalPath
();
return
getPath
(
fileName
);
...
...
@@ -311,15 +314,15 @@ public class FilePathDisk extends FilePath {
}
}
public
File
Object
openFileObject
(
String
mode
)
throws
IOException
{
File
Object
Disk
f
;
public
File
Channel
open
(
String
mode
)
throws
IOException
{
FileDisk
f
;
try
{
f
=
new
File
Object
Disk
(
name
,
mode
);
IOUtils
.
trace
(
"open
FileObject
"
,
name
,
f
);
f
=
new
FileDisk
(
name
,
mode
);
IOUtils
.
trace
(
"open"
,
name
,
f
);
}
catch
(
IOException
e
)
{
freeMemoryAndFinalize
();
try
{
f
=
new
File
Object
Disk
(
name
,
mode
);
f
=
new
FileDisk
(
name
,
mode
);
}
catch
(
IOException
e2
)
{
throw
e
;
}
...
...
@@ -363,3 +366,81 @@ public class FilePathDisk extends FilePath {
}
}
/**
* Uses java.io.RandomAccessFile to access a file.
*/
class
FileDisk
extends
FileBase
{
private
final
RandomAccessFile
file
;
private
final
String
name
;
FileDisk
(
String
fileName
,
String
mode
)
throws
FileNotFoundException
{
this
.
file
=
new
RandomAccessFile
(
fileName
,
mode
);
this
.
name
=
fileName
;
}
public
void
force
(
boolean
metaData
)
throws
IOException
{
String
m
=
SysProperties
.
SYNC_METHOD
;
if
(
""
.
equals
(
m
))
{
// do nothing
}
else
if
(
"sync"
.
equals
(
m
))
{
file
.
getFD
().
sync
();
}
else
if
(
"force"
.
equals
(
m
))
{
file
.
getChannel
().
force
(
true
);
}
else
if
(
"forceFalse"
.
equals
(
m
))
{
file
.
getChannel
().
force
(
false
);
}
else
{
file
.
getFD
().
sync
();
}
}
public
FileChannel
truncate
(
long
newLength
)
throws
IOException
{
if
(
newLength
<
file
.
length
())
{
// some implementations actually only support truncate
file
.
setLength
(
newLength
);
}
return
this
;
}
public
synchronized
FileLock
tryLock
(
long
position
,
long
size
,
boolean
shared
)
throws
IOException
{
return
file
.
getChannel
().
tryLock
();
}
public
void
implCloseChannel
()
throws
IOException
{
file
.
close
();
}
public
long
position
()
throws
IOException
{
return
file
.
getFilePointer
();
}
public
long
size
()
throws
IOException
{
return
file
.
length
();
}
public
int
read
(
ByteBuffer
dst
)
throws
IOException
{
int
len
=
file
.
read
(
dst
.
array
(),
dst
.
position
(),
dst
.
remaining
());
if
(
len
>
0
)
{
dst
.
position
(
dst
.
position
()
+
len
);
}
return
len
;
}
public
FileChannel
position
(
long
pos
)
throws
IOException
{
file
.
seek
(
pos
);
return
this
;
}
public
int
write
(
ByteBuffer
src
)
throws
IOException
{
int
len
=
src
.
remaining
();
file
.
write
(
src
.
array
(),
src
.
position
(),
len
);
src
.
position
(
src
.
position
()
+
len
);
return
len
;
}
public
String
toString
()
{
return
name
;
}
}
h2/src/main/org/h2/store/fs/FilePathMem.java
浏览文件 @
b6ad6d6a
差异被折叠。
点击展开。
h2/src/main/org/h2/store/fs/FilePathNio.java
浏览文件 @
b6ad6d6a
...
...
@@ -7,6 +7,11 @@
package
org
.
h2
.
store
.
fs
;
import
java.io.IOException
;
import
java.io.RandomAccessFile
;
import
java.nio.ByteBuffer
;
import
java.nio.channels.FileChannel
;
import
java.nio.channels.FileLock
;
import
java.nio.channels.NonWritableChannelException
;
/**
* This file system stores files on disk and uses java.nio to access the files.
...
...
@@ -14,8 +19,8 @@ import java.io.IOException;
*/
public
class
FilePathNio
extends
FilePathWrapper
{
public
File
Object
openFileObject
(
String
mode
)
throws
IOException
{
return
new
File
Object
Nio
(
name
.
substring
(
getScheme
().
length
()
+
1
),
mode
);
public
File
Channel
open
(
String
mode
)
throws
IOException
{
return
new
FileNio
(
name
.
substring
(
getScheme
().
length
()
+
1
),
mode
);
}
public
String
getScheme
()
{
...
...
@@ -23,3 +28,73 @@ public class FilePathNio extends FilePathWrapper {
}
}
/**
* File which uses NIO FileChannel.
*/
class
FileNio
extends
FileBase
{
private
final
String
name
;
private
final
FileChannel
channel
;
FileNio
(
String
fileName
,
String
mode
)
throws
IOException
{
this
.
name
=
fileName
;
channel
=
new
RandomAccessFile
(
fileName
,
mode
).
getChannel
();
}
public
void
implCloseChannel
()
throws
IOException
{
channel
.
close
();
}
public
long
position
()
throws
IOException
{
return
channel
.
position
();
}
public
long
size
()
throws
IOException
{
return
channel
.
size
();
}
public
int
read
(
ByteBuffer
dst
)
throws
IOException
{
return
channel
.
read
(
dst
);
}
public
FileChannel
position
(
long
pos
)
throws
IOException
{
channel
.
position
(
pos
);
return
this
;
}
public
FileChannel
truncate
(
long
newLength
)
throws
IOException
{
try
{
channel
.
truncate
(
newLength
);
if
(
channel
.
position
()
>
newLength
)
{
// looks like a bug in this FileChannel implementation, as the
// documentation says the position needs to be changed
channel
.
position
(
newLength
);
}
return
this
;
}
catch
(
NonWritableChannelException
e
)
{
throw
new
IOException
(
"read only"
);
}
}
public
void
force
(
boolean
metaData
)
throws
IOException
{
channel
.
force
(
metaData
);
}
public
int
write
(
ByteBuffer
src
)
throws
IOException
{
try
{
return
channel
.
write
(
src
);
}
catch
(
NonWritableChannelException
e
)
{
throw
new
IOException
(
"read only"
);
}
}
public
synchronized
FileLock
tryLock
(
long
position
,
long
size
,
boolean
shared
)
throws
IOException
{
return
channel
.
tryLock
();
}
public
String
toString
()
{
return
name
;
}
}
h2/src/main/org/h2/store/fs/FilePathNioMapped.java
浏览文件 @
b6ad6d6a
...
...
@@ -6,7 +6,17 @@
*/
package
org
.
h2
.
store
.
fs
;
import
java.io.EOFException
;
import
java.io.IOException
;
import
java.io.RandomAccessFile
;
import
java.lang.ref.WeakReference
;
import
java.lang.reflect.Method
;
import
java.nio.BufferUnderflowException
;
import
java.nio.ByteBuffer
;
import
java.nio.MappedByteBuffer
;
import
java.nio.channels.FileChannel
;
import
java.nio.channels.FileLock
;
import
org.h2.constant.SysProperties
;
/**
* This file system stores files on disk and uses java.nio to access the files.
...
...
@@ -14,8 +24,8 @@ import java.io.IOException;
*/
public
class
FilePathNioMapped
extends
FilePathNio
{
public
File
Object
openFileObject
(
String
mode
)
throws
IOException
{
return
new
File
Object
NioMapped
(
name
.
substring
(
getScheme
().
length
()
+
1
),
mode
);
public
File
Channel
open
(
String
mode
)
throws
IOException
{
return
new
FileNioMapped
(
name
.
substring
(
getScheme
().
length
()
+
1
),
mode
);
}
public
String
getScheme
()
{
...
...
@@ -23,3 +33,207 @@ public class FilePathNioMapped extends FilePathNio {
}
}
/**
* Uses memory mapped files.
* The file size is limited to 2 GB.
*/
class
FileNioMapped
extends
FileBase
{
private
static
final
long
GC_TIMEOUT_MS
=
10000
;
private
final
String
name
;
private
final
MapMode
mode
;
private
RandomAccessFile
file
;
private
MappedByteBuffer
mapped
;
private
long
fileLength
;
/**
* The position within the file. Can't use the position of the mapped buffer
* because it doesn't support seeking past the end of the file.
*/
private
int
pos
;
FileNioMapped
(
String
fileName
,
String
mode
)
throws
IOException
{
if
(
"r"
.
equals
(
mode
))
{
this
.
mode
=
MapMode
.
READ_ONLY
;
}
else
{
this
.
mode
=
MapMode
.
READ_WRITE
;
}
this
.
name
=
fileName
;
file
=
new
RandomAccessFile
(
fileName
,
mode
);
reMap
();
}
private
void
unMap
()
throws
IOException
{
if
(
mapped
==
null
)
{
return
;
}
// first write all data
mapped
.
force
();
// need to dispose old direct buffer, see bug
// http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4724038
boolean
useSystemGc
=
true
;
if
(
SysProperties
.
NIO_CLEANER_HACK
)
{
try
{
Method
cleanerMethod
=
mapped
.
getClass
().
getMethod
(
"cleaner"
);
cleanerMethod
.
setAccessible
(
true
);
Object
cleaner
=
cleanerMethod
.
invoke
(
mapped
);
if
(
cleaner
!=
null
)
{
Method
clearMethod
=
cleaner
.
getClass
().
getMethod
(
"clean"
);
clearMethod
.
invoke
(
cleaner
);
}
useSystemGc
=
false
;
}
catch
(
Throwable
e
)
{
// useSystemGc is already true
}
finally
{
mapped
=
null
;
}
}
if
(
useSystemGc
)
{
WeakReference
<
MappedByteBuffer
>
bufferWeakRef
=
new
WeakReference
<
MappedByteBuffer
>(
mapped
);
mapped
=
null
;
long
start
=
System
.
currentTimeMillis
();
while
(
bufferWeakRef
.
get
()
!=
null
)
{
if
(
System
.
currentTimeMillis
()
-
start
>
GC_TIMEOUT_MS
)
{
throw
new
IOException
(
"Timeout ("
+
GC_TIMEOUT_MS
+
" ms) reached while trying to GC mapped buffer"
);
}
System
.
gc
();
Thread
.
yield
();
}
}
}
/**
* Re-map byte buffer into memory, called when file size has changed or file
* was created.
*/
private
void
reMap
()
throws
IOException
{
int
oldPos
=
0
;
if
(
mapped
!=
null
)
{
oldPos
=
pos
;
unMap
();
}
fileLength
=
file
.
length
();
checkFileSizeLimit
(
fileLength
);
// maps new MappedByteBuffer; the old one is disposed during GC
mapped
=
file
.
getChannel
().
map
(
mode
,
0
,
fileLength
);
int
limit
=
mapped
.
limit
();
int
capacity
=
mapped
.
capacity
();
if
(
limit
<
fileLength
||
capacity
<
fileLength
)
{
throw
new
IOException
(
"Unable to map: length="
+
limit
+
" capacity="
+
capacity
+
" length="
+
fileLength
);
}
if
(
SysProperties
.
NIO_LOAD_MAPPED
)
{
mapped
.
load
();
}
this
.
pos
=
Math
.
min
(
oldPos
,
(
int
)
fileLength
);
}
private
static
void
checkFileSizeLimit
(
long
length
)
throws
IOException
{
if
(
length
>
Integer
.
MAX_VALUE
)
{
throw
new
IOException
(
"File over 2GB is not supported yet when using this file system"
);
}
}
public
void
implCloseChannel
()
throws
IOException
{
if
(
file
!=
null
)
{
unMap
();
file
.
close
();
file
=
null
;
}
}
public
long
position
()
{
return
pos
;
}
public
String
toString
()
{
return
"nioMapped:"
+
name
;
}
public
synchronized
long
size
()
throws
IOException
{
return
fileLength
;
}
public
synchronized
int
read
(
ByteBuffer
dst
)
throws
IOException
{
try
{
int
len
=
dst
.
remaining
();
if
(
len
==
0
)
{
return
0
;
}
len
=
(
int
)
Math
.
min
(
len
,
fileLength
-
pos
);
if
(
len
<=
0
)
{
return
-
1
;
}
mapped
.
position
(
pos
);
mapped
.
get
(
dst
.
array
(),
dst
.
position
(),
len
);
dst
.
position
(
dst
.
position
()
+
len
);
pos
+=
len
;
return
len
;
}
catch
(
IllegalArgumentException
e
)
{
EOFException
e2
=
new
EOFException
(
"EOF"
);
e2
.
initCause
(
e
);
throw
e2
;
}
catch
(
BufferUnderflowException
e
)
{
EOFException
e2
=
new
EOFException
(
"EOF"
);
e2
.
initCause
(
e
);
throw
e2
;
}
}
public
FileChannel
position
(
long
pos
)
throws
IOException
{
checkFileSizeLimit
(
pos
);
this
.
pos
=
(
int
)
pos
;
return
this
;
}
public
synchronized
FileChannel
truncate
(
long
newLength
)
throws
IOException
{
if
(
newLength
<
size
())
{
setFileLength
(
newLength
);
}
return
this
;
}
public
synchronized
void
setFileLength
(
long
newLength
)
throws
IOException
{
checkFileSizeLimit
(
newLength
);
int
oldPos
=
pos
;
unMap
();
for
(
int
i
=
0
;;
i
++)
{
try
{
file
.
setLength
(
newLength
);
break
;
}
catch
(
IOException
e
)
{
if
(
i
>
16
||
e
.
toString
().
indexOf
(
"user-mapped section open"
)
<
0
)
{
throw
e
;
}
}
System
.
gc
();
}
reMap
();
pos
=
(
int
)
Math
.
min
(
newLength
,
oldPos
);
}
public
void
force
(
boolean
metaData
)
throws
IOException
{
mapped
.
force
();
file
.
getFD
().
sync
();
}
public
synchronized
int
write
(
ByteBuffer
src
)
throws
IOException
{
int
len
=
src
.
remaining
();
// check if need to expand file
if
(
mapped
.
capacity
()
<
pos
+
len
)
{
setFileLength
(
pos
+
len
);
}
mapped
.
position
(
pos
);
mapped
.
put
(
src
);
pos
+=
len
;
return
len
;
}
public
synchronized
FileLock
tryLock
(
long
position
,
long
size
,
boolean
shared
)
throws
IOException
{
return
file
.
getChannel
().
tryLock
();
}
}
h2/src/main/org/h2/store/fs/FilePathRec.java
浏览文件 @
b6ad6d6a
...
...
@@ -8,6 +8,9 @@ package org.h2.store.fs;
import
java.io.IOException
;
import
java.io.OutputStream
;
import
java.nio.ByteBuffer
;
import
java.nio.channels.FileChannel
;
import
java.nio.channels.FileLock
;
/**
* A file system that records all write operations and can re-play them.
...
...
@@ -52,8 +55,8 @@ public class FilePathRec extends FilePathWrapper {
super
.
delete
();
}
public
File
Object
openFileObject
(
String
mode
)
throws
IOException
{
return
new
File
ObjectRec
(
this
,
super
.
openFileObject
(
mode
),
name
);
public
File
Channel
open
(
String
mode
)
throws
IOException
{
return
new
File
Rec
(
this
,
super
.
open
(
mode
),
name
);
}
public
OutputStream
newOutputStream
(
boolean
append
)
{
...
...
@@ -108,3 +111,68 @@ public class FilePathRec extends FilePathWrapper {
}
}
/**
* A file object that records all write operations and can re-play them.
*/
class
FileRec
extends
FileBase
{
private
final
FilePathRec
rec
;
private
final
FileChannel
channel
;
private
final
String
name
;
FileRec
(
FilePathRec
rec
,
FileChannel
file
,
String
fileName
)
{
this
.
rec
=
rec
;
this
.
channel
=
file
;
this
.
name
=
fileName
;
}
public
void
implCloseChannel
()
throws
IOException
{
channel
.
close
();
}
public
long
position
()
throws
IOException
{
return
channel
.
position
();
}
public
long
size
()
throws
IOException
{
return
channel
.
size
();
}
public
int
read
(
ByteBuffer
dst
)
throws
IOException
{
return
channel
.
read
(
dst
);
}
public
FileChannel
position
(
long
pos
)
throws
IOException
{
channel
.
position
(
pos
);
return
this
;
}
public
FileChannel
truncate
(
long
newLength
)
throws
IOException
{
rec
.
log
(
Recorder
.
TRUNCATE
,
name
,
null
,
newLength
);
channel
.
truncate
(
newLength
);
return
this
;
}
public
void
force
(
boolean
metaData
)
throws
IOException
{
channel
.
force
(
metaData
);
}
public
int
write
(
ByteBuffer
src
)
throws
IOException
{
byte
[]
buff
=
src
.
array
();
int
len
=
src
.
remaining
();
if
(
src
.
position
()
!=
0
||
len
!=
buff
.
length
)
{
byte
[]
b
=
new
byte
[
len
];
System
.
arraycopy
(
buff
,
src
.
position
(),
b
,
0
,
len
);
buff
=
b
;
}
int
result
=
channel
.
write
(
src
);
rec
.
log
(
Recorder
.
WRITE
,
name
,
buff
,
channel
.
position
());
return
result
;
}
public
synchronized
FileLock
tryLock
(
long
position
,
long
size
,
boolean
shared
)
throws
IOException
{
return
channel
.
tryLock
();
}
}
h2/src/main/org/h2/store/fs/FilePathSplit.java
浏览文件 @
b6ad6d6a
...
...
@@ -10,6 +10,9 @@ import java.io.IOException;
import
java.io.InputStream
;
import
java.io.OutputStream
;
import
java.io.SequenceInputStream
;
import
java.nio.ByteBuffer
;
import
java.nio.channels.FileChannel
;
import
java.nio.channels.FileLock
;
import
java.util.ArrayList
;
import
java.util.List
;
import
org.h2.constant.SysProperties
;
...
...
@@ -83,8 +86,8 @@ public class FilePathSplit extends FilePathWrapper {
return
length
;
}
public
ArrayList
<
FilePath
>
listFiles
()
{
List
<
FilePath
>
list
=
getBase
().
listFiles
();
public
ArrayList
<
FilePath
>
newDirectoryStream
()
{
List
<
FilePath
>
list
=
getBase
().
newDirectoryStream
();
ArrayList
<
FilePath
>
newList
=
New
.
arrayList
();
for
(
int
i
=
0
,
size
=
list
.
size
();
i
<
size
;
i
++)
{
FilePath
f
=
list
.
get
(
i
);
...
...
@@ -109,20 +112,18 @@ public class FilePathSplit extends FilePathWrapper {
return
input
;
}
public
FileObject
openFileObject
(
String
mode
)
throws
IOException
{
ArrayList
<
FileObject
>
list
=
New
.
arrayList
();
FileObject
o
=
getBase
().
openFileObject
(
mode
);
list
.
add
(
o
);
public
FileChannel
open
(
String
mode
)
throws
IOException
{
ArrayList
<
FileChannel
>
list
=
New
.
arrayList
();
list
.
add
(
getBase
().
open
(
mode
));
for
(
int
i
=
1
;;
i
++)
{
FilePath
f
=
getBase
(
i
);
if
(
f
.
exists
())
{
o
=
f
.
openFileObject
(
mode
);
list
.
add
(
o
);
list
.
add
(
f
.
open
(
mode
));
}
else
{
break
;
}
}
File
Object
[]
array
=
new
FileObject
[
list
.
size
()];
File
Channel
[]
array
=
new
FileChannel
[
list
.
size
()];
list
.
toArray
(
array
);
long
maxLength
=
array
[
0
].
size
();
long
length
=
maxLength
;
...
...
@@ -136,21 +137,21 @@ public class FilePathSplit extends FilePathWrapper {
closeAndThrow
(
0
,
array
,
array
[
0
],
maxLength
);
}
for
(
int
i
=
1
;
i
<
array
.
length
-
1
;
i
++)
{
o
=
array
[
i
];
long
l
=
o
.
size
();
FileChannel
c
=
array
[
i
];
long
l
=
c
.
size
();
length
+=
l
;
if
(
l
!=
maxLength
)
{
closeAndThrow
(
i
,
array
,
o
,
maxLength
);
closeAndThrow
(
i
,
array
,
c
,
maxLength
);
}
}
o
=
array
[
array
.
length
-
1
];
long
l
=
o
.
size
();
FileChannel
c
=
array
[
array
.
length
-
1
];
long
l
=
c
.
size
();
length
+=
l
;
if
(
l
>
maxLength
)
{
closeAndThrow
(
array
.
length
-
1
,
array
,
o
,
maxLength
);
closeAndThrow
(
array
.
length
-
1
,
array
,
c
,
maxLength
);
}
}
File
ObjectSplit
fo
=
new
FileObject
Split
(
this
,
mode
,
array
,
length
,
maxLength
);
File
Split
fo
=
new
File
Split
(
this
,
mode
,
array
,
length
,
maxLength
);
return
fo
;
}
...
...
@@ -158,9 +159,9 @@ public class FilePathSplit extends FilePathWrapper {
return
1L
<<
Integer
.
decode
(
parse
(
name
)[
0
]).
intValue
();
}
private
void
closeAndThrow
(
int
id
,
File
Object
[]
array
,
FileObject
o
,
long
maxLength
)
throws
IOException
{
private
void
closeAndThrow
(
int
id
,
File
Channel
[]
array
,
FileChannel
o
,
long
maxLength
)
throws
IOException
{
String
message
=
"Expected file length: "
+
maxLength
+
" got: "
+
o
.
size
()
+
" for "
+
getName
(
id
);
for
(
File
Object
f
:
array
)
{
for
(
File
Channel
f
:
array
)
{
f
.
close
();
}
throw
new
IOException
(
message
);
...
...
@@ -168,7 +169,7 @@ public class FilePathSplit extends FilePathWrapper {
public
OutputStream
newOutputStream
(
boolean
append
)
{
try
{
return
new
File
ObjectOutputStream
(
openFileObject
(
"rw"
),
append
);
return
new
File
ChannelOutputStream
(
open
(
"rw"
),
append
);
}
catch
(
IOException
e
)
{
throw
DbException
.
convertIOException
(
e
,
name
);
}
...
...
@@ -230,4 +231,147 @@ public class FilePathSplit extends FilePathWrapper {
return
"split"
;
}
}
\ No newline at end of file
}
/**
* A file that may be split into multiple smaller files.
*/
class
FileSplit
extends
FileBase
{
private
final
FilePathSplit
file
;
private
final
String
mode
;
private
final
long
maxLength
;
private
FileChannel
[]
list
;
private
long
filePointer
;
private
long
length
;
FileSplit
(
FilePathSplit
file
,
String
mode
,
FileChannel
[]
list
,
long
length
,
long
maxLength
)
{
this
.
file
=
file
;
this
.
mode
=
mode
;
this
.
list
=
list
;
this
.
length
=
length
;
this
.
maxLength
=
maxLength
;
}
public
void
implCloseChannel
()
throws
IOException
{
for
(
FileChannel
c
:
list
)
{
c
.
close
();
}
}
public
long
position
()
{
return
filePointer
;
}
public
long
size
()
{
return
length
;
}
public
int
read
(
ByteBuffer
dst
)
throws
IOException
{
int
len
=
dst
.
remaining
();
if
(
len
==
0
)
{
return
0
;
}
len
=
(
int
)
Math
.
min
(
len
,
length
-
filePointer
);
if
(
len
<=
0
)
{
return
-
1
;
}
long
offset
=
filePointer
%
maxLength
;
len
=
(
int
)
Math
.
min
(
len
,
maxLength
-
offset
);
FileChannel
channel
=
getFileChannel
();
channel
.
position
(
offset
);
len
=
channel
.
read
(
dst
);
filePointer
+=
len
;
return
len
;
}
public
FileChannel
position
(
long
pos
)
{
filePointer
=
pos
;
return
this
;
}
private
FileChannel
getFileChannel
()
throws
IOException
{
int
id
=
(
int
)
(
filePointer
/
maxLength
);
while
(
id
>=
list
.
length
)
{
int
i
=
list
.
length
;
FileChannel
[]
newList
=
new
FileChannel
[
i
+
1
];
System
.
arraycopy
(
list
,
0
,
newList
,
0
,
i
);
FilePath
f
=
file
.
getBase
(
i
);
newList
[
i
]
=
f
.
open
(
mode
);
list
=
newList
;
}
return
list
[
id
];
}
public
FileChannel
truncate
(
long
newLength
)
throws
IOException
{
if
(
newLength
>=
length
)
{
return
this
;
}
filePointer
=
Math
.
min
(
filePointer
,
newLength
);
int
newFileCount
=
1
+
(
int
)
(
newLength
/
maxLength
);
if
(
newFileCount
<
list
.
length
)
{
// delete some of the files
FileChannel
[]
newList
=
new
FileChannel
[
newFileCount
];
// delete backwards, so that truncating is somewhat transactional
for
(
int
i
=
list
.
length
-
1
;
i
>=
newFileCount
;
i
--)
{
// verify the file is writable
list
[
i
].
truncate
(
0
);
list
[
i
].
close
();
try
{
file
.
getBase
(
i
).
delete
();
}
catch
(
DbException
e
)
{
throw
DbException
.
convertToIOException
(
e
);
}
}
System
.
arraycopy
(
list
,
0
,
newList
,
0
,
newList
.
length
);
list
=
newList
;
}
long
size
=
newLength
-
maxLength
*
(
newFileCount
-
1
);
list
[
list
.
length
-
1
].
truncate
(
size
);
this
.
length
=
newLength
;
return
this
;
}
public
void
force
(
boolean
metaData
)
throws
IOException
{
for
(
FileChannel
c
:
list
)
{
c
.
force
(
metaData
);
}
}
public
int
write
(
ByteBuffer
src
)
throws
IOException
{
if
(
filePointer
>=
length
&&
filePointer
>
maxLength
)
{
// may need to extend and create files
long
oldFilePointer
=
filePointer
;
long
x
=
length
-
(
length
%
maxLength
)
+
maxLength
;
for
(;
x
<
filePointer
;
x
+=
maxLength
)
{
if
(
x
>
length
)
{
// expand the file size
position
(
x
-
1
);
write
(
ByteBuffer
.
wrap
(
new
byte
[
1
]));
}
filePointer
=
oldFilePointer
;
}
}
long
offset
=
filePointer
%
maxLength
;
int
len
=
src
.
remaining
();
FileChannel
channel
=
getFileChannel
();
channel
.
position
(
offset
);
int
l
=
(
int
)
Math
.
min
(
len
,
maxLength
-
offset
);
if
(
l
==
len
)
{
l
=
channel
.
write
(
src
);
}
else
{
int
oldLimit
=
src
.
limit
();
src
.
limit
(
src
.
position
()
+
l
);
l
=
channel
.
write
(
src
);
src
.
limit
(
oldLimit
);
}
filePointer
+=
l
;
length
=
Math
.
max
(
length
,
filePointer
);
return
l
;
}
public
synchronized
FileLock
tryLock
(
long
position
,
long
size
,
boolean
shared
)
throws
IOException
{
return
list
[
0
].
tryLock
();
}
}
h2/src/main/org/h2/store/fs/FilePathWrapper.java
浏览文件 @
b6ad6d6a
...
...
@@ -9,6 +9,7 @@ package org.h2.store.fs;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.io.OutputStream
;
import
java.nio.channels.FileChannel
;
import
java.util.List
;
import
org.h2.message.DbException
;
...
...
@@ -103,12 +104,12 @@ public abstract class FilePathWrapper extends FilePath {
return
base
.
lastModified
();
}
public
FilePath
getCanonic
alPath
()
{
return
wrap
(
base
.
getCanonic
alPath
());
public
FilePath
toRe
alPath
()
{
return
wrap
(
base
.
toRe
alPath
());
}
public
List
<
FilePath
>
listFiles
()
{
List
<
FilePath
>
list
=
base
.
listFiles
();
public
List
<
FilePath
>
newDirectoryStream
()
{
List
<
FilePath
>
list
=
base
.
newDirectoryStream
();
for
(
int
i
=
0
,
len
=
list
.
size
();
i
<
len
;
i
++)
{
list
.
set
(
i
,
wrap
(
list
.
get
(
i
)));
}
...
...
@@ -127,8 +128,8 @@ public abstract class FilePathWrapper extends FilePath {
return
base
.
newOutputStream
(
append
);
}
public
File
Object
openFileObject
(
String
mode
)
throws
IOException
{
return
base
.
open
FileObject
(
mode
);
public
File
Channel
open
(
String
mode
)
throws
IOException
{
return
base
.
open
(
mode
);
}
public
boolean
setReadOnly
()
{
...
...
h2/src/main/org/h2/store/fs/FilePathZip.java
浏览文件 @
b6ad6d6a
...
...
@@ -10,11 +10,15 @@ import java.io.FileNotFoundException;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.io.OutputStream
;
import
java.nio.ByteBuffer
;
import
java.nio.channels.FileChannel
;
import
java.nio.channels.FileLock
;
import
java.util.ArrayList
;
import
java.util.Enumeration
;
import
java.util.zip.ZipEntry
;
import
java.util.zip.ZipFile
;
import
org.h2.message.DbException
;
import
org.h2.util.IOUtils
;
import
org.h2.util.New
;
/**
...
...
@@ -112,7 +116,7 @@ public class FilePathZip extends FilePath {
}
}
public
ArrayList
<
FilePath
>
listFiles
()
{
public
ArrayList
<
FilePath
>
newDirectoryStream
()
{
String
path
=
name
;
ArrayList
<
FilePath
>
list
=
New
.
arrayList
();
try
{
...
...
@@ -147,16 +151,16 @@ public class FilePathZip extends FilePath {
}
public
InputStream
newInputStream
()
throws
IOException
{
return
new
File
ObjectInputStream
(
openFileObject
(
"r"
));
return
new
File
ChannelInputStream
(
open
(
"r"
));
}
public
File
Object
openFileObject
(
String
mode
)
throws
IOException
{
public
File
Channel
open
(
String
mode
)
throws
IOException
{
ZipFile
file
=
openZipFile
();
ZipEntry
entry
=
file
.
getEntry
(
getEntryName
());
if
(
entry
==
null
)
{
throw
new
FileNotFoundException
(
name
);
}
return
new
File
Object
Zip
(
file
,
entry
);
return
new
FileZip
(
file
,
entry
);
}
public
OutputStream
newOutputStream
(
boolean
append
)
{
...
...
@@ -178,7 +182,7 @@ public class FilePathZip extends FilePath {
return
FilePathDisk
.
expandUserHomeDirectory
(
fileName
);
}
public
FilePath
getCanonic
alPath
()
{
public
FilePath
toRe
alPath
()
{
return
this
;
}
...
...
@@ -214,3 +218,100 @@ public class FilePathZip extends FilePath {
}
}
/**
* The file is read from a stream. When reading from start to end, the same
* input stream is re-used, however when reading from end to start, a new input
* stream is opened for each request.
*/
class
FileZip
extends
FileBase
{
private
static
final
byte
[]
SKIP_BUFFER
=
new
byte
[
1024
];
private
ZipFile
file
;
private
ZipEntry
entry
;
private
long
pos
;
private
InputStream
in
;
private
long
inPos
;
private
long
length
;
private
boolean
skipUsingRead
;
FileZip
(
ZipFile
file
,
ZipEntry
entry
)
{
this
.
file
=
file
;
this
.
entry
=
entry
;
length
=
entry
.
getSize
();
}
public
long
position
()
{
return
pos
;
}
public
long
size
()
{
return
length
;
}
public
int
read
(
ByteBuffer
dst
)
throws
IOException
{
seek
();
int
len
=
in
.
read
(
dst
.
array
(),
dst
.
position
(),
dst
.
remaining
());
if
(
len
>
0
)
{
dst
.
position
(
dst
.
position
()
+
len
);
pos
+=
len
;
inPos
+=
len
;
}
return
len
;
}
private
void
seek
()
throws
IOException
{
if
(
inPos
>
pos
)
{
if
(
in
!=
null
)
{
in
.
close
();
}
in
=
null
;
}
if
(
in
==
null
)
{
in
=
file
.
getInputStream
(
entry
);
inPos
=
0
;
}
if
(
inPos
<
pos
)
{
long
skip
=
pos
-
inPos
;
if
(!
skipUsingRead
)
{
try
{
IOUtils
.
skipFully
(
in
,
skip
);
}
catch
(
NullPointerException
e
)
{
// workaround for Android
skipUsingRead
=
true
;
}
}
if
(
skipUsingRead
)
{
while
(
skip
>
0
)
{
int
s
=
(
int
)
Math
.
min
(
SKIP_BUFFER
.
length
,
skip
);
s
=
in
.
read
(
SKIP_BUFFER
,
0
,
s
);
skip
-=
s
;
}
}
inPos
=
pos
;
}
}
public
FileChannel
position
(
long
newPos
)
{
this
.
pos
=
newPos
;
return
this
;
}
public
FileChannel
truncate
(
long
newLength
)
throws
IOException
{
throw
new
IOException
(
"File is read-only"
);
}
public
void
force
(
boolean
metaData
)
throws
IOException
{
// nothing to do
}
public
int
write
(
ByteBuffer
src
)
throws
IOException
{
throw
new
IOException
(
"File is read-only"
);
}
public
synchronized
FileLock
tryLock
(
long
position
,
long
size
,
boolean
shared
)
throws
IOException
{
return
null
;
}
}
h2/src/main/org/h2/store/fs/FileUtils.java
浏览文件 @
b6ad6d6a
package
org
.
h2
.
store
.
fs
;
import
java.io.EOFException
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.io.OutputStream
;
import
java.nio.ByteBuffer
;
import
java.nio.channels.FileChannel
;
import
java.util.List
;
import
org.h2.constant.ErrorCode
;
import
org.h2.message.DbException
;
import
org.h2.util.IOUtils
;
import
org.h2.util.New
;
/**
* This utility class contains utility functions that use the file system
...
...
@@ -59,14 +63,14 @@ public class FileUtils {
}
/**
*
Normalize a file
name.
*
Get the canonical file or directory
name.
* This method is similar to Java 7 <code>java.nio.file.Path.toRealPath</code>.
*
* @param fileName the file name
* @return the normalized file name
*/
public
static
String
getCanonic
alPath
(
String
fileName
)
{
return
FilePath
.
get
(
fileName
).
getCanonic
alPath
().
toString
();
public
static
String
toRe
alPath
(
String
fileName
)
{
return
FilePath
.
get
(
fileName
).
toRe
alPath
().
toString
();
}
/**
...
...
@@ -116,19 +120,20 @@ public class FileUtils {
}
/**
* List the files in the given directory.
* List the files
and directories
in the given directory.
* This method is similar to Java 7 <code>java.nio.file.Path.newDirectoryStream</code>.
*
* @param path the directory
* @return the list of fully qualified file names
*/
public
static
String
[]
listFiles
(
String
path
)
{
List
<
FilePath
>
list
=
FilePath
.
get
(
path
).
listFiles
();
String
[]
array
=
new
String
[
list
.
size
()];
for
(
int
i
=
0
,
len
=
list
.
size
();
i
<
len
;
i
++)
{
array
[
i
]
=
list
.
get
(
i
).
toString
();
public
static
List
<
String
>
newDirectoryStream
(
String
path
)
{
List
<
FilePath
>
list
=
FilePath
.
get
(
path
).
newDirectoryStream
();
int
len
=
list
.
size
();
List
<
String
>
result
=
New
.
arrayList
(
len
);
for
(
int
i
=
0
;
i
<
len
;
i
++)
{
result
.
add
(
list
.
get
(
i
).
toString
());
}
return
array
;
return
result
;
}
/**
...
...
@@ -174,8 +179,8 @@ public class FileUtils {
* @param mode the access mode. Supported are r, rw, rws, rwd
* @return the file object
*/
public
static
File
Object
openFileObject
(
String
fileName
,
String
mode
)
throws
IOException
{
return
FilePath
.
get
(
fileName
).
open
FileObject
(
mode
);
public
static
File
Channel
open
(
String
fileName
,
String
mode
)
throws
IOException
{
return
FilePath
.
get
(
fileName
).
open
(
mode
);
}
/**
...
...
@@ -248,7 +253,7 @@ public class FileUtils {
public
static
void
deleteRecursive
(
String
path
,
boolean
tryOnly
)
{
if
(
exists
(
path
))
{
if
(
isDirectory
(
path
))
{
for
(
String
s
:
listFiles
(
path
))
{
for
(
String
s
:
newDirectoryStream
(
path
))
{
deleteRecursive
(
s
,
tryOnly
);
}
}
...
...
@@ -324,4 +329,33 @@ public class FileUtils {
return
FilePath
.
get
(
prefix
).
createTempFile
(
suffix
,
deleteOnExit
,
inTempDir
).
toString
();
}
/**
* Fully read from the file. This will read all remaining bytes,
* or throw an EOFException if not successful.
*
* @param channel the file channel
* @param dst the byte buffer
*/
public
static
void
readFully
(
FileChannel
channel
,
ByteBuffer
dst
)
throws
IOException
{
do
{
int
r
=
channel
.
read
(
dst
);
if
(
r
<
0
)
{
throw
new
EOFException
();
}
}
while
(
dst
.
remaining
()
>
0
);
}
/**
* Fully write to the file. This will write all remaining bytes.
*
* @param channel the file channel
* @param src the byte buffer
*/
public
static
void
writeFully
(
FileChannel
channel
,
ByteBuffer
src
)
throws
IOException
{
do
{
channel
.
write
(
src
);
}
while
(
src
.
remaining
()
>
0
);
}
}
h2/src/main/org/h2/tools/Backup.java
浏览文件 @
b6ad6d6a
...
...
@@ -11,7 +11,6 @@ import java.io.IOException;
import
java.io.InputStream
;
import
java.io.OutputStream
;
import
java.sql.SQLException
;
import
java.util.Arrays
;
import
java.util.List
;
import
java.util.zip.ZipEntry
;
import
java.util.zip.ZipOutputStream
;
...
...
@@ -109,7 +108,7 @@ public class Backup extends Tool {
List
<
String
>
list
;
boolean
allFiles
=
db
!=
null
&&
db
.
length
()
==
0
;
if
(
allFiles
)
{
list
=
Arrays
.
asList
(
FileUtils
.
listFiles
(
directory
)
);
list
=
FileUtils
.
newDirectoryStream
(
directory
);
}
else
{
list
=
FileLister
.
getDatabaseFiles
(
directory
,
db
,
true
);
}
...
...
@@ -122,7 +121,7 @@ public class Backup extends Tool {
if
(!
quiet
)
{
FileLister
.
tryUnlockDatabase
(
list
,
"backup"
);
}
zipFileName
=
FileUtils
.
getCanonic
alPath
(
zipFileName
);
zipFileName
=
FileUtils
.
toRe
alPath
(
zipFileName
);
FileUtils
.
delete
(
zipFileName
);
OutputStream
fileOut
=
null
;
try
{
...
...
@@ -136,7 +135,7 @@ public class Backup extends Tool {
}
}
for
(
String
fileName
:
list
)
{
String
f
=
FileUtils
.
getCanonic
alPath
(
fileName
);
String
f
=
FileUtils
.
toRe
alPath
(
fileName
);
if
(!
f
.
startsWith
(
base
))
{
DbException
.
throwInternalError
(
f
+
" does not start with "
+
base
);
}
...
...
h2/src/main/org/h2/value/ValueLob.java
浏览文件 @
b6ad6d6a
...
...
@@ -237,7 +237,7 @@ public class ValueLob extends Value {
name
=
SysProperties
.
FILE_SEPARATOR
+
f
+
Constants
.
SUFFIX_LOBS_DIRECTORY
+
name
;
objectId
/=
SysProperties
.
LOB_FILES_PER_DIRECTORY
;
}
name
=
FileUtils
.
getCanonic
alPath
(
path
+
Constants
.
SUFFIX_LOBS_DIRECTORY
+
name
);
name
=
FileUtils
.
toRe
alPath
(
path
+
Constants
.
SUFFIX_LOBS_DIRECTORY
+
name
);
return
name
;
}
...
...
@@ -322,12 +322,12 @@ public class ValueLob extends Value {
SmallLRUCache
<
String
,
String
[]>
cache
=
h
.
getLobFileListCache
();
String
[]
list
;
if
(
cache
==
null
)
{
list
=
FileUtils
.
listFiles
(
dir
);
list
=
FileUtils
.
newDirectoryStream
(
dir
).
toArray
(
new
String
[
0
]
);
}
else
{
synchronized
(
cache
)
{
list
=
cache
.
get
(
dir
);
if
(
list
==
null
)
{
list
=
FileUtils
.
listFiles
(
dir
);
list
=
FileUtils
.
newDirectoryStream
(
dir
).
toArray
(
new
String
[
0
]
);
cache
.
put
(
dir
,
list
);
}
}
...
...
@@ -719,7 +719,7 @@ public class ValueLob extends Value {
}
private
static
void
removeAllForTable
(
DataHandler
handler
,
String
dir
,
int
tableId
)
{
for
(
String
name
:
FileUtils
.
listFiles
(
dir
))
{
for
(
String
name
:
FileUtils
.
newDirectoryStream
(
dir
))
{
if
(
FileUtils
.
isDirectory
(
name
))
{
removeAllForTable
(
handler
,
name
,
tableId
);
}
else
{
...
...
h2/src/test/org/h2/test/db/TestCases.java
浏览文件 @
b6ad6d6a
...
...
@@ -17,6 +17,7 @@ import java.sql.SQLException;
import
java.sql.Statement
;
import
java.sql.Time
;
import
java.sql.Timestamp
;
import
java.util.List
;
import
java.util.Random
;
import
org.h2.constant.ErrorCode
;
import
org.h2.store.fs.FileUtils
;
...
...
@@ -1218,10 +1219,8 @@ public class TestCases extends TestBase {
conn
.
close
();
String
[]
list
=
FileUtils
.
listFiles
(
getBaseDir
()
+
"/cases.lobs.db"
);
if
(
list
!=
null
&&
list
.
length
>
0
)
{
fail
(
"Lob file was not deleted"
);
}
List
<
String
>
list
=
FileUtils
.
newDirectoryStream
(
getBaseDir
()
+
"/cases.lobs.db"
);
assertEquals
(
"Lob file was not deleted: "
+
list
,
0
,
list
.
size
());
}
private
void
testDeleteTop
()
throws
SQLException
{
...
...
h2/src/test/org/h2/test/db/TestLinkedTable.java
浏览文件 @
b6ad6d6a
...
...
@@ -632,8 +632,7 @@ public class TestLinkedTable extends TestBase {
stat
.
execute
(
"CREATE TABLE TEST(ID INT PRIMARY KEY)"
);
conn
.
close
();
String
[]
files
=
FileUtils
.
listFiles
(
getBaseDir
());
for
(
String
file
:
files
)
{
for
(
String
file
:
FileUtils
.
newDirectoryStream
(
getBaseDir
()))
{
String
name
=
FileUtils
.
getName
(
file
);
if
((
name
.
startsWith
(
"testLinkedTableInReadOnlyDb"
))
&&
(!
name
.
endsWith
(
".trace.db"
)))
{
FileUtils
.
setReadOnly
(
file
);
...
...
h2/src/test/org/h2/test/db/TestLob.java
浏览文件 @
b6ad6d6a
...
...
@@ -23,6 +23,7 @@ import java.sql.SQLException;
import
java.sql.Savepoint
;
import
java.sql.Statement
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.Random
;
import
org.h2.constant.ErrorCode
;
import
org.h2.constant.SysProperties
;
...
...
@@ -385,21 +386,21 @@ public class TestLob extends TestBase {
stat
.
execute
(
"create table test(id int primary key, name clob)"
);
stat
.
execute
(
"insert into test values(1, space(10000))"
);
assertEquals
(
1
,
FileUtils
.
listFiles
(
getBaseDir
()
+
"/lob.lobs.db"
).
length
);
assertEquals
(
1
,
FileUtils
.
newDirectoryStream
(
getBaseDir
()
+
"/lob.lobs.db"
).
size
()
);
stat
.
execute
(
"drop table test"
);
assertEquals
(
0
,
FileUtils
.
listFiles
(
getBaseDir
()
+
"/lob.lobs.db"
).
length
);
assertEquals
(
0
,
FileUtils
.
newDirectoryStream
(
getBaseDir
()
+
"/lob.lobs.db"
).
size
()
);
stat
.
execute
(
"create table test(id int primary key, name clob)"
);
stat
.
execute
(
"insert into test values(1, space(10000))"
);
assertEquals
(
1
,
FileUtils
.
listFiles
(
getBaseDir
()
+
"/lob.lobs.db"
).
length
);
assertEquals
(
1
,
FileUtils
.
newDirectoryStream
(
getBaseDir
()
+
"/lob.lobs.db"
).
size
()
);
stat
.
execute
(
"drop all objects"
);
assertEquals
(
0
,
FileUtils
.
listFiles
(
getBaseDir
()
+
"/lob.lobs.db"
).
length
);
assertEquals
(
0
,
FileUtils
.
newDirectoryStream
(
getBaseDir
()
+
"/lob.lobs.db"
).
size
()
);
stat
.
execute
(
"create table test(id int primary key, name clob)"
);
stat
.
execute
(
"insert into test values(1, space(10000))"
);
assertEquals
(
1
,
FileUtils
.
listFiles
(
getBaseDir
()
+
"/lob.lobs.db"
).
length
);
assertEquals
(
1
,
FileUtils
.
newDirectoryStream
(
getBaseDir
()
+
"/lob.lobs.db"
).
size
()
);
stat
.
execute
(
"truncate table test"
);
assertEquals
(
0
,
FileUtils
.
listFiles
(
getBaseDir
()
+
"/lob.lobs.db"
).
length
);
assertEquals
(
0
,
FileUtils
.
newDirectoryStream
(
getBaseDir
()
+
"/lob.lobs.db"
).
size
()
);
conn
.
close
();
}
...
...
@@ -438,13 +439,10 @@ public class TestLob extends TestBase {
}
private
void
testTempFilesDeleted
()
throws
Exception
{
String
[]
list
;
FileUtils
.
deleteRecursive
(
TEMP_DIR
,
true
);
FileUtils
.
createDirectories
(
TEMP_DIR
);
list
=
FileUtils
.
listFiles
(
TEMP_DIR
);
if
(
list
.
length
>
0
)
{
fail
(
"Unexpected temp file: "
+
list
[
0
]);
}
List
<
String
>
list
=
FileUtils
.
newDirectoryStream
(
TEMP_DIR
);
assertEquals
(
"Unexpected temp file: "
+
list
,
0
,
list
.
size
());
deleteDb
(
"lob"
);
Connection
conn
=
getConnection
(
"lob"
);
Statement
stat
;
...
...
@@ -457,10 +455,8 @@ public class TestLob extends TestBase {
rs
.
getCharacterStream
(
"name"
).
close
();
rs
.
close
();
conn
.
close
();
list
=
FileUtils
.
listFiles
(
TEMP_DIR
);
if
(
list
.
length
>
0
)
{
fail
(
"Unexpected temp file: "
+
list
[
0
]);
}
list
=
FileUtils
.
newDirectoryStream
(
TEMP_DIR
);
assertEquals
(
"Unexpected temp file: "
+
list
,
0
,
list
.
size
());
}
private
static
void
testAddLobRestart
()
throws
SQLException
{
...
...
@@ -503,10 +499,10 @@ public class TestLob extends TestBase {
Connection
conn
=
getConnection
(
"lob"
);
Statement
stat
=
conn
.
createStatement
();
stat
.
execute
(
"create table test(data clob) as select space(100000) from dual"
);
assertEquals
(
1
,
FileUtils
.
listFiles
(
getBaseDir
()
+
"/lob.lobs.db"
).
length
);
assertEquals
(
1
,
FileUtils
.
newDirectoryStream
(
getBaseDir
()
+
"/lob.lobs.db"
).
size
()
);
stat
.
execute
(
"delete from test"
);
conn
.
close
();
assertEquals
(
0
,
FileUtils
.
listFiles
(
getBaseDir
()
+
"/lob.lobs.db"
).
length
);
assertEquals
(
0
,
FileUtils
.
newDirectoryStream
(
getBaseDir
()
+
"/lob.lobs.db"
).
size
()
);
}
private
void
testLobServerMemory
()
throws
SQLException
{
...
...
h2/src/test/org/h2/test/db/TestOpenClose.java
浏览文件 @
b6ad6d6a
...
...
@@ -6,6 +6,8 @@
*/
package
org
.
h2
.
test
.
db
;
import
java.nio.ByteBuffer
;
import
java.nio.channels.FileChannel
;
import
java.sql.Connection
;
import
java.sql.DriverManager
;
import
java.sql.PreparedStatement
;
...
...
@@ -14,7 +16,6 @@ import java.sql.SQLException;
import
java.sql.Statement
;
import
org.h2.api.DatabaseEventListener
;
import
org.h2.constant.ErrorCode
;
import
org.h2.store.fs.FileObject
;
import
org.h2.store.fs.FileUtils
;
import
org.h2.test.TestBase
;
import
org.h2.tools.Restore
;
...
...
@@ -67,10 +68,10 @@ public class TestOpenClose extends TestBase implements DatabaseEventListener {
conn
=
DriverManager
.
getConnection
(
"jdbc:h2:split:18:"
+
getBaseDir
()
+
"/openClose2"
);
conn
.
createStatement
().
execute
(
"create table test(id int, name varchar) as select 1, space(1000000)"
);
conn
.
close
();
File
Object
f
=
FileUtils
.
openFileObject
(
getBaseDir
()
+
"/openClose2.h2.db.1.part"
,
"rw"
);
f
.
position
(
f
.
size
()
*
2
-
1
);
f
.
write
(
new
byte
[
1
],
0
,
1
);
f
.
close
();
File
Channel
c
=
FileUtils
.
open
(
getBaseDir
()
+
"/openClose2.h2.db.1.part"
,
"rw"
);
c
.
position
(
c
.
size
()
*
2
-
1
);
c
.
write
(
ByteBuffer
.
wrap
(
new
byte
[
1
])
);
c
.
close
();
assertThrows
(
ErrorCode
.
IO_EXCEPTION_2
,
this
).
getConnection
(
"jdbc:h2:split:18:"
+
getBaseDir
()
+
"/openClose2"
);
FileUtils
.
delete
(
"split:"
+
getBaseDir
()
+
"/openClose2.h2.db"
);
...
...
h2/src/test/org/h2/test/unit/TestClearReferences.java
浏览文件 @
b6ad6d6a
...
...
@@ -68,7 +68,7 @@ public class TestClearReferences extends TestBase {
// initialize the known classes
MathUtils
.
secureRandomLong
();
ValueInt
.
get
(
1
);
Class
.
forName
(
"org.h2.store.fs.File
Object
MemData"
);
Class
.
forName
(
"org.h2.store.fs.FileMemData"
);
clear
();
...
...
h2/src/test/org/h2/test/unit/TestFileLockSerialized.java
浏览文件 @
b6ad6d6a
...
...
@@ -13,7 +13,6 @@ import java.sql.PreparedStatement;
import
java.sql.ResultSet
;
import
java.sql.SQLException
;
import
java.sql.Statement
;
import
java.util.Arrays
;
import
java.util.List
;
import
org.h2.constant.ErrorCode
;
import
org.h2.jdbc.JdbcConnection
;
...
...
@@ -604,7 +603,7 @@ public class TestFileLockSerialized extends TestBase {
stat
.
execute
(
"insert into test values(0)"
);
conn
.
close
();
List
<
String
>
filesWithoutSerialized
=
Arrays
.
asList
(
FileUtils
.
listFiles
(
getBaseDir
()
));
List
<
String
>
filesWithoutSerialized
=
FileUtils
.
newDirectoryStream
(
getBaseDir
(
));
deleteDb
(
"fileLockSerialized"
);
// with serialized
...
...
@@ -616,7 +615,7 @@ public class TestFileLockSerialized extends TestBase {
stat
.
execute
(
"insert into test values(0)"
);
conn
.
close
();
List
<
String
>
filesWithSerialized
=
Arrays
.
asList
(
FileUtils
.
listFiles
(
getBaseDir
()
));
List
<
String
>
filesWithSerialized
=
FileUtils
.
newDirectoryStream
(
getBaseDir
(
));
if
(
filesWithoutSerialized
.
size
()
!=
filesWithSerialized
.
size
())
{
for
(
int
i
=
0
;
i
<
filesWithoutSerialized
.
size
();
i
++)
{
if
(!
filesWithSerialized
.
contains
(
filesWithoutSerialized
.
get
(
i
)))
{
...
...
h2/src/test/org/h2/test/unit/TestFileSystem.java
浏览文件 @
b6ad6d6a
...
...
@@ -12,6 +12,8 @@ import java.io.IOException;
import
java.io.InputStream
;
import
java.io.OutputStream
;
import
java.io.RandomAccessFile
;
import
java.nio.ByteBuffer
;
import
java.nio.channels.FileChannel
;
import
java.nio.channels.FileLock
;
import
java.sql.Connection
;
import
java.sql.DriverManager
;
...
...
@@ -21,10 +23,10 @@ import java.sql.Statement;
import
java.util.List
;
import
java.util.Random
;
import
org.h2.dev.fs.FilePathCrypt
;
import
org.h2.store.fs.FileObject
;
import
org.h2.store.fs.FilePath
;
import
org.h2.store.fs.FileUtils
;
import
org.h2.test.TestBase
;
import
org.h2.test.utils.AssertThrows
;
import
org.h2.test.utils.FilePathDebug
;
import
org.h2.tools.Backup
;
import
org.h2.tools.DeleteDbFiles
;
...
...
@@ -58,7 +60,7 @@ public class TestFileSystem extends TestBase {
testDatabaseInJar
();
// set default part size to 1 << 10
String
f
=
"split:10:"
+
getBaseDir
()
+
"/fs"
;
FileUtils
.
getCanonic
alPath
(
f
);
FileUtils
.
toRe
alPath
(
f
);
testFileSystem
(
getBaseDir
()
+
"/fs"
);
testFileSystem
(
"memFS:"
);
testFileSystem
(
"memLZF:"
);
...
...
@@ -85,8 +87,7 @@ public class TestFileSystem extends TestBase {
private
void
testMemFsDir
()
throws
IOException
{
FileUtils
.
newOutputStream
(
"memFS:data/test/a.txt"
,
false
).
close
();
String
[]
list
=
FileUtils
.
listFiles
(
"memFS:data/test"
);
assertEquals
(
1
,
list
.
length
);
assertEquals
(
1
,
FileUtils
.
newDirectoryStream
(
"memFS:data/test"
).
size
());
FileUtils
.
deleteRecursive
(
"memFS:"
,
false
);
}
...
...
@@ -110,15 +111,15 @@ public class TestFileSystem extends TestBase {
private
void
testSimpleExpandTruncateSize
()
throws
Exception
{
String
f
=
"memFS:"
+
getBaseDir
()
+
"/fs/test.data"
;
FileUtils
.
createDirectories
(
"memFS:"
+
getBaseDir
()
+
"/fs"
);
File
Object
o
=
FileUtils
.
openFileObject
(
f
,
"rw"
);
o
.
position
(
4000
);
o
.
write
(
new
byte
[
1
],
0
,
1
);
FileLock
lock
=
o
.
tryLock
();
o
.
truncate
(
0
);
File
Channel
c
=
FileUtils
.
open
(
f
,
"rw"
);
c
.
position
(
4000
);
c
.
write
(
ByteBuffer
.
wrap
(
new
byte
[
1
])
);
FileLock
lock
=
c
.
tryLock
();
c
.
truncate
(
0
);
if
(
lock
!=
null
)
{
lock
.
release
();
}
o
.
close
();
c
.
close
();
}
private
void
testSplitDatabaseInZip
()
throws
SQLException
{
...
...
@@ -184,7 +185,7 @@ public class TestFileSystem extends TestBase {
conn
.
close
();
deleteDb
(
"fsJar"
);
for
(
String
f
:
FileUtils
.
listFiles
(
"zip:"
+
getBaseDir
()
+
"/fsJar.zip"
))
{
for
(
String
f
:
FileUtils
.
newDirectoryStream
(
"zip:"
+
getBaseDir
()
+
"/fsJar.zip"
))
{
assertTrue
(
FileUtils
.
isAbsolute
(
f
));
assertTrue
(!
FileUtils
.
isDirectory
(
f
));
assertTrue
(
FileUtils
.
size
(
f
)
>
0
);
...
...
@@ -209,7 +210,7 @@ public class TestFileSystem extends TestBase {
}
private
void
testUserHome
()
{
String
fileName
=
FileUtils
.
getCanonic
alPath
(
"~/test"
);
String
fileName
=
FileUtils
.
toRe
alPath
(
"~/test"
);
String
userDir
=
System
.
getProperty
(
"user.home"
).
replace
(
'\\'
,
'/'
);
assertTrue
(
fileName
.
startsWith
(
userDir
));
}
...
...
@@ -222,55 +223,64 @@ public class TestFileSystem extends TestBase {
private
void
testSimple
(
final
String
fsBase
)
throws
Exception
{
long
time
=
System
.
currentTimeMillis
();
for
(
String
s
:
FileUtils
.
listFiles
(
fsBase
))
{
for
(
String
s
:
FileUtils
.
newDirectoryStream
(
fsBase
))
{
FileUtils
.
delete
(
s
);
}
FileUtils
.
createDirectories
(
fsBase
+
"/test"
);
FileUtils
.
delete
(
fsBase
+
"/test"
);
FileUtils
.
delete
(
fsBase
+
"/test2"
);
assertTrue
(
FileUtils
.
createFile
(
fsBase
+
"/test"
));
List
<
FilePath
>
p
=
FilePath
.
get
(
fsBase
).
listFiles
();
List
<
FilePath
>
p
=
FilePath
.
get
(
fsBase
).
newDirectoryStream
();
assertEquals
(
1
,
p
.
size
());
String
can
=
FilePath
.
get
(
fsBase
+
"/test"
).
getCanonic
alPath
().
toString
();
String
can
=
FilePath
.
get
(
fsBase
+
"/test"
).
toRe
alPath
().
toString
();
assertEquals
(
can
,
p
.
get
(
0
).
toString
());
assertTrue
(
FileUtils
.
canWrite
(
fsBase
+
"/test"
));
File
Object
fo
=
FileUtils
.
openFileObject
(
fsBase
+
"/test"
,
"rw"
);
File
Channel
channel
=
FileUtils
.
open
(
fsBase
+
"/test"
,
"rw"
);
byte
[]
buffer
=
new
byte
[
10000
];
Random
random
=
new
Random
(
1
);
random
.
nextBytes
(
buffer
);
fo
.
write
(
buffer
,
0
,
10000
);
assertEquals
(
10000
,
fo
.
size
());
fo
.
position
(
20000
);
assertEquals
(
20000
,
fo
.
position
());
assert
Throws
(
EOFException
.
class
,
fo
).
readFully
(
buffer
,
0
,
1
);
channel
.
write
(
ByteBuffer
.
wrap
(
buffer
)
);
assertEquals
(
10000
,
channel
.
size
());
channel
.
position
(
20000
);
assertEquals
(
20000
,
channel
.
position
());
assert
Equals
(-
1
,
channel
.
read
(
ByteBuffer
.
wrap
(
buffer
,
0
,
1
))
);
String
path
=
fsBase
+
"/test"
;
assertEquals
(
"test"
,
FileUtils
.
getName
(
path
));
can
=
FilePath
.
get
(
fsBase
).
getCanonic
alPath
().
toString
();
String
can2
=
FileUtils
.
getCanonic
alPath
(
FileUtils
.
getParent
(
path
));
can
=
FilePath
.
get
(
fsBase
).
toRe
alPath
().
toString
();
String
can2
=
FileUtils
.
toRe
alPath
(
FileUtils
.
getParent
(
path
));
assertEquals
(
can
,
can2
);
FileLock
lock
=
fo
.
tryLock
();
FileLock
lock
=
channel
.
tryLock
();
if
(
lock
!=
null
)
{
lock
.
release
();
}
assertEquals
(
10000
,
fo
.
size
());
fo
.
close
();
assertEquals
(
10000
,
channel
.
size
());
channel
.
close
();
assertEquals
(
10000
,
FileUtils
.
size
(
fsBase
+
"/test"
));
fo
=
FileUtils
.
openFileObject
(
fsBase
+
"/test"
,
"r"
);
byte
[]
test
=
new
byte
[
10000
];
fo
.
readFully
(
test
,
0
,
10000
);
channel
=
FileUtils
.
open
(
fsBase
+
"/test"
,
"r"
);
final
byte
[]
test
=
new
byte
[
10000
];
FileUtils
.
readFully
(
channel
,
ByteBuffer
.
wrap
(
test
,
0
,
10000
)
);
assertEquals
(
buffer
,
test
);
assertThrows
(
IOException
.
class
,
fo
).
write
(
test
,
0
,
10
);
assertThrows
(
IOException
.
class
,
fo
).
truncate
(
10
);
fo
.
close
();
final
FileChannel
fc
=
channel
;
new
AssertThrows
(
IOException
.
class
)
{
public
void
test
()
throws
Exception
{
fc
.
write
(
ByteBuffer
.
wrap
(
test
,
0
,
10
));
}
};
new
AssertThrows
(
IOException
.
class
)
{
public
void
test
()
throws
Exception
{
fc
.
truncate
(
10
);
}
};
channel
.
close
();
long
lastMod
=
FileUtils
.
lastModified
(
fsBase
+
"/test"
);
if
(
lastMod
<
time
-
1999
)
{
// at most 2 seconds difference
assertEquals
(
time
,
lastMod
);
}
assertEquals
(
10000
,
FileUtils
.
size
(
fsBase
+
"/test"
));
String
[]
list
=
FileUtils
.
listFiles
(
fsBase
);
assertEquals
(
1
,
list
.
length
);
assertTrue
(
list
[
0
]
.
endsWith
(
"test"
));
List
<
String
>
list
=
FileUtils
.
newDirectoryStream
(
fsBase
);
assertEquals
(
1
,
list
.
size
()
);
assertTrue
(
list
.
get
(
0
)
.
endsWith
(
"test"
));
FileUtils
.
copy
(
fsBase
+
"/test"
,
fsBase
+
"/test3"
);
FileUtils
.
moveTo
(
fsBase
+
"/test3"
,
fsBase
+
"/test2"
);
assertTrue
(!
FileUtils
.
exists
(
fsBase
+
"/test3"
));
...
...
@@ -314,8 +324,8 @@ public class TestFileSystem extends TestBase {
file
.
delete
();
RandomAccessFile
ra
=
new
RandomAccessFile
(
file
,
"rw"
);
FileUtils
.
delete
(
s
);
File
Object
f
=
FileUtils
.
openFileObject
(
s
,
"rw"
);
assert
Throws
(
EOFException
.
class
,
f
).
readFully
(
new
byte
[
1
],
0
,
1
);
File
Channel
f
=
FileUtils
.
open
(
s
,
"rw"
);
assert
Equals
(-
1
,
f
.
read
(
ByteBuffer
.
wrap
(
new
byte
[
1
]))
);
f
.
force
(
true
);
Random
random
=
new
Random
(
seed
);
int
size
=
getSize
(
100
,
500
);
...
...
@@ -337,7 +347,7 @@ public class TestFileSystem extends TestBase {
random
.
nextBytes
(
buffer
);
trace
(
"write "
+
buffer
.
length
);
buff
.
append
(
"write "
+
buffer
.
length
+
"\n"
);
f
.
write
(
buffer
,
0
,
buffer
.
length
);
f
.
write
(
ByteBuffer
.
wrap
(
buffer
)
);
ra
.
write
(
buffer
,
0
,
buffer
.
length
);
break
;
}
...
...
@@ -360,7 +370,11 @@ public class TestFileSystem extends TestBase {
byte
[]
b2
=
new
byte
[
len
];
trace
(
"readFully "
+
len
);
ra
.
readFully
(
b1
,
0
,
len
);
f
.
readFully
(
b2
,
0
,
len
);
try
{
FileUtils
.
readFully
(
f
,
ByteBuffer
.
wrap
(
b2
,
0
,
len
));
}
catch
(
EOFException
e
)
{
e
.
printStackTrace
();
}
buff
.
append
(
"readFully "
+
len
+
"\n"
);
assertEquals
(
b1
,
b2
);
break
;
...
...
@@ -383,7 +397,7 @@ public class TestFileSystem extends TestBase {
f
.
close
();
ra
.
close
();
ra
=
new
RandomAccessFile
(
file
,
"rw"
);
f
=
FileUtils
.
open
FileObject
(
s
,
"rw"
);
f
=
FileUtils
.
open
(
s
,
"rw"
);
assertEquals
(
ra
.
length
(),
f
.
size
());
break
;
}
...
...
h2/src/test/org/h2/test/unit/TestPageStoreCoverage.java
浏览文件 @
b6ad6d6a
...
...
@@ -6,13 +6,13 @@
*/
package
org
.
h2
.
test
.
unit
;
import
java.nio.channels.FileChannel
;
import
java.sql.Connection
;
import
java.sql.ResultSet
;
import
java.sql.SQLException
;
import
java.sql.Statement
;
import
org.h2.constant.ErrorCode
;
import
org.h2.engine.Constants
;
import
org.h2.store.fs.FileObject
;
import
org.h2.store.fs.FileUtils
;
import
org.h2.test.TestBase
;
import
org.h2.tools.Restore
;
...
...
@@ -229,11 +229,11 @@ public class TestPageStoreCoverage extends TestBase {
stat
.
execute
(
"drop table if exists INFORMATION_SCHEMA.LOB_DATA"
);
stat
.
execute
(
"drop table if exists INFORMATION_SCHEMA.LOB_MAP"
);
conn
.
close
();
File
Object
f
=
FileUtils
.
openFileObject
(
fileName
,
"rw"
);
File
Channel
f
=
FileUtils
.
open
(
fileName
,
"rw"
);
// create a new database
conn
=
getConnection
(
"pageStore"
);
conn
.
close
();
f
=
FileUtils
.
open
FileObject
(
fileName
,
"rw"
);
f
=
FileUtils
.
open
(
fileName
,
"rw"
);
f
.
truncate
(
16
);
// create a new database
conn
=
getConnection
(
"pageStore"
);
...
...
h2/src/test/org/h2/test/unit/TestRecovery.java
浏览文件 @
b6ad6d6a
...
...
@@ -9,12 +9,13 @@ package org.h2.test.unit;
import
java.io.ByteArrayOutputStream
;
import
java.io.InputStreamReader
;
import
java.io.PrintStream
;
import
java.nio.ByteBuffer
;
import
java.nio.channels.FileChannel
;
import
java.sql.Connection
;
import
java.sql.ResultSet
;
import
java.sql.SQLException
;
import
java.sql.Statement
;
import
org.h2.engine.Constants
;
import
org.h2.store.fs.FileObject
;
import
org.h2.store.fs.FileUtils
;
import
org.h2.test.TestBase
;
import
org.h2.tools.DeleteDbFiles
;
...
...
@@ -134,14 +135,14 @@ public class TestRecovery extends TestBase {
Statement
stat
=
conn
.
createStatement
();
stat
.
execute
(
"create table test(id int, name varchar) as select 1, 'Hello World1'"
);
conn
.
close
();
File
Object
f
=
FileUtils
.
openFileObject
(
getBaseDir
()
+
"/recovery.h2.db"
,
"rw"
);
File
Channel
f
=
FileUtils
.
open
(
getBaseDir
()
+
"/recovery.h2.db"
,
"rw"
);
byte
[]
buff
=
new
byte
[
Constants
.
DEFAULT_PAGE_SIZE
];
while
(
f
.
position
()
<
f
.
size
())
{
f
.
readFully
(
buff
,
0
,
buff
.
length
);
FileUtils
.
readFully
(
f
,
ByteBuffer
.
wrap
(
buff
)
);
if
(
new
String
(
buff
).
indexOf
(
"Hello World1"
)
>=
0
)
{
buff
[
buff
.
length
-
1
]++;
f
.
position
(
f
.
position
()
-
buff
.
length
);
f
.
write
(
buff
,
0
,
buff
.
length
);
f
.
write
(
ByteBuffer
.
wrap
(
buff
)
);
}
}
f
.
close
();
...
...
h2/src/test/org/h2/test/utils/FileDebug.java
deleted
100644 → 0
浏览文件 @
fa398730
/*
* Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License,
* Version 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package
org
.
h2
.
test
.
utils
;
import
java.io.IOException
;
import
java.nio.channels.FileLock
;
import
org.h2.store.fs.FileObject
;
/**
* A debugging file that logs all operations.
*/
public
class
FileDebug
implements
FileObject
{
private
final
FilePathDebug
fs
;
private
final
FileObject
file
;
private
final
String
name
;
FileDebug
(
FilePathDebug
fs
,
FileObject
file
,
String
name
)
{
this
.
fs
=
fs
;
this
.
file
=
file
;
this
.
name
=
fs
.
getScheme
()
+
":"
+
name
;
}
public
void
close
()
throws
IOException
{
debug
(
"close"
);
file
.
close
();
}
public
long
position
()
throws
IOException
{
debug
(
"getFilePointer"
);
return
file
.
position
();
}
public
long
size
()
throws
IOException
{
debug
(
"length"
);
return
file
.
size
();
}
public
void
readFully
(
byte
[]
b
,
int
off
,
int
len
)
throws
IOException
{
debug
(
"readFully"
,
file
.
position
(),
off
,
len
);
file
.
readFully
(
b
,
off
,
len
);
}
public
void
position
(
long
pos
)
throws
IOException
{
debug
(
"seek"
,
pos
);
file
.
position
(
pos
);
}
public
void
truncate
(
long
newLength
)
throws
IOException
{
checkPowerOff
();
debug
(
"truncate"
,
newLength
);
file
.
truncate
(
newLength
);
}
public
void
force
(
boolean
metaData
)
throws
IOException
{
debug
(
"force"
);
file
.
force
(
metaData
);
}
public
void
write
(
byte
[]
b
,
int
off
,
int
len
)
throws
IOException
{
checkPowerOff
();
debug
(
"write"
,
file
.
position
(),
off
,
len
);
file
.
write
(
b
,
off
,
len
);
}
private
void
debug
(
String
method
,
Object
...
params
)
{
fs
.
trace
(
name
,
method
,
params
);
}
private
void
checkPowerOff
()
throws
IOException
{
try
{
fs
.
checkPowerOff
();
}
catch
(
IOException
e
)
{
try
{
file
.
close
();
}
catch
(
IOException
e2
)
{
// ignore
}
throw
e
;
}
}
public
FileLock
tryLock
()
throws
IOException
{
debug
(
"tryLock"
);
return
file
.
tryLock
();
}
}
\ No newline at end of file
h2/src/test/org/h2/test/utils/FilePathDebug.java
浏览文件 @
b6ad6d6a
...
...
@@ -10,8 +10,11 @@ import java.io.FilterInputStream;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.io.OutputStream
;
import
java.nio.ByteBuffer
;
import
java.nio.channels.FileChannel
;
import
java.nio.channels.FileLock
;
import
java.util.List
;
import
org.h2.store.fs.File
Object
;
import
org.h2.store.fs.File
Base
;
import
org.h2.store.fs.FilePath
;
import
org.h2.store.fs.FilePathWrapper
;
...
...
@@ -116,14 +119,14 @@ public class FilePathDebug extends FilePathWrapper {
return
super
.
size
();
}
public
List
<
FilePath
>
listFiles
()
{
trace
(
name
,
"
listFiles
"
);
return
super
.
listFiles
();
public
List
<
FilePath
>
newDirectoryStream
()
{
trace
(
name
,
"
newDirectoryStream
"
);
return
super
.
newDirectoryStream
();
}
public
FilePath
getCanonic
alPath
()
{
trace
(
name
,
"
getCanonic
alPath"
);
return
super
.
getCanonic
alPath
();
public
FilePath
toRe
alPath
()
{
trace
(
name
,
"
toRe
alPath"
);
return
super
.
toRe
alPath
();
}
public
InputStream
newInputStream
()
throws
IOException
{
...
...
@@ -151,9 +154,9 @@ public class FilePathDebug extends FilePathWrapper {
};
}
public
File
Object
openFileObject
(
String
mode
)
throws
IOException
{
trace
(
name
,
"open
FileObject
"
,
mode
);
return
new
FileDebug
(
this
,
super
.
open
FileObject
(
mode
),
name
);
public
File
Channel
open
(
String
mode
)
throws
IOException
{
trace
(
name
,
"open"
,
mode
);
return
new
FileDebug
(
this
,
super
.
open
(
mode
),
name
);
}
public
OutputStream
newOutputStream
(
boolean
append
)
{
...
...
@@ -211,3 +214,86 @@ public class FilePathDebug extends FilePathWrapper {
}
}
/**
* A debugging file that logs all operations.
*/
class
FileDebug
extends
FileBase
{
private
final
FilePathDebug
debug
;
private
final
FileChannel
channel
;
private
final
String
name
;
FileDebug
(
FilePathDebug
debug
,
FileChannel
channel
,
String
name
)
{
this
.
debug
=
debug
;
this
.
channel
=
channel
;
this
.
name
=
debug
.
getScheme
()
+
":"
+
name
;
}
public
void
implCloseChannel
()
throws
IOException
{
debug
(
"close"
);
channel
.
close
();
}
public
long
position
()
throws
IOException
{
debug
(
"getFilePointer"
);
return
channel
.
position
();
}
public
long
size
()
throws
IOException
{
debug
(
"length"
);
return
channel
.
size
();
}
public
int
read
(
ByteBuffer
dst
)
throws
IOException
{
debug
(
"read"
,
channel
.
position
(),
dst
.
position
(),
dst
.
remaining
());
return
channel
.
read
(
dst
);
}
public
FileChannel
position
(
long
pos
)
throws
IOException
{
debug
(
"seek"
,
pos
);
channel
.
position
(
pos
);
return
this
;
}
public
FileChannel
truncate
(
long
newLength
)
throws
IOException
{
checkPowerOff
();
debug
(
"truncate"
,
newLength
);
channel
.
truncate
(
newLength
);
return
this
;
}
public
void
force
(
boolean
metaData
)
throws
IOException
{
debug
(
"force"
);
channel
.
force
(
metaData
);
}
public
int
write
(
ByteBuffer
src
)
throws
IOException
{
checkPowerOff
();
debug
(
"write"
,
channel
.
position
(),
src
.
position
(),
src
.
remaining
());
return
channel
.
write
(
src
);
}
private
void
debug
(
String
method
,
Object
...
params
)
{
debug
.
trace
(
name
,
method
,
params
);
}
private
void
checkPowerOff
()
throws
IOException
{
try
{
debug
.
checkPowerOff
();
}
catch
(
IOException
e
)
{
try
{
channel
.
close
();
}
catch
(
IOException
e2
)
{
// ignore
}
throw
e
;
}
}
public
synchronized
FileLock
tryLock
(
long
position
,
long
size
,
boolean
shared
)
throws
IOException
{
debug
(
"tryLock"
);
return
channel
.
tryLock
();
}
}
h2/src/tools/org/h2/dev/fs/FileObjectCrypt.java
deleted
100644 → 0
浏览文件 @
fa398730
/*
* Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License,
* Version 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package
org
.
h2
.
dev
.
fs
;
import
java.io.EOFException
;
import
java.io.IOException
;
import
java.nio.channels.FileLock
;
import
org.h2.engine.Constants
;
import
org.h2.security.BlockCipher
;
import
org.h2.security.CipherFactory
;
import
org.h2.security.SHA256
;
import
org.h2.store.fs.FileObject
;
import
org.h2.util.MathUtils
;
import
org.h2.util.StringUtils
;
/**
* An encrypted file.
*/
public
class
FileObjectCrypt
implements
FileObject
{
static
final
int
HEADER_LENGTH
=
4096
;
static
final
int
BLOCK_SIZE
=
Constants
.
FILE_BLOCK_SIZE
;
// TODO improve the header
// TODO store the number of empty blocks in the last block
private
static
final
byte
[]
HEADER
=
"-- H2 crypt --\n\0"
.
getBytes
();
private
static
final
int
SALT_POS
=
HEADER
.
length
;
private
static
final
int
SALT_LENGTH
=
16
;
private
static
final
int
HASH_ITERATIONS
=
Constants
.
ENCRYPTION_KEY_HASH_ITERATIONS
;
private
final
String
name
;
private
final
FileObject
file
;
private
final
BlockCipher
cipher
,
cipherForInitVector
;
private
byte
[]
bufferForInitVector
;
public
FileObjectCrypt
(
String
name
,
String
algorithm
,
String
password
,
FileObject
file
)
throws
IOException
{
this
.
name
=
name
;
this
.
file
=
file
;
boolean
newFile
=
file
.
size
()
<
HEADER_LENGTH
+
BLOCK_SIZE
;
byte
[]
filePasswordHash
;
if
(
algorithm
.
endsWith
(
"-hash"
))
{
filePasswordHash
=
StringUtils
.
convertHexToBytes
(
password
);
algorithm
=
algorithm
.
substring
(
0
,
algorithm
.
length
()
-
"-hash"
.
length
());
}
else
{
filePasswordHash
=
SHA256
.
getKeyPasswordHash
(
"file"
,
password
.
toCharArray
());
}
cipher
=
CipherFactory
.
getBlockCipher
(
algorithm
);
cipherForInitVector
=
CipherFactory
.
getBlockCipher
(
algorithm
);
int
keyIterations
=
HASH_ITERATIONS
;
byte
[]
salt
;
if
(
newFile
)
{
salt
=
MathUtils
.
secureRandomBytes
(
SALT_LENGTH
);
file
.
write
(
HEADER
,
0
,
HEADER
.
length
);
file
.
position
(
SALT_POS
);
file
.
write
(
salt
,
0
,
salt
.
length
);
}
else
{
salt
=
new
byte
[
SALT_LENGTH
];
file
.
position
(
SALT_POS
);
file
.
readFully
(
salt
,
0
,
SALT_LENGTH
);
}
byte
[]
key
=
SHA256
.
getHashWithSalt
(
filePasswordHash
,
salt
);
for
(
int
i
=
0
;
i
<
keyIterations
;
i
++)
{
key
=
SHA256
.
getHash
(
key
,
true
);
}
cipher
.
setKey
(
key
);
bufferForInitVector
=
new
byte
[
BLOCK_SIZE
];
position
(
0
);
}
public
long
position
()
throws
IOException
{
return
Math
.
max
(
0
,
file
.
position
()
-
HEADER_LENGTH
);
}
public
long
size
()
throws
IOException
{
return
Math
.
max
(
0
,
file
.
size
()
-
HEADER_LENGTH
-
BLOCK_SIZE
);
}
public
void
position
(
long
pos
)
throws
IOException
{
file
.
position
(
pos
+
HEADER_LENGTH
);
}
public
void
force
(
boolean
metaData
)
throws
IOException
{
file
.
force
(
metaData
);
}
public
FileLock
tryLock
()
throws
IOException
{
return
file
.
tryLock
();
}
public
void
close
()
throws
IOException
{
file
.
close
();
}
public
void
truncate
(
long
newLength
)
throws
IOException
{
if
(
newLength
>=
size
())
{
return
;
}
int
mod
=
(
int
)
(
newLength
%
BLOCK_SIZE
);
if
(
mod
==
0
)
{
file
.
truncate
(
HEADER_LENGTH
+
newLength
);
}
else
{
file
.
truncate
(
HEADER_LENGTH
+
newLength
+
BLOCK_SIZE
-
mod
);
byte
[]
buff
=
new
byte
[
BLOCK_SIZE
-
mod
];
long
pos
=
position
();
position
(
newLength
);
write
(
buff
,
0
,
buff
.
length
);
position
(
pos
);
}
file
.
truncate
(
HEADER_LENGTH
+
newLength
+
BLOCK_SIZE
);
if
(
newLength
<
position
())
{
position
(
newLength
);
}
}
public
void
readFully
(
byte
[]
b
,
int
off
,
int
len
)
throws
IOException
{
long
pos
=
position
();
long
length
=
size
();
if
(
pos
+
len
>
length
)
{
throw
new
EOFException
(
"pos: "
+
pos
+
" len: "
+
len
+
" length: "
+
length
);
}
int
posMod
=
(
int
)
(
pos
%
BLOCK_SIZE
);
if
(
posMod
==
0
&&
len
%
BLOCK_SIZE
==
0
)
{
readAligned
(
pos
,
b
,
off
,
len
);
}
else
{
long
p
=
pos
-
posMod
;
int
l
=
len
;
if
(
posMod
!=
0
)
{
l
+=
posMod
;
}
l
=
MathUtils
.
roundUpInt
(
l
,
BLOCK_SIZE
);
position
(
p
);
byte
[]
temp
=
new
byte
[
l
];
try
{
readAligned
(
p
,
temp
,
0
,
l
);
System
.
arraycopy
(
temp
,
posMod
,
b
,
off
,
len
);
}
finally
{
position
(
pos
+
len
);
}
}
}
public
void
write
(
byte
[]
b
,
int
off
,
int
len
)
throws
IOException
{
long
pos
=
position
();
int
posMod
=
(
int
)
(
pos
%
BLOCK_SIZE
);
if
(
posMod
==
0
&&
len
%
BLOCK_SIZE
==
0
)
{
byte
[]
temp
=
new
byte
[
len
];
System
.
arraycopy
(
b
,
off
,
temp
,
0
,
len
);
writeAligned
(
pos
,
temp
,
0
,
len
);
}
else
{
long
p
=
pos
-
posMod
;
int
l
=
len
;
if
(
posMod
!=
0
)
{
l
+=
posMod
;
}
l
=
MathUtils
.
roundUpInt
(
l
,
BLOCK_SIZE
);
position
(
p
);
byte
[]
temp
=
new
byte
[
l
];
if
(
file
.
size
()
<
HEADER_LENGTH
+
p
+
l
)
{
file
.
position
(
HEADER_LENGTH
+
p
+
l
-
1
);
file
.
write
(
new
byte
[
1
],
0
,
1
);
position
(
p
);
}
readAligned
(
p
,
temp
,
0
,
l
);
System
.
arraycopy
(
b
,
off
,
temp
,
posMod
,
len
);
position
(
p
);
try
{
writeAligned
(
p
,
temp
,
0
,
l
);
}
finally
{
position
(
pos
+
len
);
}
}
pos
=
file
.
position
();
if
(
file
.
size
()
<
pos
+
BLOCK_SIZE
)
{
file
.
position
(
pos
+
BLOCK_SIZE
-
1
);
file
.
write
(
new
byte
[
1
],
0
,
1
);
file
.
position
(
pos
);
}
}
private
void
readAligned
(
long
pos
,
byte
[]
b
,
int
off
,
int
len
)
throws
IOException
{
file
.
readFully
(
b
,
off
,
len
);
for
(
int
p
=
0
;
p
<
len
;
p
+=
BLOCK_SIZE
)
{
for
(
int
i
=
0
;
i
<
BLOCK_SIZE
;
i
++)
{
// empty blocks are not decrypted
if
(
b
[
p
+
off
+
i
]
!=
0
)
{
cipher
.
decrypt
(
b
,
p
+
off
,
BLOCK_SIZE
);
xorInitVector
(
b
,
p
+
off
,
BLOCK_SIZE
,
p
+
pos
);
break
;
}
}
}
}
private
void
writeAligned
(
long
pos
,
byte
[]
b
,
int
off
,
int
len
)
throws
IOException
{
for
(
int
p
=
0
;
p
<
len
;
p
+=
BLOCK_SIZE
)
{
for
(
int
i
=
0
;
i
<
BLOCK_SIZE
;
i
++)
{
// empty blocks are not decrypted
if
(
b
[
p
+
off
+
i
]
!=
0
)
{
xorInitVector
(
b
,
p
+
off
,
BLOCK_SIZE
,
p
+
pos
);
cipher
.
encrypt
(
b
,
p
+
off
,
BLOCK_SIZE
);
break
;
}
}
}
file
.
write
(
b
,
off
,
len
);
}
private
void
xorInitVector
(
byte
[]
b
,
int
off
,
int
len
,
long
p
)
{
byte
[]
iv
=
bufferForInitVector
;
while
(
len
>
0
)
{
for
(
int
i
=
0
;
i
<
BLOCK_SIZE
;
i
+=
8
)
{
long
block
=
(
p
+
i
)
>>>
3
;
iv
[
i
]
=
(
byte
)
(
block
>>
56
);
iv
[
i
+
1
]
=
(
byte
)
(
block
>>
48
);
iv
[
i
+
2
]
=
(
byte
)
(
block
>>
40
);
iv
[
i
+
3
]
=
(
byte
)
(
block
>>
32
);
iv
[
i
+
4
]
=
(
byte
)
(
block
>>
24
);
iv
[
i
+
5
]
=
(
byte
)
(
block
>>
16
);
iv
[
i
+
6
]
=
(
byte
)
(
block
>>
8
);
iv
[
i
+
7
]
=
(
byte
)
block
;
}
cipherForInitVector
.
encrypt
(
iv
,
0
,
BLOCK_SIZE
);
for
(
int
i
=
0
;
i
<
BLOCK_SIZE
;
i
++)
{
b
[
off
+
i
]
^=
iv
[
i
];
}
p
+=
BLOCK_SIZE
;
off
+=
BLOCK_SIZE
;
len
-=
BLOCK_SIZE
;
}
}
public
String
toString
()
{
return
name
;
}
}
h2/src/tools/org/h2/dev/fs/FileObjectZip2.java
deleted
100644 → 0
浏览文件 @
fa398730
/*
* Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License,
* Version 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package
org
.
h2
.
dev
.
fs
;
import
java.io.EOFException
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.nio.channels.FileLock
;
import
java.util.zip.ZipInputStream
;
import
org.h2.store.fs.FileObject
;
import
org.h2.store.fs.FileUtils
;
import
org.h2.util.IOUtils
;
/**
* The file is read from a stream. When reading from start to end, the same
* input stream is re-used, however when reading from end to start, a new input
* stream is opened for each request.
*/
public
class
FileObjectZip2
implements
FileObject
{
private
static
final
byte
[]
SKIP_BUFFER
=
new
byte
[
1024
];
private
final
String
fullName
;
private
final
String
name
;
private
final
long
length
;
private
long
pos
;
private
InputStream
in
;
private
long
inPos
;
private
boolean
skipUsingRead
;
FileObjectZip2
(
String
fullName
,
String
name
,
ZipInputStream
in
,
long
length
)
{
this
.
fullName
=
fullName
;
this
.
name
=
name
;
this
.
length
=
length
;
this
.
in
=
in
;
}
public
void
close
()
{
try
{
in
.
close
();
}
catch
(
IOException
e
)
{
// ignore
}
}
public
long
position
()
{
return
pos
;
}
public
long
size
()
{
return
length
;
}
public
void
readFully
(
byte
[]
b
,
int
off
,
int
len
)
throws
IOException
{
if
(
inPos
>
pos
)
{
if
(
in
!=
null
)
{
in
.
close
();
}
in
=
null
;
}
if
(
in
==
null
)
{
in
=
FileUtils
.
newInputStream
(
fullName
);
inPos
=
0
;
}
if
(
inPos
<
pos
)
{
long
skip
=
pos
-
inPos
;
if
(!
skipUsingRead
)
{
try
{
IOUtils
.
skipFully
(
in
,
skip
);
}
catch
(
NullPointerException
e
)
{
// workaround for Android
skipUsingRead
=
true
;
}
}
if
(
skipUsingRead
)
{
while
(
skip
>
0
)
{
int
s
=
(
int
)
Math
.
min
(
SKIP_BUFFER
.
length
,
skip
);
s
=
in
.
read
(
SKIP_BUFFER
,
0
,
s
);
skip
-=
s
;
}
}
inPos
=
pos
;
}
int
l
=
IOUtils
.
readFully
(
in
,
b
,
off
,
len
);
if
(
l
!=
len
)
{
throw
new
EOFException
();
}
pos
+=
len
;
inPos
+=
len
;
}
public
void
position
(
long
newPos
)
{
this
.
pos
=
newPos
;
}
public
void
truncate
(
long
newLength
)
throws
IOException
{
throw
new
IOException
(
"File is read-only"
);
}
public
void
force
(
boolean
metaData
)
throws
IOException
{
// nothing to do
}
public
void
write
(
byte
[]
b
,
int
off
,
int
len
)
throws
IOException
{
throw
new
IOException
(
"File is read-only"
);
}
public
FileLock
tryLock
()
{
return
null
;
}
public
String
toString
()
{
return
name
;
}
}
h2/src/tools/org/h2/dev/fs/FilePathCrypt.java
浏览文件 @
b6ad6d6a
差异被折叠。
点击展开。
h2/src/tools/org/h2/dev/fs/FilePathZip2.java
浏览文件 @
b6ad6d6a
...
...
@@ -10,16 +10,20 @@ import java.io.FileNotFoundException;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.io.OutputStream
;
import
java.nio.ByteBuffer
;
import
java.nio.channels.FileChannel
;
import
java.nio.channels.FileLock
;
import
java.util.ArrayList
;
import
java.util.zip.ZipEntry
;
import
java.util.zip.ZipInputStream
;
import
org.h2.engine.Constants
;
import
org.h2.message.DbException
;
import
org.h2.store.fs.File
Object
;
import
org.h2.store.fs.File
Object
InputStream
;
import
org.h2.store.fs.File
Base
;
import
org.h2.store.fs.File
Channel
InputStream
;
import
org.h2.store.fs.FilePath
;
import
org.h2.store.fs.FilePathDisk
;
import
org.h2.store.fs.FileUtils
;
import
org.h2.util.IOUtils
;
import
org.h2.util.New
;
/**
...
...
@@ -184,7 +188,7 @@ public class FilePathZip2 extends FilePath {
}
}
public
ArrayList
<
FilePath
>
listFiles
()
{
public
ArrayList
<
FilePath
>
newDirectoryStream
()
{
String
path
=
name
;
try
{
if
(
path
.
indexOf
(
'!'
)
<
0
)
{
...
...
@@ -218,16 +222,15 @@ public class FilePathZip2 extends FilePath {
}
}
public
FilePath
getCanonic
alPath
()
{
public
FilePath
toRe
alPath
()
{
return
this
;
}
public
InputStream
newInputStream
()
throws
IOException
{
FileObject
file
=
openFileObject
(
"r"
);
return
new
FileObjectInputStream
(
file
);
return
new
FileChannelInputStream
(
open
(
"r"
));
}
public
File
Object
openFileObject
(
String
mode
)
throws
IOException
{
public
File
Channel
open
(
String
mode
)
throws
IOException
{
String
entryName
=
getEntryName
();
if
(
entryName
.
length
()
==
0
)
{
throw
new
FileNotFoundException
();
...
...
@@ -239,7 +242,7 @@ public class FilePathZip2 extends FilePath {
break
;
}
if
(
entry
.
getName
().
equals
(
entryName
))
{
return
new
File
Object
Zip2
(
name
,
entryName
,
in
,
size
());
return
new
FileZip2
(
name
,
entryName
,
in
,
size
());
}
in
.
closeEntry
();
}
...
...
@@ -301,4 +304,114 @@ public class FilePathZip2 extends FilePath {
return
"zip2"
;
}
}
/**
* The file is read from a stream. When reading from start to end, the same
* input stream is re-used, however when reading from end to start, a new input
* stream is opened for each request.
*/
class
FileZip2
extends
FileBase
{
private
static
final
byte
[]
SKIP_BUFFER
=
new
byte
[
1024
];
private
final
String
fullName
;
private
final
String
name
;
private
final
long
length
;
private
long
pos
;
private
InputStream
in
;
private
long
inPos
;
private
boolean
skipUsingRead
;
FileZip2
(
String
fullName
,
String
name
,
ZipInputStream
in
,
long
length
)
{
this
.
fullName
=
fullName
;
this
.
name
=
name
;
this
.
length
=
length
;
this
.
in
=
in
;
}
public
void
implCloseChannel
()
throws
IOException
{
try
{
in
.
close
();
}
catch
(
IOException
e
)
{
// ignore
}
}
public
long
position
()
{
return
pos
;
}
public
long
size
()
{
return
length
;
}
public
int
read
(
ByteBuffer
dst
)
throws
IOException
{
seek
();
int
len
=
in
.
read
(
dst
.
array
(),
dst
.
position
(),
dst
.
remaining
());
if
(
len
>
0
)
{
dst
.
position
(
dst
.
position
()
+
len
);
pos
+=
len
;
inPos
+=
len
;
}
return
len
;
}
private
void
seek
()
throws
IOException
{
if
(
inPos
>
pos
)
{
if
(
in
!=
null
)
{
in
.
close
();
}
in
=
null
;
}
if
(
in
==
null
)
{
in
=
FileUtils
.
newInputStream
(
fullName
);
inPos
=
0
;
}
if
(
inPos
<
pos
)
{
long
skip
=
pos
-
inPos
;
if
(!
skipUsingRead
)
{
try
{
IOUtils
.
skipFully
(
in
,
skip
);
}
catch
(
NullPointerException
e
)
{
// workaround for Android
skipUsingRead
=
true
;
}
}
if
(
skipUsingRead
)
{
while
(
skip
>
0
)
{
int
s
=
(
int
)
Math
.
min
(
SKIP_BUFFER
.
length
,
skip
);
s
=
in
.
read
(
SKIP_BUFFER
,
0
,
s
);
skip
-=
s
;
}
}
inPos
=
pos
;
}
}
public
FileChannel
position
(
long
newPos
)
{
this
.
pos
=
newPos
;
return
this
;
}
public
FileChannel
truncate
(
long
newLength
)
throws
IOException
{
throw
new
IOException
(
"File is read-only"
);
}
public
void
force
(
boolean
metaData
)
throws
IOException
{
// nothing to do
}
public
int
write
(
ByteBuffer
src
)
throws
IOException
{
throw
new
IOException
(
"File is read-only"
);
}
public
synchronized
FileLock
tryLock
(
long
position
,
long
size
,
boolean
shared
)
throws
IOException
{
return
null
;
}
public
String
toString
()
{
return
name
;
}
}
\ No newline at end of file
h2/src/tools/org/h2/dev/fs/FileShell.java
浏览文件 @
b6ad6d6a
...
...
@@ -14,6 +14,7 @@ import java.io.InputStream;
import
java.io.InputStreamReader
;
import
java.io.OutputStream
;
import
java.io.PrintStream
;
import
java.nio.channels.FileChannel
;
import
java.sql.SQLException
;
import
java.sql.Timestamp
;
import
java.util.ArrayList
;
...
...
@@ -24,7 +25,6 @@ import org.h2.command.dml.BackupCommand;
import
org.h2.constant.SysProperties
;
import
org.h2.engine.Constants
;
import
org.h2.message.DbException
;
import
org.h2.store.fs.FileObject
;
import
org.h2.store.fs.FileUtils
;
import
org.h2.util.IOUtils
;
import
org.h2.util.New
;
...
...
@@ -127,7 +127,7 @@ public class FileShell extends Tool {
if
(
reader
==
null
)
{
reader
=
new
BufferedReader
(
new
InputStreamReader
(
in
));
}
println
(
FileUtils
.
getCanonic
alPath
(
currentWorkingDirectory
));
println
(
FileUtils
.
toRe
alPath
(
currentWorkingDirectory
));
while
(
true
)
{
try
{
print
(
"> "
);
...
...
@@ -212,7 +212,7 @@ public class FileShell extends Tool {
}
end
(
list
,
i
);
println
(
dir
);
for
(
String
file
:
FileUtils
.
listFiles
(
dir
))
{
for
(
String
file
:
FileUtils
.
newDirectoryStream
(
dir
))
{
StringBuilder
buff
=
new
StringBuilder
();
buff
.
append
(
FileUtils
.
isDirectory
(
file
)
?
"d"
:
"-"
);
buff
.
append
(
FileUtils
.
canWrite
(
file
)
?
"rw"
:
"r-"
);
...
...
@@ -236,7 +236,7 @@ public class FileShell extends Tool {
FileUtils
.
moveTo
(
source
,
target
);
}
else
if
(
"pwd"
.
equals
(
c
))
{
end
(
list
,
i
);
println
(
FileUtils
.
getCanonic
alPath
(
currentWorkingDirectory
));
println
(
FileUtils
.
toRe
alPath
(
currentWorkingDirectory
));
}
else
if
(
"rm"
.
equals
(
c
))
{
if
(
"-r"
.
equals
(
list
[
i
]))
{
i
++;
...
...
@@ -311,9 +311,9 @@ public class FileShell extends Tool {
}
private
void
truncate
(
String
fileName
,
long
length
)
{
File
Object
f
=
null
;
File
Channel
f
=
null
;
try
{
f
=
FileUtils
.
open
FileObject
(
fileName
,
"rw"
);
f
=
FileUtils
.
open
(
fileName
,
"rw"
);
f
.
truncate
(
length
);
}
catch
(
IOException
e
)
{
error
(
e
);
...
...
@@ -340,7 +340,7 @@ public class FileShell extends Tool {
fileOut
=
FileUtils
.
newOutputStream
(
zipFileName
,
false
);
ZipOutputStream
zipOut
=
new
ZipOutputStream
(
fileOut
);
for
(
String
fileName
:
source
)
{
String
f
=
FileUtils
.
getCanonic
alPath
(
fileName
);
String
f
=
FileUtils
.
toRe
alPath
(
fileName
);
if
(!
f
.
startsWith
(
base
))
{
DbException
.
throwInternalError
(
f
+
" does not start with "
+
base
);
}
...
...
@@ -432,7 +432,7 @@ public class FileShell extends Tool {
private
void
addFilesRecursive
(
String
f
,
ArrayList
<
String
>
target
)
{
if
(
FileUtils
.
isDirectory
(
f
))
{
for
(
String
c
:
FileUtils
.
listFiles
(
f
))
{
for
(
String
c
:
FileUtils
.
newDirectoryStream
(
f
))
{
addFilesRecursive
(
c
,
target
);
}
}
else
{
...
...
@@ -447,7 +447,7 @@ public class FileShell extends Tool {
String
unwrapped
=
FileUtils
.
unwrap
(
f
);
String
prefix
=
f
.
substring
(
0
,
f
.
length
()
-
unwrapped
.
length
());
f
=
prefix
+
currentWorkingDirectory
+
SysProperties
.
FILE_SEPARATOR
+
unwrapped
;
return
FileUtils
.
getCanonic
alPath
(
f
);
return
FileUtils
.
toRe
alPath
(
f
);
}
private
void
showHelp
()
{
...
...
h2/src/tools/org/h2/dev/ftp/server/FtpServer.java
浏览文件 @
b6ad6d6a
...
...
@@ -292,7 +292,7 @@ public class FtpServer extends Tool implements Service {
*/
String
getDirectoryListing
(
String
directory
,
boolean
listDirectories
)
{
StringBuilder
buff
=
new
StringBuilder
();
for
(
String
fileName
:
FileUtils
.
listFiles
(
directory
))
{
for
(
String
fileName
:
FileUtils
.
newDirectoryStream
(
directory
))
{
if
(!
FileUtils
.
isDirectory
(
fileName
)
||
(
FileUtils
.
isDirectory
(
fileName
)
&&
listDirectories
))
{
appendFile
(
buff
,
fileName
);
}
...
...
@@ -327,7 +327,7 @@ public class FtpServer extends Tool implements Service {
if
(
"-ftpPort"
.
equals
(
a
))
{
port
=
Integer
.
decode
(
args
[++
i
]);
}
else
if
(
"-ftpDir"
.
equals
(
a
))
{
root
=
FileUtils
.
getCanonic
alPath
(
args
[++
i
]);
root
=
FileUtils
.
toRe
alPath
(
args
[++
i
]);
}
else
if
(
"-ftpRead"
.
equals
(
a
))
{
readUserName
=
args
[++
i
];
}
else
if
(
"-ftpWrite"
.
equals
(
a
))
{
...
...
@@ -351,7 +351,7 @@ public class FtpServer extends Tool implements Service {
}
public
void
start
()
{
root
=
FileUtils
.
getCanonic
alPath
(
root
);
root
=
FileUtils
.
toRe
alPath
(
root
);
FileUtils
.
createDirectories
(
root
);
serverSocket
=
NetUtils
.
createServerSocket
(
port
,
false
);
port
=
serverSocket
.
getLocalPort
();
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论