Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
b6ad6d6a
提交
b6ad6d6a
authored
13 年前
作者:
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
...
@@ -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>
.
<code>
jdbc:h2:nio:~/test
</code>
.
</p>
</p>
<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.
and call the method
<code>
FilePath.register
</code>
before using it.
</p>
</p>
<p>
<p>
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/command/dml/BackupCommand.java
浏览文件 @
b6ad6d6a
...
@@ -101,8 +101,8 @@ public class BackupCommand extends Prepared {
...
@@ -101,8 +101,8 @@ public class BackupCommand extends Prepared {
}
}
private
static
void
backupFile
(
ZipOutputStream
out
,
String
base
,
String
fn
)
throws
IOException
{
private
static
void
backupFile
(
ZipOutputStream
out
,
String
base
,
String
fn
)
throws
IOException
{
String
f
=
FileUtils
.
getCanonic
alPath
(
fn
);
String
f
=
FileUtils
.
toRe
alPath
(
fn
);
base
=
FileUtils
.
getCanonic
alPath
(
base
);
base
=
FileUtils
.
toRe
alPath
(
base
);
if
(!
f
.
startsWith
(
base
))
{
if
(!
f
.
startsWith
(
base
))
{
DbException
.
throwInternalError
(
f
+
" does not start with "
+
base
);
DbException
.
throwInternalError
(
f
+
" does not start with "
+
base
);
}
}
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/engine/ConnectionInfo.java
浏览文件 @
b6ad6d6a
...
@@ -159,7 +159,7 @@ public class ConnectionInfo implements Cloneable {
...
@@ -159,7 +159,7 @@ public class ConnectionInfo implements Cloneable {
*/
*/
public
void
setBaseDir
(
String
dir
)
{
public
void
setBaseDir
(
String
dir
)
{
if
(
persistent
)
{
if
(
persistent
)
{
String
absDir
=
FileUtils
.
unwrap
(
FileUtils
.
getCanonic
alPath
(
dir
));
String
absDir
=
FileUtils
.
unwrap
(
FileUtils
.
toRe
alPath
(
dir
));
boolean
absolute
=
FileUtils
.
isAbsolute
(
name
);
boolean
absolute
=
FileUtils
.
isAbsolute
(
name
);
String
n
;
String
n
;
String
prefix
=
null
;
String
prefix
=
null
;
...
@@ -170,7 +170,7 @@ public class ConnectionInfo implements Cloneable {
...
@@ -170,7 +170,7 @@ public class ConnectionInfo implements Cloneable {
prefix
=
name
.
substring
(
0
,
name
.
length
()
-
n
.
length
());
prefix
=
name
.
substring
(
0
,
name
.
length
()
-
n
.
length
());
n
=
dir
+
SysProperties
.
FILE_SEPARATOR
+
n
;
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
))
{
if
(
normalizedName
.
equals
(
absDir
)
||
!
normalizedName
.
startsWith
(
absDir
))
{
throw
DbException
.
get
(
ErrorCode
.
IO_EXCEPTION_1
,
normalizedName
+
" outside "
+
throw
DbException
.
get
(
ErrorCode
.
IO_EXCEPTION_1
,
normalizedName
+
" outside "
+
absDir
);
absDir
);
...
@@ -364,7 +364,7 @@ public class ConnectionInfo implements Cloneable {
...
@@ -364,7 +364,7 @@ public class ConnectionInfo implements Cloneable {
if
(
persistent
)
{
if
(
persistent
)
{
if
(
nameNormalized
==
null
)
{
if
(
nameNormalized
==
null
)
{
String
suffix
=
Constants
.
SUFFIX_PAGE_FILE
;
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
);
String
fileName
=
FileUtils
.
getName
(
n
);
if
(
fileName
.
length
()
<
suffix
.
length
()
+
1
)
{
if
(
fileName
.
length
()
<
suffix
.
length
()
+
1
)
{
throw
DbException
.
get
(
ErrorCode
.
INVALID_DATABASE_NAME_1
,
name
);
throw
DbException
.
get
(
ErrorCode
.
INVALID_DATABASE_NAME_1
,
name
);
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/engine/Database.java
浏览文件 @
b6ad6d6a
...
@@ -1348,7 +1348,7 @@ public class Database implements DataHandler {
...
@@ -1348,7 +1348,7 @@ public class Database implements DataHandler {
public
String
getDatabasePath
()
{
public
String
getDatabasePath
()
{
if
(
persistent
)
{
if
(
persistent
)
{
return
FileUtils
.
getCanonic
alPath
(
databaseName
);
return
FileUtils
.
toRe
alPath
(
databaseName
);
}
}
return
null
;
return
null
;
}
}
...
@@ -1477,8 +1477,7 @@ public class Database implements DataHandler {
...
@@ -1477,8 +1477,7 @@ public class Database implements DataHandler {
private
void
deleteOldTempFiles
()
{
private
void
deleteOldTempFiles
()
{
String
path
=
FileUtils
.
getParent
(
databaseName
);
String
path
=
FileUtils
.
getParent
(
databaseName
);
String
[]
list
=
FileUtils
.
listFiles
(
path
);
for
(
String
name
:
FileUtils
.
newDirectoryStream
(
path
))
{
for
(
String
name
:
list
)
{
if
(
name
.
endsWith
(
Constants
.
SUFFIX_TEMP_FILE
)
&&
name
.
startsWith
(
databaseName
))
{
if
(
name
.
endsWith
(
Constants
.
SUFFIX_TEMP_FILE
)
&&
name
.
startsWith
(
databaseName
))
{
// can't always delete the files, they may still be open
// can't always delete the files, they may still be open
FileUtils
.
tryDelete
(
name
);
FileUtils
.
tryDelete
(
name
);
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/security/CipherFactory.java
浏览文件 @
b6ad6d6a
...
@@ -244,7 +244,7 @@ public class CipherFactory {
...
@@ -244,7 +244,7 @@ public class CipherFactory {
throw
DbException
.
convertToIOException
(
e
);
throw
DbException
.
convertToIOException
(
e
);
}
}
}
}
String
absolutePath
=
FileUtils
.
getCanonic
alPath
(
fileName
);
String
absolutePath
=
FileUtils
.
toRe
alPath
(
fileName
);
System
.
setProperty
(
KEYSTORE_KEY
,
absolutePath
);
System
.
setProperty
(
KEYSTORE_KEY
,
absolutePath
);
}
}
if
(
p
.
getProperty
(
KEYSTORE_PASSWORD_KEY
)
==
null
)
{
if
(
p
.
getProperty
(
KEYSTORE_PASSWORD_KEY
)
==
null
)
{
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/store/Data.java
浏览文件 @
b6ad6d6a
...
@@ -90,7 +90,7 @@ public class Data {
...
@@ -90,7 +90,7 @@ public class Data {
/**
/**
* The data itself.
* The data itself.
*/
*/
pr
otected
byte
[]
data
;
pr
ivate
byte
[]
data
;
/**
/**
* The current write or read position.
* The current write or read position.
...
@@ -102,7 +102,7 @@ public class Data {
...
@@ -102,7 +102,7 @@ public class Data {
*/
*/
private
final
DataHandler
handler
;
private
final
DataHandler
handler
;
pr
otected
Data
(
DataHandler
handler
,
byte
[]
data
)
{
pr
ivate
Data
(
DataHandler
handler
,
byte
[]
data
)
{
this
.
handler
=
handler
;
this
.
handler
=
handler
;
this
.
data
=
data
;
this
.
data
=
data
;
}
}
...
@@ -1131,7 +1131,7 @@ public class Data {
...
@@ -1131,7 +1131,7 @@ public class Data {
* @param x the value
* @param x the value
* @return the len
* @return the len
*/
*/
p
ublic
static
int
getVarIntLen
(
int
x
)
{
p
rivate
static
int
getVarIntLen
(
int
x
)
{
if
((
x
&
(-
1
<<
7
))
==
0
)
{
if
((
x
&
(-
1
<<
7
))
==
0
)
{
return
1
;
return
1
;
}
else
if
((
x
&
(-
1
<<
14
))
==
0
)
{
}
else
if
((
x
&
(-
1
<<
14
))
==
0
)
{
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/store/FileLister.java
浏览文件 @
b6ad6d6a
...
@@ -58,7 +58,7 @@ public class FileLister {
...
@@ -58,7 +58,7 @@ public class FileLister {
if
(
dir
==
null
||
dir
.
equals
(
""
))
{
if
(
dir
==
null
||
dir
.
equals
(
""
))
{
return
"."
;
return
"."
;
}
}
return
FileUtils
.
getCanonic
alPath
(
dir
);
return
FileUtils
.
toRe
alPath
(
dir
);
}
}
/**
/**
...
@@ -74,10 +74,8 @@ public class FileLister {
...
@@ -74,10 +74,8 @@ public class FileLister {
public
static
ArrayList
<
String
>
getDatabaseFiles
(
String
dir
,
String
db
,
boolean
all
)
{
public
static
ArrayList
<
String
>
getDatabaseFiles
(
String
dir
,
String
db
,
boolean
all
)
{
ArrayList
<
String
>
files
=
New
.
arrayList
();
ArrayList
<
String
>
files
=
New
.
arrayList
();
// for Windows, File.getCanonicalPath("...b.") returns just "...b"
// for Windows, File.getCanonicalPath("...b.") returns just "...b"
String
start
=
db
==
null
?
null
:
(
FileUtils
.
getCanonicalPath
(
dir
+
"/"
+
db
)
+
"."
);
String
start
=
db
==
null
?
null
:
(
FileUtils
.
toRealPath
(
dir
+
"/"
+
db
)
+
"."
);
String
[]
list
=
FileUtils
.
listFiles
(
dir
);
for
(
String
f
:
FileUtils
.
newDirectoryStream
(
dir
))
{
for
(
int
i
=
0
;
list
!=
null
&&
i
<
list
.
length
;
i
++)
{
String
f
=
list
[
i
];
boolean
ok
=
false
;
boolean
ok
=
false
;
if
(
f
.
endsWith
(
Constants
.
SUFFIX_LOBS_DIRECTORY
))
{
if
(
f
.
endsWith
(
Constants
.
SUFFIX_LOBS_DIRECTORY
))
{
if
(
start
==
null
||
f
.
startsWith
(
start
))
{
if
(
start
==
null
||
f
.
startsWith
(
start
))
{
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/store/FileStore.java
浏览文件 @
b6ad6d6a
...
@@ -8,12 +8,13 @@ package org.h2.store;
...
@@ -8,12 +8,13 @@ package org.h2.store;
import
java.io.IOException
;
import
java.io.IOException
;
import
java.lang.ref.Reference
;
import
java.lang.ref.Reference
;
import
java.nio.ByteBuffer
;
import
java.nio.channels.FileChannel
;
import
org.h2.constant.ErrorCode
;
import
org.h2.constant.ErrorCode
;
import
org.h2.constant.SysProperties
;
import
org.h2.constant.SysProperties
;
import
org.h2.engine.Constants
;
import
org.h2.engine.Constants
;
import
org.h2.message.DbException
;
import
org.h2.message.DbException
;
import
org.h2.security.SecureFileStore
;
import
org.h2.security.SecureFileStore
;
import
org.h2.store.fs.FileObject
;
import
org.h2.store.fs.FileUtils
;
import
org.h2.store.fs.FileUtils
;
import
org.h2.util.TempFileDeleter
;
import
org.h2.util.TempFileDeleter
;
import
org.h2.util.Utils
;
import
org.h2.util.Utils
;
...
@@ -46,7 +47,7 @@ public class FileStore {
...
@@ -46,7 +47,7 @@ public class FileStore {
*/
*/
protected
DataHandler
handler
;
protected
DataHandler
handler
;
private
File
Object
file
;
private
File
Channel
file
;
private
long
filePos
;
private
long
filePos
;
private
long
fileLength
;
private
long
fileLength
;
private
Reference
<?>
autoDeleteReference
;
private
Reference
<?>
autoDeleteReference
;
...
@@ -78,7 +79,7 @@ public class FileStore {
...
@@ -78,7 +79,7 @@ public class FileStore {
}
else
{
}
else
{
FileUtils
.
createDirectories
(
FileUtils
.
getParent
(
name
));
FileUtils
.
createDirectories
(
FileUtils
.
getParent
(
name
));
}
}
file
=
FileUtils
.
open
FileObject
(
name
,
mode
);
file
=
FileUtils
.
open
(
name
,
mode
);
if
(
exists
)
{
if
(
exists
)
{
fileLength
=
file
.
size
();
fileLength
=
file
.
size
();
}
}
...
@@ -272,7 +273,7 @@ public class FileStore {
...
@@ -272,7 +273,7 @@ public class FileStore {
}
}
checkPowerOff
();
checkPowerOff
();
try
{
try
{
file
.
readFully
(
b
,
off
,
len
);
FileUtils
.
readFully
(
file
,
ByteBuffer
.
wrap
(
b
,
off
,
len
)
);
}
catch
(
IOException
e
)
{
}
catch
(
IOException
e
)
{
throw
DbException
.
convertIOException
(
e
,
name
);
throw
DbException
.
convertIOException
(
e
,
name
);
}
}
...
@@ -323,11 +324,11 @@ public class FileStore {
...
@@ -323,11 +324,11 @@ public class FileStore {
checkWritingAllowed
();
checkWritingAllowed
();
checkPowerOff
();
checkPowerOff
();
try
{
try
{
file
.
write
(
b
,
off
,
len
);
FileUtils
.
writeFully
(
file
,
ByteBuffer
.
wrap
(
b
,
off
,
len
)
);
}
catch
(
IOException
e
)
{
}
catch
(
IOException
e
)
{
if
(
freeUpDiskSpace
())
{
if
(
freeUpDiskSpace
())
{
try
{
try
{
file
.
write
(
b
,
off
,
len
);
FileUtils
.
writeFully
(
file
,
ByteBuffer
.
wrap
(
b
,
off
,
len
)
);
}
catch
(
IOException
e2
)
{
}
catch
(
IOException
e2
)
{
throw
DbException
.
convertIOException
(
e2
,
name
);
throw
DbException
.
convertIOException
(
e2
,
name
);
}
}
...
@@ -362,7 +363,7 @@ public class FileStore {
...
@@ -362,7 +363,7 @@ public class FileStore {
if
(
newLength
>
fileLength
)
{
if
(
newLength
>
fileLength
)
{
long
pos
=
filePos
;
long
pos
=
filePos
;
file
.
position
(
newLength
-
1
);
file
.
position
(
newLength
-
1
);
file
.
write
(
new
byte
[
1
],
0
,
1
);
FileUtils
.
writeFully
(
file
,
ByteBuffer
.
wrap
(
new
byte
[
1
])
);
file
.
position
(
pos
);
file
.
position
(
pos
);
}
else
{
}
else
{
file
.
truncate
(
newLength
);
file
.
truncate
(
newLength
);
...
@@ -468,7 +469,7 @@ public class FileStore {
...
@@ -468,7 +469,7 @@ public class FileStore {
*/
*/
public
void
openFile
()
throws
IOException
{
public
void
openFile
()
throws
IOException
{
if
(
file
==
null
)
{
if
(
file
==
null
)
{
file
=
FileUtils
.
open
FileObject
(
name
,
mode
);
file
=
FileUtils
.
open
(
name
,
mode
);
file
.
position
(
filePos
);
file
.
position
(
filePos
);
}
}
}
}
...
...
This diff is collapsed.
Click to expand it.
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
}
}
This diff is collapsed.
Click to expand it.
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;
...
@@ -8,29 +8,31 @@ package org.h2.store.fs;
import
java.io.IOException
;
import
java.io.IOException
;
import
java.io.InputStream
;
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
};
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
)
{
public
File
ChannelInputStream
(
FileChannel
channel
)
{
this
.
file
=
file
;
this
.
channel
=
channel
;
}
}
public
int
read
()
throws
IOException
{
public
int
read
()
throws
IOException
{
if
(
file
.
position
()
>=
file
.
size
())
{
if
(
channel
.
position
()
>=
channel
.
size
())
{
return
-
1
;
return
-
1
;
}
}
file
.
readFully
(
buffer
,
0
,
1
);
FileUtils
.
readFully
(
channel
,
ByteBuffer
.
wrap
(
buffer
)
);
return
buffer
[
0
]
&
0xff
;
return
buffer
[
0
]
&
0xff
;
}
}
...
@@ -39,15 +41,15 @@ public class FileObjectInputStream extends InputStream {
...
@@ -39,15 +41,15 @@ public class FileObjectInputStream extends InputStream {
}
}
public
int
read
(
byte
[]
b
,
int
off
,
int
len
)
throws
IOException
{
public
int
read
(
byte
[]
b
,
int
off
,
int
len
)
throws
IOException
{
if
(
file
.
position
()
+
len
<
file
.
size
())
{
if
(
channel
.
position
()
+
len
<
channel
.
size
())
{
file
.
readFully
(
b
,
off
,
len
);
FileUtils
.
readFully
(
channel
,
ByteBuffer
.
wrap
(
b
,
off
,
len
)
);
return
len
;
return
len
;
}
}
return
super
.
read
(
b
,
off
,
len
);
return
super
.
read
(
b
,
off
,
len
);
}
}
public
void
close
()
throws
IOException
{
public
void
close
()
throws
IOException
{
file
.
close
();
channel
.
close
();
}
}
}
}
This diff is collapsed.
Click to expand it.
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;
...
@@ -8,46 +8,48 @@ package org.h2.store.fs;
import
java.io.IOException
;
import
java.io.IOException
;
import
java.io.OutputStream
;
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
};
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
* @param append true for append mode, false for truncate and overwrite
*/
*/
public
File
ObjectOutputStream
(
FileObject
file
,
boolean
append
)
throws
IOException
{
public
File
ChannelOutputStream
(
FileChannel
channel
,
boolean
append
)
throws
IOException
{
this
.
file
=
file
;
this
.
channel
=
channel
;
if
(
append
)
{
if
(
append
)
{
file
.
position
(
file
.
size
());
channel
.
position
(
channel
.
size
());
}
else
{
}
else
{
file
.
position
(
0
);
channel
.
position
(
0
);
file
.
truncate
(
0
);
channel
.
truncate
(
0
);
}
}
}
}
public
void
write
(
int
b
)
throws
IOException
{
public
void
write
(
int
b
)
throws
IOException
{
buffer
[
0
]
=
(
byte
)
b
;
buffer
[
0
]
=
(
byte
)
b
;
file
.
write
(
buffer
,
0
,
1
);
FileUtils
.
writeFully
(
channel
,
ByteBuffer
.
wrap
(
buffer
)
);
}
}
public
void
write
(
byte
[]
b
)
throws
IOException
{
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
{
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
{
public
void
close
()
throws
IOException
{
file
.
close
();
channel
.
close
();
}
}
}
}
This diff is collapsed.
Click to expand it.
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
;
}
This diff is collapsed.
Click to expand it.
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
;
}
}
This diff is collapsed.
Click to expand it.
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
;
}
}
This diff is collapsed.
Click to expand it.
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
;
}
}
This diff is collapsed.
Click to expand it.
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
;
}
}
This diff is collapsed.
Click to expand it.
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
();
}
}
This diff is collapsed.
Click to expand it.
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
This diff is collapsed.
Click to expand it.
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
();
}
}
This diff is collapsed.
Click to expand it.
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
;
}
}
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/store/fs/FilePath.java
浏览文件 @
b6ad6d6a
...
@@ -9,6 +9,7 @@ package org.h2.store.fs;
...
@@ -9,6 +9,7 @@ package org.h2.store.fs;
import
java.io.IOException
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.io.InputStream
;
import
java.io.OutputStream
;
import
java.io.OutputStream
;
import
java.nio.channels.FileChannel
;
import
java.util.Collections
;
import
java.util.Collections
;
import
java.util.List
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Map
;
...
@@ -142,18 +143,18 @@ public abstract class FilePath {
...
@@ -142,18 +143,18 @@ public abstract class FilePath {
public
abstract
void
delete
();
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
* @return the list of fully qualified file names
*/
*/
public
abstract
List
<
FilePath
>
listFiles
();
public
abstract
List
<
FilePath
>
newDirectoryStream
();
/**
/**
* Normalize a file name.
* Normalize a file name.
*
*
* @return the normalized 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.
* Get the parent directory of a file or directory.
...
@@ -220,7 +221,7 @@ public abstract class FilePath {
...
@@ -220,7 +221,7 @@ public abstract class FilePath {
* @param mode the access mode. Supported are r, rw, rws, rwd
* @param mode the access mode. Supported are r, rw, rws, rwd
* @return the file object
* @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.
* Create an input stream to read from the file.
...
@@ -253,7 +254,7 @@ public abstract class FilePath {
...
@@ -253,7 +254,7 @@ public abstract class FilePath {
getNextTempFileNamePart
(
true
);
getNextTempFileNamePart
(
true
);
continue
;
continue
;
}
}
p
.
open
FileObject
(
"rw"
).
close
();
p
.
open
(
"rw"
).
close
();
return
p
;
return
p
;
}
}
}
}
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/store/fs/FilePathDisk.java
浏览文件 @
b6ad6d6a
...
@@ -15,6 +15,9 @@ import java.io.InputStream;
...
@@ -15,6 +15,9 @@ import java.io.InputStream;
import
java.io.OutputStream
;
import
java.io.OutputStream
;
import
java.io.RandomAccessFile
;
import
java.io.RandomAccessFile
;
import
java.net.URL
;
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.ArrayList
;
import
java.util.List
;
import
java.util.List
;
import
org.h2.constant.ErrorCode
;
import
org.h2.constant.ErrorCode
;
...
@@ -146,7 +149,7 @@ public class FilePathDisk extends FilePath {
...
@@ -146,7 +149,7 @@ public class FilePathDisk extends FilePath {
throw
DbException
.
get
(
ErrorCode
.
FILE_DELETE_FAILED_1
,
name
);
throw
DbException
.
get
(
ErrorCode
.
FILE_DELETE_FAILED_1
,
name
);
}
}
public
List
<
FilePath
>
listFiles
()
{
public
List
<
FilePath
>
newDirectoryStream
()
{
ArrayList
<
FilePath
>
list
=
New
.
arrayList
();
ArrayList
<
FilePath
>
list
=
New
.
arrayList
();
File
f
=
new
File
(
name
);
File
f
=
new
File
(
name
);
try
{
try
{
...
@@ -175,7 +178,7 @@ public class FilePathDisk extends FilePath {
...
@@ -175,7 +178,7 @@ public class FilePathDisk extends FilePath {
return
f
.
setReadOnly
();
return
f
.
setReadOnly
();
}
}
public
FilePathDisk
getCanonic
alPath
()
{
public
FilePathDisk
toRe
alPath
()
{
try
{
try
{
String
fileName
=
new
File
(
name
).
getCanonicalPath
();
String
fileName
=
new
File
(
name
).
getCanonicalPath
();
return
getPath
(
fileName
);
return
getPath
(
fileName
);
...
@@ -311,15 +314,15 @@ public class FilePathDisk extends FilePath {
...
@@ -311,15 +314,15 @@ public class FilePathDisk extends FilePath {
}
}
}
}
public
File
Object
openFileObject
(
String
mode
)
throws
IOException
{
public
File
Channel
open
(
String
mode
)
throws
IOException
{
File
Object
Disk
f
;
FileDisk
f
;
try
{
try
{
f
=
new
File
Object
Disk
(
name
,
mode
);
f
=
new
FileDisk
(
name
,
mode
);
IOUtils
.
trace
(
"open
FileObject
"
,
name
,
f
);
IOUtils
.
trace
(
"open"
,
name
,
f
);
}
catch
(
IOException
e
)
{
}
catch
(
IOException
e
)
{
freeMemoryAndFinalize
();
freeMemoryAndFinalize
();
try
{
try
{
f
=
new
File
Object
Disk
(
name
,
mode
);
f
=
new
FileDisk
(
name
,
mode
);
}
catch
(
IOException
e2
)
{
}
catch
(
IOException
e2
)
{
throw
e
;
throw
e
;
}
}
...
@@ -363,3 +366,81 @@ public class FilePathDisk extends FilePath {
...
@@ -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
;
}
}
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/store/fs/FilePathMem.java
浏览文件 @
b6ad6d6a
...
@@ -9,10 +9,17 @@ package org.h2.store.fs;
...
@@ -9,10 +9,17 @@ package org.h2.store.fs;
import
java.io.IOException
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.io.InputStream
;
import
java.io.OutputStream
;
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.ArrayList
;
import
java.util.LinkedHashMap
;
import
java.util.List
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.TreeMap
;
import
java.util.TreeMap
;
import
org.h2.compress.CompressLZF
;
import
org.h2.message.DbException
;
import
org.h2.message.DbException
;
import
org.h2.util.MathUtils
;
import
org.h2.util.New
;
import
org.h2.util.New
;
/**
/**
...
@@ -21,7 +28,7 @@ import org.h2.util.New;
...
@@ -21,7 +28,7 @@ import org.h2.util.New;
*/
*/
public
class
FilePathMem
extends
FilePath
{
public
class
FilePathMem
extends
FilePath
{
private
static
final
TreeMap
<
String
,
File
ObjectMemData
>
MEMORY_FILES
=
new
TreeMap
<
String
,
FileObject
MemData
>();
private
static
final
TreeMap
<
String
,
File
MemData
>
MEMORY_FILES
=
new
TreeMap
<
String
,
File
MemData
>();
public
FilePathMem
getPath
(
String
path
)
{
public
FilePathMem
getPath
(
String
path
)
{
FilePathMem
p
=
new
FilePathMem
();
FilePathMem
p
=
new
FilePathMem
();
...
@@ -35,7 +42,7 @@ public class FilePathMem extends FilePath {
...
@@ -35,7 +42,7 @@ public class FilePathMem extends FilePath {
public
void
moveTo
(
FilePath
newName
)
{
public
void
moveTo
(
FilePath
newName
)
{
synchronized
(
MEMORY_FILES
)
{
synchronized
(
MEMORY_FILES
)
{
File
Object
MemData
f
=
getMemoryFile
();
FileMemData
f
=
getMemoryFile
();
f
.
setName
(
newName
.
name
);
f
.
setName
(
newName
.
name
);
MEMORY_FILES
.
remove
(
name
);
MEMORY_FILES
.
remove
(
name
);
MEMORY_FILES
.
put
(
newName
.
name
,
f
);
MEMORY_FILES
.
put
(
newName
.
name
,
f
);
...
@@ -70,7 +77,7 @@ public class FilePathMem extends FilePath {
...
@@ -70,7 +77,7 @@ public class FilePathMem extends FilePath {
}
}
}
}
public
List
<
FilePath
>
listFiles
()
{
public
List
<
FilePath
>
newDirectoryStream
()
{
ArrayList
<
FilePath
>
list
=
New
.
arrayList
();
ArrayList
<
FilePath
>
list
=
New
.
arrayList
();
synchronized
(
MEMORY_FILES
)
{
synchronized
(
MEMORY_FILES
)
{
for
(
String
n
:
MEMORY_FILES
.
tailMap
(
name
).
keySet
())
{
for
(
String
n
:
MEMORY_FILES
.
tailMap
(
name
).
keySet
())
{
...
@@ -108,7 +115,7 @@ public class FilePathMem extends FilePath {
...
@@ -108,7 +115,7 @@ public class FilePathMem extends FilePath {
return
true
;
return
true
;
}
}
public
FilePathMem
getCanonic
alPath
()
{
public
FilePathMem
toRe
alPath
()
{
return
this
;
return
this
;
}
}
...
@@ -122,30 +129,30 @@ public class FilePathMem extends FilePath {
...
@@ -122,30 +129,30 @@ public class FilePathMem extends FilePath {
public
OutputStream
newOutputStream
(
boolean
append
)
{
public
OutputStream
newOutputStream
(
boolean
append
)
{
try
{
try
{
File
Object
MemData
obj
=
getMemoryFile
();
FileMemData
obj
=
getMemoryFile
();
File
ObjectMem
m
=
new
FileObject
Mem
(
obj
,
false
);
File
Mem
m
=
new
File
Mem
(
obj
,
false
);
return
new
File
Object
OutputStream
(
m
,
append
);
return
new
File
Channel
OutputStream
(
m
,
append
);
}
catch
(
IOException
e
)
{
}
catch
(
IOException
e
)
{
throw
DbException
.
convertIOException
(
e
,
name
);
throw
DbException
.
convertIOException
(
e
,
name
);
}
}
}
}
public
InputStream
newInputStream
()
{
public
InputStream
newInputStream
()
{
File
Object
MemData
obj
=
getMemoryFile
();
FileMemData
obj
=
getMemoryFile
();
File
ObjectMem
m
=
new
FileObject
Mem
(
obj
,
true
);
File
Mem
m
=
new
File
Mem
(
obj
,
true
);
return
new
File
Object
InputStream
(
m
);
return
new
File
Channel
InputStream
(
m
);
}
}
public
File
Object
openFileObject
(
String
mode
)
{
public
File
Channel
open
(
String
mode
)
{
File
Object
MemData
obj
=
getMemoryFile
();
FileMemData
obj
=
getMemoryFile
();
return
new
File
Object
Mem
(
obj
,
"r"
.
equals
(
mode
));
return
new
FileMem
(
obj
,
"r"
.
equals
(
mode
));
}
}
private
File
Object
MemData
getMemoryFile
()
{
private
FileMemData
getMemoryFile
()
{
synchronized
(
MEMORY_FILES
)
{
synchronized
(
MEMORY_FILES
)
{
File
Object
MemData
m
=
MEMORY_FILES
.
get
(
name
);
FileMemData
m
=
MEMORY_FILES
.
get
(
name
);
if
(
m
==
null
)
{
if
(
m
==
null
)
{
m
=
new
File
Object
MemData
(
name
,
compressed
());
m
=
new
FileMemData
(
name
,
compressed
());
MEMORY_FILES
.
put
(
name
,
m
);
MEMORY_FILES
.
put
(
name
,
m
);
}
}
return
m
;
return
m
;
...
@@ -195,3 +202,375 @@ class FilePathMemLZF extends FilePathMem {
...
@@ -195,3 +202,375 @@ class FilePathMemLZF extends FilePathMem {
}
}
/**
* This class represents an in-memory file.
*/
class
FileMem
extends
FileBase
{
private
final
FileMemData
data
;
private
final
boolean
readOnly
;
private
long
pos
;
FileMem
(
FileMemData
data
,
boolean
readOnly
)
{
this
.
data
=
data
;
this
.
readOnly
=
readOnly
;
}
public
long
size
()
{
return
data
.
length
();
}
public
FileChannel
truncate
(
long
newLength
)
throws
IOException
{
if
(
newLength
<
size
())
{
data
.
touch
(
readOnly
);
pos
=
Math
.
min
(
pos
,
newLength
);
data
.
truncate
(
newLength
);
}
return
this
;
}
public
FileChannel
position
(
long
newPos
)
{
this
.
pos
=
(
int
)
newPos
;
return
this
;
}
public
int
write
(
ByteBuffer
src
)
throws
IOException
{
int
len
=
src
.
remaining
();
if
(
len
==
0
)
{
return
0
;
}
data
.
touch
(
readOnly
);
pos
=
data
.
readWrite
(
pos
,
src
.
array
(),
src
.
position
(),
len
,
true
);
src
.
position
(
src
.
position
()
+
len
);
return
len
;
}
public
int
read
(
ByteBuffer
dst
)
throws
IOException
{
int
len
=
dst
.
remaining
();
if
(
len
==
0
)
{
return
0
;
}
long
newPos
=
data
.
readWrite
(
pos
,
dst
.
array
(),
dst
.
position
(),
len
,
false
);
len
=
(
int
)
(
newPos
-
pos
);
if
(
len
<=
0
)
{
return
-
1
;
}
dst
.
position
(
dst
.
position
()
+
len
);
pos
=
newPos
;
return
len
;
}
public
long
position
()
{
return
pos
;
}
public
void
implCloseChannel
()
throws
IOException
{
pos
=
0
;
}
public
void
force
(
boolean
metaData
)
throws
IOException
{
// do nothing
}
public
synchronized
FileLock
tryLock
(
long
position
,
long
size
,
boolean
shared
)
throws
IOException
{
return
null
;
}
}
/**
* This class contains the data of an in-memory random access file.
* Data compression using the LZF algorithm is supported as well.
*/
class
FileMemData
{
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
;
}
}
FileMemData
(
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
)
{
long
end
=
pos
+
len
;
if
(
end
>
length
)
{
if
(
write
)
{
changeLength
(
end
);
}
else
{
return
pos
;
}
}
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
;
}
}
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/store/fs/FilePathNio.java
浏览文件 @
b6ad6d6a
...
@@ -7,6 +7,11 @@
...
@@ -7,6 +7,11 @@
package
org
.
h2
.
store
.
fs
;
package
org
.
h2
.
store
.
fs
;
import
java.io.IOException
;
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.
* This file system stores files on disk and uses java.nio to access the files.
...
@@ -14,8 +19,8 @@ import java.io.IOException;
...
@@ -14,8 +19,8 @@ import java.io.IOException;
*/
*/
public
class
FilePathNio
extends
FilePathWrapper
{
public
class
FilePathNio
extends
FilePathWrapper
{
public
File
Object
openFileObject
(
String
mode
)
throws
IOException
{
public
File
Channel
open
(
String
mode
)
throws
IOException
{
return
new
File
Object
Nio
(
name
.
substring
(
getScheme
().
length
()
+
1
),
mode
);
return
new
FileNio
(
name
.
substring
(
getScheme
().
length
()
+
1
),
mode
);
}
}
public
String
getScheme
()
{
public
String
getScheme
()
{
...
@@ -23,3 +28,73 @@ public class FilePathNio extends FilePathWrapper {
...
@@ -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
;
}
}
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/store/fs/FilePathNioMapped.java
浏览文件 @
b6ad6d6a
...
@@ -6,7 +6,17 @@
...
@@ -6,7 +6,17 @@
*/
*/
package
org
.
h2
.
store
.
fs
;
package
org
.
h2
.
store
.
fs
;
import
java.io.EOFException
;
import
java.io.IOException
;
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.
* This file system stores files on disk and uses java.nio to access the files.
...
@@ -14,8 +24,8 @@ import java.io.IOException;
...
@@ -14,8 +24,8 @@ import java.io.IOException;
*/
*/
public
class
FilePathNioMapped
extends
FilePathNio
{
public
class
FilePathNioMapped
extends
FilePathNio
{
public
File
Object
openFileObject
(
String
mode
)
throws
IOException
{
public
File
Channel
open
(
String
mode
)
throws
IOException
{
return
new
File
Object
NioMapped
(
name
.
substring
(
getScheme
().
length
()
+
1
),
mode
);
return
new
FileNioMapped
(
name
.
substring
(
getScheme
().
length
()
+
1
),
mode
);
}
}
public
String
getScheme
()
{
public
String
getScheme
()
{
...
@@ -23,3 +33,207 @@ public class FilePathNioMapped extends FilePathNio {
...
@@ -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
();
}
}
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/store/fs/FilePathRec.java
浏览文件 @
b6ad6d6a
...
@@ -8,6 +8,9 @@ package org.h2.store.fs;
...
@@ -8,6 +8,9 @@ package org.h2.store.fs;
import
java.io.IOException
;
import
java.io.IOException
;
import
java.io.OutputStream
;
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.
* A file system that records all write operations and can re-play them.
...
@@ -52,8 +55,8 @@ public class FilePathRec extends FilePathWrapper {
...
@@ -52,8 +55,8 @@ public class FilePathRec extends FilePathWrapper {
super
.
delete
();
super
.
delete
();
}
}
public
File
Object
openFileObject
(
String
mode
)
throws
IOException
{
public
File
Channel
open
(
String
mode
)
throws
IOException
{
return
new
File
ObjectRec
(
this
,
super
.
openFileObject
(
mode
),
name
);
return
new
File
Rec
(
this
,
super
.
open
(
mode
),
name
);
}
}
public
OutputStream
newOutputStream
(
boolean
append
)
{
public
OutputStream
newOutputStream
(
boolean
append
)
{
...
@@ -108,3 +111,68 @@ public class FilePathRec extends FilePathWrapper {
...
@@ -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
();
}
}
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/store/fs/FilePathSplit.java
浏览文件 @
b6ad6d6a
...
@@ -10,6 +10,9 @@ import java.io.IOException;
...
@@ -10,6 +10,9 @@ import java.io.IOException;
import
java.io.InputStream
;
import
java.io.InputStream
;
import
java.io.OutputStream
;
import
java.io.OutputStream
;
import
java.io.SequenceInputStream
;
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.ArrayList
;
import
java.util.List
;
import
java.util.List
;
import
org.h2.constant.SysProperties
;
import
org.h2.constant.SysProperties
;
...
@@ -83,8 +86,8 @@ public class FilePathSplit extends FilePathWrapper {
...
@@ -83,8 +86,8 @@ public class FilePathSplit extends FilePathWrapper {
return
length
;
return
length
;
}
}
public
ArrayList
<
FilePath
>
listFiles
()
{
public
ArrayList
<
FilePath
>
newDirectoryStream
()
{
List
<
FilePath
>
list
=
getBase
().
listFiles
();
List
<
FilePath
>
list
=
getBase
().
newDirectoryStream
();
ArrayList
<
FilePath
>
newList
=
New
.
arrayList
();
ArrayList
<
FilePath
>
newList
=
New
.
arrayList
();
for
(
int
i
=
0
,
size
=
list
.
size
();
i
<
size
;
i
++)
{
for
(
int
i
=
0
,
size
=
list
.
size
();
i
<
size
;
i
++)
{
FilePath
f
=
list
.
get
(
i
);
FilePath
f
=
list
.
get
(
i
);
...
@@ -109,20 +112,18 @@ public class FilePathSplit extends FilePathWrapper {
...
@@ -109,20 +112,18 @@ public class FilePathSplit extends FilePathWrapper {
return
input
;
return
input
;
}
}
public
FileObject
openFileObject
(
String
mode
)
throws
IOException
{
public
FileChannel
open
(
String
mode
)
throws
IOException
{
ArrayList
<
FileObject
>
list
=
New
.
arrayList
();
ArrayList
<
FileChannel
>
list
=
New
.
arrayList
();
FileObject
o
=
getBase
().
openFileObject
(
mode
);
list
.
add
(
getBase
().
open
(
mode
));
list
.
add
(
o
);
for
(
int
i
=
1
;;
i
++)
{
for
(
int
i
=
1
;;
i
++)
{
FilePath
f
=
getBase
(
i
);
FilePath
f
=
getBase
(
i
);
if
(
f
.
exists
())
{
if
(
f
.
exists
())
{
o
=
f
.
openFileObject
(
mode
);
list
.
add
(
f
.
open
(
mode
));
list
.
add
(
o
);
}
else
{
}
else
{
break
;
break
;
}
}
}
}
File
Object
[]
array
=
new
FileObject
[
list
.
size
()];
File
Channel
[]
array
=
new
FileChannel
[
list
.
size
()];
list
.
toArray
(
array
);
list
.
toArray
(
array
);
long
maxLength
=
array
[
0
].
size
();
long
maxLength
=
array
[
0
].
size
();
long
length
=
maxLength
;
long
length
=
maxLength
;
...
@@ -136,21 +137,21 @@ public class FilePathSplit extends FilePathWrapper {
...
@@ -136,21 +137,21 @@ public class FilePathSplit extends FilePathWrapper {
closeAndThrow
(
0
,
array
,
array
[
0
],
maxLength
);
closeAndThrow
(
0
,
array
,
array
[
0
],
maxLength
);
}
}
for
(
int
i
=
1
;
i
<
array
.
length
-
1
;
i
++)
{
for
(
int
i
=
1
;
i
<
array
.
length
-
1
;
i
++)
{
o
=
array
[
i
];
FileChannel
c
=
array
[
i
];
long
l
=
o
.
size
();
long
l
=
c
.
size
();
length
+=
l
;
length
+=
l
;
if
(
l
!=
maxLength
)
{
if
(
l
!=
maxLength
)
{
closeAndThrow
(
i
,
array
,
o
,
maxLength
);
closeAndThrow
(
i
,
array
,
c
,
maxLength
);
}
}
}
}
o
=
array
[
array
.
length
-
1
];
FileChannel
c
=
array
[
array
.
length
-
1
];
long
l
=
o
.
size
();
long
l
=
c
.
size
();
length
+=
l
;
length
+=
l
;
if
(
l
>
maxLength
)
{
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
;
return
fo
;
}
}
...
@@ -158,9 +159,9 @@ public class FilePathSplit extends FilePathWrapper {
...
@@ -158,9 +159,9 @@ public class FilePathSplit extends FilePathWrapper {
return
1L
<<
Integer
.
decode
(
parse
(
name
)[
0
]).
intValue
();
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
);
String
message
=
"Expected file length: "
+
maxLength
+
" got: "
+
o
.
size
()
+
" for "
+
getName
(
id
);
for
(
File
Object
f
:
array
)
{
for
(
File
Channel
f
:
array
)
{
f
.
close
();
f
.
close
();
}
}
throw
new
IOException
(
message
);
throw
new
IOException
(
message
);
...
@@ -168,7 +169,7 @@ public class FilePathSplit extends FilePathWrapper {
...
@@ -168,7 +169,7 @@ public class FilePathSplit extends FilePathWrapper {
public
OutputStream
newOutputStream
(
boolean
append
)
{
public
OutputStream
newOutputStream
(
boolean
append
)
{
try
{
try
{
return
new
File
ObjectOutputStream
(
openFileObject
(
"rw"
),
append
);
return
new
File
ChannelOutputStream
(
open
(
"rw"
),
append
);
}
catch
(
IOException
e
)
{
}
catch
(
IOException
e
)
{
throw
DbException
.
convertIOException
(
e
,
name
);
throw
DbException
.
convertIOException
(
e
,
name
);
}
}
...
@@ -231,3 +232,146 @@ public class FilePathSplit extends FilePathWrapper {
...
@@ -231,3 +232,146 @@ public class FilePathSplit extends FilePathWrapper {
}
}
}
}
/**
* 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
();
}
}
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/store/fs/FilePathWrapper.java
浏览文件 @
b6ad6d6a
...
@@ -9,6 +9,7 @@ package org.h2.store.fs;
...
@@ -9,6 +9,7 @@ package org.h2.store.fs;
import
java.io.IOException
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.io.InputStream
;
import
java.io.OutputStream
;
import
java.io.OutputStream
;
import
java.nio.channels.FileChannel
;
import
java.util.List
;
import
java.util.List
;
import
org.h2.message.DbException
;
import
org.h2.message.DbException
;
...
@@ -103,12 +104,12 @@ public abstract class FilePathWrapper extends FilePath {
...
@@ -103,12 +104,12 @@ public abstract class FilePathWrapper extends FilePath {
return
base
.
lastModified
();
return
base
.
lastModified
();
}
}
public
FilePath
getCanonic
alPath
()
{
public
FilePath
toRe
alPath
()
{
return
wrap
(
base
.
getCanonic
alPath
());
return
wrap
(
base
.
toRe
alPath
());
}
}
public
List
<
FilePath
>
listFiles
()
{
public
List
<
FilePath
>
newDirectoryStream
()
{
List
<
FilePath
>
list
=
base
.
listFiles
();
List
<
FilePath
>
list
=
base
.
newDirectoryStream
();
for
(
int
i
=
0
,
len
=
list
.
size
();
i
<
len
;
i
++)
{
for
(
int
i
=
0
,
len
=
list
.
size
();
i
<
len
;
i
++)
{
list
.
set
(
i
,
wrap
(
list
.
get
(
i
)));
list
.
set
(
i
,
wrap
(
list
.
get
(
i
)));
}
}
...
@@ -127,8 +128,8 @@ public abstract class FilePathWrapper extends FilePath {
...
@@ -127,8 +128,8 @@ public abstract class FilePathWrapper extends FilePath {
return
base
.
newOutputStream
(
append
);
return
base
.
newOutputStream
(
append
);
}
}
public
File
Object
openFileObject
(
String
mode
)
throws
IOException
{
public
File
Channel
open
(
String
mode
)
throws
IOException
{
return
base
.
open
FileObject
(
mode
);
return
base
.
open
(
mode
);
}
}
public
boolean
setReadOnly
()
{
public
boolean
setReadOnly
()
{
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/store/fs/FilePathZip.java
浏览文件 @
b6ad6d6a
...
@@ -10,11 +10,15 @@ import java.io.FileNotFoundException;
...
@@ -10,11 +10,15 @@ import java.io.FileNotFoundException;
import
java.io.IOException
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.io.InputStream
;
import
java.io.OutputStream
;
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.ArrayList
;
import
java.util.Enumeration
;
import
java.util.Enumeration
;
import
java.util.zip.ZipEntry
;
import
java.util.zip.ZipEntry
;
import
java.util.zip.ZipFile
;
import
java.util.zip.ZipFile
;
import
org.h2.message.DbException
;
import
org.h2.message.DbException
;
import
org.h2.util.IOUtils
;
import
org.h2.util.New
;
import
org.h2.util.New
;
/**
/**
...
@@ -112,7 +116,7 @@ public class FilePathZip extends FilePath {
...
@@ -112,7 +116,7 @@ public class FilePathZip extends FilePath {
}
}
}
}
public
ArrayList
<
FilePath
>
listFiles
()
{
public
ArrayList
<
FilePath
>
newDirectoryStream
()
{
String
path
=
name
;
String
path
=
name
;
ArrayList
<
FilePath
>
list
=
New
.
arrayList
();
ArrayList
<
FilePath
>
list
=
New
.
arrayList
();
try
{
try
{
...
@@ -147,16 +151,16 @@ public class FilePathZip extends FilePath {
...
@@ -147,16 +151,16 @@ public class FilePathZip extends FilePath {
}
}
public
InputStream
newInputStream
()
throws
IOException
{
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
();
ZipFile
file
=
openZipFile
();
ZipEntry
entry
=
file
.
getEntry
(
getEntryName
());
ZipEntry
entry
=
file
.
getEntry
(
getEntryName
());
if
(
entry
==
null
)
{
if
(
entry
==
null
)
{
throw
new
FileNotFoundException
(
name
);
throw
new
FileNotFoundException
(
name
);
}
}
return
new
File
Object
Zip
(
file
,
entry
);
return
new
FileZip
(
file
,
entry
);
}
}
public
OutputStream
newOutputStream
(
boolean
append
)
{
public
OutputStream
newOutputStream
(
boolean
append
)
{
...
@@ -178,7 +182,7 @@ public class FilePathZip extends FilePath {
...
@@ -178,7 +182,7 @@ public class FilePathZip extends FilePath {
return
FilePathDisk
.
expandUserHomeDirectory
(
fileName
);
return
FilePathDisk
.
expandUserHomeDirectory
(
fileName
);
}
}
public
FilePath
getCanonic
alPath
()
{
public
FilePath
toRe
alPath
()
{
return
this
;
return
this
;
}
}
...
@@ -214,3 +218,100 @@ public class FilePathZip extends FilePath {
...
@@ -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
;
}
}
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/store/fs/FileUtils.java
浏览文件 @
b6ad6d6a
package
org
.
h2
.
store
.
fs
;
package
org
.
h2
.
store
.
fs
;
import
java.io.EOFException
;
import
java.io.IOException
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.io.InputStream
;
import
java.io.OutputStream
;
import
java.io.OutputStream
;
import
java.nio.ByteBuffer
;
import
java.nio.channels.FileChannel
;
import
java.util.List
;
import
java.util.List
;
import
org.h2.constant.ErrorCode
;
import
org.h2.constant.ErrorCode
;
import
org.h2.message.DbException
;
import
org.h2.message.DbException
;
import
org.h2.util.IOUtils
;
import
org.h2.util.IOUtils
;
import
org.h2.util.New
;
/**
/**
* This utility class contains utility functions that use the file system
* This utility class contains utility functions that use the file system
...
@@ -59,14 +63,14 @@ public class FileUtils {
...
@@ -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>.
* This method is similar to Java 7 <code>java.nio.file.Path.toRealPath</code>.
*
*
* @param fileName the file name
* @param fileName the file name
* @return the normalized file name
* @return the normalized file name
*/
*/
public
static
String
getCanonic
alPath
(
String
fileName
)
{
public
static
String
toRe
alPath
(
String
fileName
)
{
return
FilePath
.
get
(
fileName
).
getCanonic
alPath
().
toString
();
return
FilePath
.
get
(
fileName
).
toRe
alPath
().
toString
();
}
}
/**
/**
...
@@ -116,19 +120,20 @@ public class FileUtils {
...
@@ -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>.
* This method is similar to Java 7 <code>java.nio.file.Path.newDirectoryStream</code>.
*
*
* @param path the directory
* @param path the directory
* @return the list of fully qualified file names
* @return the list of fully qualified file names
*/
*/
public
static
String
[]
listFiles
(
String
path
)
{
public
static
List
<
String
>
newDirectoryStream
(
String
path
)
{
List
<
FilePath
>
list
=
FilePath
.
get
(
path
).
listFiles
();
List
<
FilePath
>
list
=
FilePath
.
get
(
path
).
newDirectoryStream
();
String
[]
array
=
new
String
[
list
.
size
()];
int
len
=
list
.
size
();
for
(
int
i
=
0
,
len
=
list
.
size
();
i
<
len
;
i
++)
{
List
<
String
>
result
=
New
.
arrayList
(
len
);
array
[
i
]
=
list
.
get
(
i
).
toString
();
for
(
int
i
=
0
;
i
<
len
;
i
++)
{
result
.
add
(
list
.
get
(
i
).
toString
());
}
}
return
array
;
return
result
;
}
}
/**
/**
...
@@ -174,8 +179,8 @@ public class FileUtils {
...
@@ -174,8 +179,8 @@ public class FileUtils {
* @param mode the access mode. Supported are r, rw, rws, rwd
* @param mode the access mode. Supported are r, rw, rws, rwd
* @return the file object
* @return the file object
*/
*/
public
static
File
Object
openFileObject
(
String
fileName
,
String
mode
)
throws
IOException
{
public
static
File
Channel
open
(
String
fileName
,
String
mode
)
throws
IOException
{
return
FilePath
.
get
(
fileName
).
open
FileObject
(
mode
);
return
FilePath
.
get
(
fileName
).
open
(
mode
);
}
}
/**
/**
...
@@ -248,7 +253,7 @@ public class FileUtils {
...
@@ -248,7 +253,7 @@ public class FileUtils {
public
static
void
deleteRecursive
(
String
path
,
boolean
tryOnly
)
{
public
static
void
deleteRecursive
(
String
path
,
boolean
tryOnly
)
{
if
(
exists
(
path
))
{
if
(
exists
(
path
))
{
if
(
isDirectory
(
path
))
{
if
(
isDirectory
(
path
))
{
for
(
String
s
:
listFiles
(
path
))
{
for
(
String
s
:
newDirectoryStream
(
path
))
{
deleteRecursive
(
s
,
tryOnly
);
deleteRecursive
(
s
,
tryOnly
);
}
}
}
}
...
@@ -324,4 +329,33 @@ public class FileUtils {
...
@@ -324,4 +329,33 @@ public class FileUtils {
return
FilePath
.
get
(
prefix
).
createTempFile
(
suffix
,
deleteOnExit
,
inTempDir
).
toString
();
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
);
}
}
}
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/tools/Backup.java
浏览文件 @
b6ad6d6a
...
@@ -11,7 +11,6 @@ import java.io.IOException;
...
@@ -11,7 +11,6 @@ import java.io.IOException;
import
java.io.InputStream
;
import
java.io.InputStream
;
import
java.io.OutputStream
;
import
java.io.OutputStream
;
import
java.sql.SQLException
;
import
java.sql.SQLException
;
import
java.util.Arrays
;
import
java.util.List
;
import
java.util.List
;
import
java.util.zip.ZipEntry
;
import
java.util.zip.ZipEntry
;
import
java.util.zip.ZipOutputStream
;
import
java.util.zip.ZipOutputStream
;
...
@@ -109,7 +108,7 @@ public class Backup extends Tool {
...
@@ -109,7 +108,7 @@ public class Backup extends Tool {
List
<
String
>
list
;
List
<
String
>
list
;
boolean
allFiles
=
db
!=
null
&&
db
.
length
()
==
0
;
boolean
allFiles
=
db
!=
null
&&
db
.
length
()
==
0
;
if
(
allFiles
)
{
if
(
allFiles
)
{
list
=
Arrays
.
asList
(
FileUtils
.
listFiles
(
directory
)
);
list
=
FileUtils
.
newDirectoryStream
(
directory
);
}
else
{
}
else
{
list
=
FileLister
.
getDatabaseFiles
(
directory
,
db
,
true
);
list
=
FileLister
.
getDatabaseFiles
(
directory
,
db
,
true
);
}
}
...
@@ -122,7 +121,7 @@ public class Backup extends Tool {
...
@@ -122,7 +121,7 @@ public class Backup extends Tool {
if
(!
quiet
)
{
if
(!
quiet
)
{
FileLister
.
tryUnlockDatabase
(
list
,
"backup"
);
FileLister
.
tryUnlockDatabase
(
list
,
"backup"
);
}
}
zipFileName
=
FileUtils
.
getCanonic
alPath
(
zipFileName
);
zipFileName
=
FileUtils
.
toRe
alPath
(
zipFileName
);
FileUtils
.
delete
(
zipFileName
);
FileUtils
.
delete
(
zipFileName
);
OutputStream
fileOut
=
null
;
OutputStream
fileOut
=
null
;
try
{
try
{
...
@@ -136,7 +135,7 @@ public class Backup extends Tool {
...
@@ -136,7 +135,7 @@ public class Backup extends Tool {
}
}
}
}
for
(
String
fileName
:
list
)
{
for
(
String
fileName
:
list
)
{
String
f
=
FileUtils
.
getCanonic
alPath
(
fileName
);
String
f
=
FileUtils
.
toRe
alPath
(
fileName
);
if
(!
f
.
startsWith
(
base
))
{
if
(!
f
.
startsWith
(
base
))
{
DbException
.
throwInternalError
(
f
+
" does not start with "
+
base
);
DbException
.
throwInternalError
(
f
+
" does not start with "
+
base
);
}
}
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/value/ValueLob.java
浏览文件 @
b6ad6d6a
...
@@ -237,7 +237,7 @@ public class ValueLob extends Value {
...
@@ -237,7 +237,7 @@ public class ValueLob extends Value {
name
=
SysProperties
.
FILE_SEPARATOR
+
f
+
Constants
.
SUFFIX_LOBS_DIRECTORY
+
name
;
name
=
SysProperties
.
FILE_SEPARATOR
+
f
+
Constants
.
SUFFIX_LOBS_DIRECTORY
+
name
;
objectId
/=
SysProperties
.
LOB_FILES_PER_DIRECTORY
;
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
;
return
name
;
}
}
...
@@ -322,12 +322,12 @@ public class ValueLob extends Value {
...
@@ -322,12 +322,12 @@ public class ValueLob extends Value {
SmallLRUCache
<
String
,
String
[]>
cache
=
h
.
getLobFileListCache
();
SmallLRUCache
<
String
,
String
[]>
cache
=
h
.
getLobFileListCache
();
String
[]
list
;
String
[]
list
;
if
(
cache
==
null
)
{
if
(
cache
==
null
)
{
list
=
FileUtils
.
listFiles
(
dir
);
list
=
FileUtils
.
newDirectoryStream
(
dir
).
toArray
(
new
String
[
0
]
);
}
else
{
}
else
{
synchronized
(
cache
)
{
synchronized
(
cache
)
{
list
=
cache
.
get
(
dir
);
list
=
cache
.
get
(
dir
);
if
(
list
==
null
)
{
if
(
list
==
null
)
{
list
=
FileUtils
.
listFiles
(
dir
);
list
=
FileUtils
.
newDirectoryStream
(
dir
).
toArray
(
new
String
[
0
]
);
cache
.
put
(
dir
,
list
);
cache
.
put
(
dir
,
list
);
}
}
}
}
...
@@ -719,7 +719,7 @@ public class ValueLob extends Value {
...
@@ -719,7 +719,7 @@ public class ValueLob extends Value {
}
}
private
static
void
removeAllForTable
(
DataHandler
handler
,
String
dir
,
int
tableId
)
{
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
))
{
if
(
FileUtils
.
isDirectory
(
name
))
{
removeAllForTable
(
handler
,
name
,
tableId
);
removeAllForTable
(
handler
,
name
,
tableId
);
}
else
{
}
else
{
...
...
This diff is collapsed.
Click to expand it.
h2/src/test/org/h2/test/db/TestCases.java
浏览文件 @
b6ad6d6a
...
@@ -17,6 +17,7 @@ import java.sql.SQLException;
...
@@ -17,6 +17,7 @@ import java.sql.SQLException;
import
java.sql.Statement
;
import
java.sql.Statement
;
import
java.sql.Time
;
import
java.sql.Time
;
import
java.sql.Timestamp
;
import
java.sql.Timestamp
;
import
java.util.List
;
import
java.util.Random
;
import
java.util.Random
;
import
org.h2.constant.ErrorCode
;
import
org.h2.constant.ErrorCode
;
import
org.h2.store.fs.FileUtils
;
import
org.h2.store.fs.FileUtils
;
...
@@ -1218,10 +1219,8 @@ public class TestCases extends TestBase {
...
@@ -1218,10 +1219,8 @@ public class TestCases extends TestBase {
conn
.
close
();
conn
.
close
();
String
[]
list
=
FileUtils
.
listFiles
(
getBaseDir
()
+
"/cases.lobs.db"
);
List
<
String
>
list
=
FileUtils
.
newDirectoryStream
(
getBaseDir
()
+
"/cases.lobs.db"
);
if
(
list
!=
null
&&
list
.
length
>
0
)
{
assertEquals
(
"Lob file was not deleted: "
+
list
,
0
,
list
.
size
());
fail
(
"Lob file was not deleted"
);
}
}
}
private
void
testDeleteTop
()
throws
SQLException
{
private
void
testDeleteTop
()
throws
SQLException
{
...
...
This diff is collapsed.
Click to expand it.
h2/src/test/org/h2/test/db/TestLinkedTable.java
浏览文件 @
b6ad6d6a
...
@@ -632,8 +632,7 @@ public class TestLinkedTable extends TestBase {
...
@@ -632,8 +632,7 @@ public class TestLinkedTable extends TestBase {
stat
.
execute
(
"CREATE TABLE TEST(ID INT PRIMARY KEY)"
);
stat
.
execute
(
"CREATE TABLE TEST(ID INT PRIMARY KEY)"
);
conn
.
close
();
conn
.
close
();
String
[]
files
=
FileUtils
.
listFiles
(
getBaseDir
());
for
(
String
file
:
FileUtils
.
newDirectoryStream
(
getBaseDir
()))
{
for
(
String
file
:
files
)
{
String
name
=
FileUtils
.
getName
(
file
);
String
name
=
FileUtils
.
getName
(
file
);
if
((
name
.
startsWith
(
"testLinkedTableInReadOnlyDb"
))
&&
(!
name
.
endsWith
(
".trace.db"
)))
{
if
((
name
.
startsWith
(
"testLinkedTableInReadOnlyDb"
))
&&
(!
name
.
endsWith
(
".trace.db"
)))
{
FileUtils
.
setReadOnly
(
file
);
FileUtils
.
setReadOnly
(
file
);
...
...
This diff is collapsed.
Click to expand it.
h2/src/test/org/h2/test/db/TestLob.java
浏览文件 @
b6ad6d6a
...
@@ -23,6 +23,7 @@ import java.sql.SQLException;
...
@@ -23,6 +23,7 @@ import java.sql.SQLException;
import
java.sql.Savepoint
;
import
java.sql.Savepoint
;
import
java.sql.Statement
;
import
java.sql.Statement
;
import
java.util.ArrayList
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.Random
;
import
java.util.Random
;
import
org.h2.constant.ErrorCode
;
import
org.h2.constant.ErrorCode
;
import
org.h2.constant.SysProperties
;
import
org.h2.constant.SysProperties
;
...
@@ -385,21 +386,21 @@ public class TestLob extends TestBase {
...
@@ -385,21 +386,21 @@ public class TestLob extends TestBase {
stat
.
execute
(
"create table test(id int primary key, name clob)"
);
stat
.
execute
(
"create table test(id int primary key, name clob)"
);
stat
.
execute
(
"insert into test values(1, space(10000))"
);
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"
);
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
(
"create table test(id int primary key, name clob)"
);
stat
.
execute
(
"insert into test values(1, space(10000))"
);
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"
);
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
(
"create table test(id int primary key, name clob)"
);
stat
.
execute
(
"insert into test values(1, space(10000))"
);
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"
);
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
();
conn
.
close
();
}
}
...
@@ -438,13 +439,10 @@ public class TestLob extends TestBase {
...
@@ -438,13 +439,10 @@ public class TestLob extends TestBase {
}
}
private
void
testTempFilesDeleted
()
throws
Exception
{
private
void
testTempFilesDeleted
()
throws
Exception
{
String
[]
list
;
FileUtils
.
deleteRecursive
(
TEMP_DIR
,
true
);
FileUtils
.
deleteRecursive
(
TEMP_DIR
,
true
);
FileUtils
.
createDirectories
(
TEMP_DIR
);
FileUtils
.
createDirectories
(
TEMP_DIR
);
list
=
FileUtils
.
listFiles
(
TEMP_DIR
);
List
<
String
>
list
=
FileUtils
.
newDirectoryStream
(
TEMP_DIR
);
if
(
list
.
length
>
0
)
{
assertEquals
(
"Unexpected temp file: "
+
list
,
0
,
list
.
size
());
fail
(
"Unexpected temp file: "
+
list
[
0
]);
}
deleteDb
(
"lob"
);
deleteDb
(
"lob"
);
Connection
conn
=
getConnection
(
"lob"
);
Connection
conn
=
getConnection
(
"lob"
);
Statement
stat
;
Statement
stat
;
...
@@ -457,10 +455,8 @@ public class TestLob extends TestBase {
...
@@ -457,10 +455,8 @@ public class TestLob extends TestBase {
rs
.
getCharacterStream
(
"name"
).
close
();
rs
.
getCharacterStream
(
"name"
).
close
();
rs
.
close
();
rs
.
close
();
conn
.
close
();
conn
.
close
();
list
=
FileUtils
.
listFiles
(
TEMP_DIR
);
list
=
FileUtils
.
newDirectoryStream
(
TEMP_DIR
);
if
(
list
.
length
>
0
)
{
assertEquals
(
"Unexpected temp file: "
+
list
,
0
,
list
.
size
());
fail
(
"Unexpected temp file: "
+
list
[
0
]);
}
}
}
private
static
void
testAddLobRestart
()
throws
SQLException
{
private
static
void
testAddLobRestart
()
throws
SQLException
{
...
@@ -503,10 +499,10 @@ public class TestLob extends TestBase {
...
@@ -503,10 +499,10 @@ public class TestLob extends TestBase {
Connection
conn
=
getConnection
(
"lob"
);
Connection
conn
=
getConnection
(
"lob"
);
Statement
stat
=
conn
.
createStatement
();
Statement
stat
=
conn
.
createStatement
();
stat
.
execute
(
"create table test(data clob) as select space(100000) from dual"
);
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"
);
stat
.
execute
(
"delete from test"
);
conn
.
close
();
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
{
private
void
testLobServerMemory
()
throws
SQLException
{
...
...
This diff is collapsed.
Click to expand it.
h2/src/test/org/h2/test/db/TestOpenClose.java
浏览文件 @
b6ad6d6a
...
@@ -6,6 +6,8 @@
...
@@ -6,6 +6,8 @@
*/
*/
package
org
.
h2
.
test
.
db
;
package
org
.
h2
.
test
.
db
;
import
java.nio.ByteBuffer
;
import
java.nio.channels.FileChannel
;
import
java.sql.Connection
;
import
java.sql.Connection
;
import
java.sql.DriverManager
;
import
java.sql.DriverManager
;
import
java.sql.PreparedStatement
;
import
java.sql.PreparedStatement
;
...
@@ -14,7 +16,6 @@ import java.sql.SQLException;
...
@@ -14,7 +16,6 @@ import java.sql.SQLException;
import
java.sql.Statement
;
import
java.sql.Statement
;
import
org.h2.api.DatabaseEventListener
;
import
org.h2.api.DatabaseEventListener
;
import
org.h2.constant.ErrorCode
;
import
org.h2.constant.ErrorCode
;
import
org.h2.store.fs.FileObject
;
import
org.h2.store.fs.FileUtils
;
import
org.h2.store.fs.FileUtils
;
import
org.h2.test.TestBase
;
import
org.h2.test.TestBase
;
import
org.h2.tools.Restore
;
import
org.h2.tools.Restore
;
...
@@ -67,10 +68,10 @@ public class TestOpenClose extends TestBase implements DatabaseEventListener {
...
@@ -67,10 +68,10 @@ public class TestOpenClose extends TestBase implements DatabaseEventListener {
conn
=
DriverManager
.
getConnection
(
"jdbc:h2:split:18:"
+
getBaseDir
()
+
"/openClose2"
);
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
.
createStatement
().
execute
(
"create table test(id int, name varchar) as select 1, space(1000000)"
);
conn
.
close
();
conn
.
close
();
File
Object
f
=
FileUtils
.
openFileObject
(
getBaseDir
()
+
"/openClose2.h2.db.1.part"
,
"rw"
);
File
Channel
c
=
FileUtils
.
open
(
getBaseDir
()
+
"/openClose2.h2.db.1.part"
,
"rw"
);
f
.
position
(
f
.
size
()
*
2
-
1
);
c
.
position
(
c
.
size
()
*
2
-
1
);
f
.
write
(
new
byte
[
1
],
0
,
1
);
c
.
write
(
ByteBuffer
.
wrap
(
new
byte
[
1
])
);
f
.
close
();
c
.
close
();
assertThrows
(
ErrorCode
.
IO_EXCEPTION_2
,
this
).
assertThrows
(
ErrorCode
.
IO_EXCEPTION_2
,
this
).
getConnection
(
"jdbc:h2:split:18:"
+
getBaseDir
()
+
"/openClose2"
);
getConnection
(
"jdbc:h2:split:18:"
+
getBaseDir
()
+
"/openClose2"
);
FileUtils
.
delete
(
"split:"
+
getBaseDir
()
+
"/openClose2.h2.db"
);
FileUtils
.
delete
(
"split:"
+
getBaseDir
()
+
"/openClose2.h2.db"
);
...
...
This diff is collapsed.
Click to expand it.
h2/src/test/org/h2/test/unit/TestClearReferences.java
浏览文件 @
b6ad6d6a
...
@@ -68,7 +68,7 @@ public class TestClearReferences extends TestBase {
...
@@ -68,7 +68,7 @@ public class TestClearReferences extends TestBase {
// initialize the known classes
// initialize the known classes
MathUtils
.
secureRandomLong
();
MathUtils
.
secureRandomLong
();
ValueInt
.
get
(
1
);
ValueInt
.
get
(
1
);
Class
.
forName
(
"org.h2.store.fs.File
Object
MemData"
);
Class
.
forName
(
"org.h2.store.fs.FileMemData"
);
clear
();
clear
();
...
...
This diff is collapsed.
Click to expand it.
h2/src/test/org/h2/test/unit/TestFileLockSerialized.java
浏览文件 @
b6ad6d6a
...
@@ -13,7 +13,6 @@ import java.sql.PreparedStatement;
...
@@ -13,7 +13,6 @@ import java.sql.PreparedStatement;
import
java.sql.ResultSet
;
import
java.sql.ResultSet
;
import
java.sql.SQLException
;
import
java.sql.SQLException
;
import
java.sql.Statement
;
import
java.sql.Statement
;
import
java.util.Arrays
;
import
java.util.List
;
import
java.util.List
;
import
org.h2.constant.ErrorCode
;
import
org.h2.constant.ErrorCode
;
import
org.h2.jdbc.JdbcConnection
;
import
org.h2.jdbc.JdbcConnection
;
...
@@ -604,7 +603,7 @@ public class TestFileLockSerialized extends TestBase {
...
@@ -604,7 +603,7 @@ public class TestFileLockSerialized extends TestBase {
stat
.
execute
(
"insert into test values(0)"
);
stat
.
execute
(
"insert into test values(0)"
);
conn
.
close
();
conn
.
close
();
List
<
String
>
filesWithoutSerialized
=
Arrays
.
asList
(
FileUtils
.
listFiles
(
getBaseDir
()
));
List
<
String
>
filesWithoutSerialized
=
FileUtils
.
newDirectoryStream
(
getBaseDir
(
));
deleteDb
(
"fileLockSerialized"
);
deleteDb
(
"fileLockSerialized"
);
// with serialized
// with serialized
...
@@ -616,7 +615,7 @@ public class TestFileLockSerialized extends TestBase {
...
@@ -616,7 +615,7 @@ public class TestFileLockSerialized extends TestBase {
stat
.
execute
(
"insert into test values(0)"
);
stat
.
execute
(
"insert into test values(0)"
);
conn
.
close
();
conn
.
close
();
List
<
String
>
filesWithSerialized
=
Arrays
.
asList
(
FileUtils
.
listFiles
(
getBaseDir
()
));
List
<
String
>
filesWithSerialized
=
FileUtils
.
newDirectoryStream
(
getBaseDir
(
));
if
(
filesWithoutSerialized
.
size
()
!=
filesWithSerialized
.
size
())
{
if
(
filesWithoutSerialized
.
size
()
!=
filesWithSerialized
.
size
())
{
for
(
int
i
=
0
;
i
<
filesWithoutSerialized
.
size
();
i
++)
{
for
(
int
i
=
0
;
i
<
filesWithoutSerialized
.
size
();
i
++)
{
if
(!
filesWithSerialized
.
contains
(
filesWithoutSerialized
.
get
(
i
)))
{
if
(!
filesWithSerialized
.
contains
(
filesWithoutSerialized
.
get
(
i
)))
{
...
...
This diff is collapsed.
Click to expand it.
h2/src/test/org/h2/test/unit/TestFileSystem.java
浏览文件 @
b6ad6d6a
...
@@ -12,6 +12,8 @@ import java.io.IOException;
...
@@ -12,6 +12,8 @@ import java.io.IOException;
import
java.io.InputStream
;
import
java.io.InputStream
;
import
java.io.OutputStream
;
import
java.io.OutputStream
;
import
java.io.RandomAccessFile
;
import
java.io.RandomAccessFile
;
import
java.nio.ByteBuffer
;
import
java.nio.channels.FileChannel
;
import
java.nio.channels.FileLock
;
import
java.nio.channels.FileLock
;
import
java.sql.Connection
;
import
java.sql.Connection
;
import
java.sql.DriverManager
;
import
java.sql.DriverManager
;
...
@@ -21,10 +23,10 @@ import java.sql.Statement;
...
@@ -21,10 +23,10 @@ import java.sql.Statement;
import
java.util.List
;
import
java.util.List
;
import
java.util.Random
;
import
java.util.Random
;
import
org.h2.dev.fs.FilePathCrypt
;
import
org.h2.dev.fs.FilePathCrypt
;
import
org.h2.store.fs.FileObject
;
import
org.h2.store.fs.FilePath
;
import
org.h2.store.fs.FilePath
;
import
org.h2.store.fs.FileUtils
;
import
org.h2.store.fs.FileUtils
;
import
org.h2.test.TestBase
;
import
org.h2.test.TestBase
;
import
org.h2.test.utils.AssertThrows
;
import
org.h2.test.utils.FilePathDebug
;
import
org.h2.test.utils.FilePathDebug
;
import
org.h2.tools.Backup
;
import
org.h2.tools.Backup
;
import
org.h2.tools.DeleteDbFiles
;
import
org.h2.tools.DeleteDbFiles
;
...
@@ -58,7 +60,7 @@ public class TestFileSystem extends TestBase {
...
@@ -58,7 +60,7 @@ public class TestFileSystem extends TestBase {
testDatabaseInJar
();
testDatabaseInJar
();
// set default part size to 1 << 10
// set default part size to 1 << 10
String
f
=
"split:10:"
+
getBaseDir
()
+
"/fs"
;
String
f
=
"split:10:"
+
getBaseDir
()
+
"/fs"
;
FileUtils
.
getCanonic
alPath
(
f
);
FileUtils
.
toRe
alPath
(
f
);
testFileSystem
(
getBaseDir
()
+
"/fs"
);
testFileSystem
(
getBaseDir
()
+
"/fs"
);
testFileSystem
(
"memFS:"
);
testFileSystem
(
"memFS:"
);
testFileSystem
(
"memLZF:"
);
testFileSystem
(
"memLZF:"
);
...
@@ -85,8 +87,7 @@ public class TestFileSystem extends TestBase {
...
@@ -85,8 +87,7 @@ public class TestFileSystem extends TestBase {
private
void
testMemFsDir
()
throws
IOException
{
private
void
testMemFsDir
()
throws
IOException
{
FileUtils
.
newOutputStream
(
"memFS:data/test/a.txt"
,
false
).
close
();
FileUtils
.
newOutputStream
(
"memFS:data/test/a.txt"
,
false
).
close
();
String
[]
list
=
FileUtils
.
listFiles
(
"memFS:data/test"
);
assertEquals
(
1
,
FileUtils
.
newDirectoryStream
(
"memFS:data/test"
).
size
());
assertEquals
(
1
,
list
.
length
);
FileUtils
.
deleteRecursive
(
"memFS:"
,
false
);
FileUtils
.
deleteRecursive
(
"memFS:"
,
false
);
}
}
...
@@ -110,15 +111,15 @@ public class TestFileSystem extends TestBase {
...
@@ -110,15 +111,15 @@ public class TestFileSystem extends TestBase {
private
void
testSimpleExpandTruncateSize
()
throws
Exception
{
private
void
testSimpleExpandTruncateSize
()
throws
Exception
{
String
f
=
"memFS:"
+
getBaseDir
()
+
"/fs/test.data"
;
String
f
=
"memFS:"
+
getBaseDir
()
+
"/fs/test.data"
;
FileUtils
.
createDirectories
(
"memFS:"
+
getBaseDir
()
+
"/fs"
);
FileUtils
.
createDirectories
(
"memFS:"
+
getBaseDir
()
+
"/fs"
);
File
Object
o
=
FileUtils
.
openFileObject
(
f
,
"rw"
);
File
Channel
c
=
FileUtils
.
open
(
f
,
"rw"
);
o
.
position
(
4000
);
c
.
position
(
4000
);
o
.
write
(
new
byte
[
1
],
0
,
1
);
c
.
write
(
ByteBuffer
.
wrap
(
new
byte
[
1
])
);
FileLock
lock
=
o
.
tryLock
();
FileLock
lock
=
c
.
tryLock
();
o
.
truncate
(
0
);
c
.
truncate
(
0
);
if
(
lock
!=
null
)
{
if
(
lock
!=
null
)
{
lock
.
release
();
lock
.
release
();
}
}
o
.
close
();
c
.
close
();
}
}
private
void
testSplitDatabaseInZip
()
throws
SQLException
{
private
void
testSplitDatabaseInZip
()
throws
SQLException
{
...
@@ -184,7 +185,7 @@ public class TestFileSystem extends TestBase {
...
@@ -184,7 +185,7 @@ public class TestFileSystem extends TestBase {
conn
.
close
();
conn
.
close
();
deleteDb
(
"fsJar"
);
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
.
isAbsolute
(
f
));
assertTrue
(!
FileUtils
.
isDirectory
(
f
));
assertTrue
(!
FileUtils
.
isDirectory
(
f
));
assertTrue
(
FileUtils
.
size
(
f
)
>
0
);
assertTrue
(
FileUtils
.
size
(
f
)
>
0
);
...
@@ -209,7 +210,7 @@ public class TestFileSystem extends TestBase {
...
@@ -209,7 +210,7 @@ public class TestFileSystem extends TestBase {
}
}
private
void
testUserHome
()
{
private
void
testUserHome
()
{
String
fileName
=
FileUtils
.
getCanonic
alPath
(
"~/test"
);
String
fileName
=
FileUtils
.
toRe
alPath
(
"~/test"
);
String
userDir
=
System
.
getProperty
(
"user.home"
).
replace
(
'\\'
,
'/'
);
String
userDir
=
System
.
getProperty
(
"user.home"
).
replace
(
'\\'
,
'/'
);
assertTrue
(
fileName
.
startsWith
(
userDir
));
assertTrue
(
fileName
.
startsWith
(
userDir
));
}
}
...
@@ -222,55 +223,64 @@ public class TestFileSystem extends TestBase {
...
@@ -222,55 +223,64 @@ public class TestFileSystem extends TestBase {
private
void
testSimple
(
final
String
fsBase
)
throws
Exception
{
private
void
testSimple
(
final
String
fsBase
)
throws
Exception
{
long
time
=
System
.
currentTimeMillis
();
long
time
=
System
.
currentTimeMillis
();
for
(
String
s
:
FileUtils
.
listFiles
(
fsBase
))
{
for
(
String
s
:
FileUtils
.
newDirectoryStream
(
fsBase
))
{
FileUtils
.
delete
(
s
);
FileUtils
.
delete
(
s
);
}
}
FileUtils
.
createDirectories
(
fsBase
+
"/test"
);
FileUtils
.
createDirectories
(
fsBase
+
"/test"
);
FileUtils
.
delete
(
fsBase
+
"/test"
);
FileUtils
.
delete
(
fsBase
+
"/test"
);
FileUtils
.
delete
(
fsBase
+
"/test2"
);
FileUtils
.
delete
(
fsBase
+
"/test2"
);
assertTrue
(
FileUtils
.
createFile
(
fsBase
+
"/test"
));
assertTrue
(
FileUtils
.
createFile
(
fsBase
+
"/test"
));
List
<
FilePath
>
p
=
FilePath
.
get
(
fsBase
).
listFiles
();
List
<
FilePath
>
p
=
FilePath
.
get
(
fsBase
).
newDirectoryStream
();
assertEquals
(
1
,
p
.
size
());
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
());
assertEquals
(
can
,
p
.
get
(
0
).
toString
());
assertTrue
(
FileUtils
.
canWrite
(
fsBase
+
"/test"
));
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
];
byte
[]
buffer
=
new
byte
[
10000
];
Random
random
=
new
Random
(
1
);
Random
random
=
new
Random
(
1
);
random
.
nextBytes
(
buffer
);
random
.
nextBytes
(
buffer
);
fo
.
write
(
buffer
,
0
,
10000
);
channel
.
write
(
ByteBuffer
.
wrap
(
buffer
)
);
assertEquals
(
10000
,
fo
.
size
());
assertEquals
(
10000
,
channel
.
size
());
fo
.
position
(
20000
);
channel
.
position
(
20000
);
assertEquals
(
20000
,
fo
.
position
());
assertEquals
(
20000
,
channel
.
position
());
assert
Throws
(
EOFException
.
class
,
fo
).
readFully
(
buffer
,
0
,
1
);
assert
Equals
(-
1
,
channel
.
read
(
ByteBuffer
.
wrap
(
buffer
,
0
,
1
))
);
String
path
=
fsBase
+
"/test"
;
String
path
=
fsBase
+
"/test"
;
assertEquals
(
"test"
,
FileUtils
.
getName
(
path
));
assertEquals
(
"test"
,
FileUtils
.
getName
(
path
));
can
=
FilePath
.
get
(
fsBase
).
getCanonic
alPath
().
toString
();
can
=
FilePath
.
get
(
fsBase
).
toRe
alPath
().
toString
();
String
can2
=
FileUtils
.
getCanonic
alPath
(
FileUtils
.
getParent
(
path
));
String
can2
=
FileUtils
.
toRe
alPath
(
FileUtils
.
getParent
(
path
));
assertEquals
(
can
,
can2
);
assertEquals
(
can
,
can2
);
FileLock
lock
=
fo
.
tryLock
();
FileLock
lock
=
channel
.
tryLock
();
if
(
lock
!=
null
)
{
if
(
lock
!=
null
)
{
lock
.
release
();
lock
.
release
();
}
}
assertEquals
(
10000
,
fo
.
size
());
assertEquals
(
10000
,
channel
.
size
());
fo
.
close
();
channel
.
close
();
assertEquals
(
10000
,
FileUtils
.
size
(
fsBase
+
"/test"
));
assertEquals
(
10000
,
FileUtils
.
size
(
fsBase
+
"/test"
));
fo
=
FileUtils
.
openFileObject
(
fsBase
+
"/test"
,
"r"
);
channel
=
FileUtils
.
open
(
fsBase
+
"/test"
,
"r"
);
byte
[]
test
=
new
byte
[
10000
];
final
byte
[]
test
=
new
byte
[
10000
];
fo
.
readFully
(
test
,
0
,
10000
);
FileUtils
.
readFully
(
channel
,
ByteBuffer
.
wrap
(
test
,
0
,
10000
)
);
assertEquals
(
buffer
,
test
);
assertEquals
(
buffer
,
test
);
assertThrows
(
IOException
.
class
,
fo
).
write
(
test
,
0
,
10
);
final
FileChannel
fc
=
channel
;
assertThrows
(
IOException
.
class
,
fo
).
truncate
(
10
);
new
AssertThrows
(
IOException
.
class
)
{
fo
.
close
();
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"
);
long
lastMod
=
FileUtils
.
lastModified
(
fsBase
+
"/test"
);
if
(
lastMod
<
time
-
1999
)
{
if
(
lastMod
<
time
-
1999
)
{
// at most 2 seconds difference
// at most 2 seconds difference
assertEquals
(
time
,
lastMod
);
assertEquals
(
time
,
lastMod
);
}
}
assertEquals
(
10000
,
FileUtils
.
size
(
fsBase
+
"/test"
));
assertEquals
(
10000
,
FileUtils
.
size
(
fsBase
+
"/test"
));
String
[]
list
=
FileUtils
.
listFiles
(
fsBase
);
List
<
String
>
list
=
FileUtils
.
newDirectoryStream
(
fsBase
);
assertEquals
(
1
,
list
.
length
);
assertEquals
(
1
,
list
.
size
()
);
assertTrue
(
list
[
0
]
.
endsWith
(
"test"
));
assertTrue
(
list
.
get
(
0
)
.
endsWith
(
"test"
));
FileUtils
.
copy
(
fsBase
+
"/test"
,
fsBase
+
"/test3"
);
FileUtils
.
copy
(
fsBase
+
"/test"
,
fsBase
+
"/test3"
);
FileUtils
.
moveTo
(
fsBase
+
"/test3"
,
fsBase
+
"/test2"
);
FileUtils
.
moveTo
(
fsBase
+
"/test3"
,
fsBase
+
"/test2"
);
assertTrue
(!
FileUtils
.
exists
(
fsBase
+
"/test3"
));
assertTrue
(!
FileUtils
.
exists
(
fsBase
+
"/test3"
));
...
@@ -314,8 +324,8 @@ public class TestFileSystem extends TestBase {
...
@@ -314,8 +324,8 @@ public class TestFileSystem extends TestBase {
file
.
delete
();
file
.
delete
();
RandomAccessFile
ra
=
new
RandomAccessFile
(
file
,
"rw"
);
RandomAccessFile
ra
=
new
RandomAccessFile
(
file
,
"rw"
);
FileUtils
.
delete
(
s
);
FileUtils
.
delete
(
s
);
File
Object
f
=
FileUtils
.
openFileObject
(
s
,
"rw"
);
File
Channel
f
=
FileUtils
.
open
(
s
,
"rw"
);
assert
Throws
(
EOFException
.
class
,
f
).
readFully
(
new
byte
[
1
],
0
,
1
);
assert
Equals
(-
1
,
f
.
read
(
ByteBuffer
.
wrap
(
new
byte
[
1
]))
);
f
.
force
(
true
);
f
.
force
(
true
);
Random
random
=
new
Random
(
seed
);
Random
random
=
new
Random
(
seed
);
int
size
=
getSize
(
100
,
500
);
int
size
=
getSize
(
100
,
500
);
...
@@ -337,7 +347,7 @@ public class TestFileSystem extends TestBase {
...
@@ -337,7 +347,7 @@ public class TestFileSystem extends TestBase {
random
.
nextBytes
(
buffer
);
random
.
nextBytes
(
buffer
);
trace
(
"write "
+
buffer
.
length
);
trace
(
"write "
+
buffer
.
length
);
buff
.
append
(
"write "
+
buffer
.
length
+
"\n"
);
buff
.
append
(
"write "
+
buffer
.
length
+
"\n"
);
f
.
write
(
buffer
,
0
,
buffer
.
length
);
f
.
write
(
ByteBuffer
.
wrap
(
buffer
)
);
ra
.
write
(
buffer
,
0
,
buffer
.
length
);
ra
.
write
(
buffer
,
0
,
buffer
.
length
);
break
;
break
;
}
}
...
@@ -360,7 +370,11 @@ public class TestFileSystem extends TestBase {
...
@@ -360,7 +370,11 @@ public class TestFileSystem extends TestBase {
byte
[]
b2
=
new
byte
[
len
];
byte
[]
b2
=
new
byte
[
len
];
trace
(
"readFully "
+
len
);
trace
(
"readFully "
+
len
);
ra
.
readFully
(
b1
,
0
,
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"
);
buff
.
append
(
"readFully "
+
len
+
"\n"
);
assertEquals
(
b1
,
b2
);
assertEquals
(
b1
,
b2
);
break
;
break
;
...
@@ -383,7 +397,7 @@ public class TestFileSystem extends TestBase {
...
@@ -383,7 +397,7 @@ public class TestFileSystem extends TestBase {
f
.
close
();
f
.
close
();
ra
.
close
();
ra
.
close
();
ra
=
new
RandomAccessFile
(
file
,
"rw"
);
ra
=
new
RandomAccessFile
(
file
,
"rw"
);
f
=
FileUtils
.
open
FileObject
(
s
,
"rw"
);
f
=
FileUtils
.
open
(
s
,
"rw"
);
assertEquals
(
ra
.
length
(),
f
.
size
());
assertEquals
(
ra
.
length
(),
f
.
size
());
break
;
break
;
}
}
...
...
This diff is collapsed.
Click to expand it.
h2/src/test/org/h2/test/unit/TestPageStoreCoverage.java
浏览文件 @
b6ad6d6a
...
@@ -6,13 +6,13 @@
...
@@ -6,13 +6,13 @@
*/
*/
package
org
.
h2
.
test
.
unit
;
package
org
.
h2
.
test
.
unit
;
import
java.nio.channels.FileChannel
;
import
java.sql.Connection
;
import
java.sql.Connection
;
import
java.sql.ResultSet
;
import
java.sql.ResultSet
;
import
java.sql.SQLException
;
import
java.sql.SQLException
;
import
java.sql.Statement
;
import
java.sql.Statement
;
import
org.h2.constant.ErrorCode
;
import
org.h2.constant.ErrorCode
;
import
org.h2.engine.Constants
;
import
org.h2.engine.Constants
;
import
org.h2.store.fs.FileObject
;
import
org.h2.store.fs.FileUtils
;
import
org.h2.store.fs.FileUtils
;
import
org.h2.test.TestBase
;
import
org.h2.test.TestBase
;
import
org.h2.tools.Restore
;
import
org.h2.tools.Restore
;
...
@@ -229,11 +229,11 @@ public class TestPageStoreCoverage extends TestBase {
...
@@ -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_DATA"
);
stat
.
execute
(
"drop table if exists INFORMATION_SCHEMA.LOB_MAP"
);
stat
.
execute
(
"drop table if exists INFORMATION_SCHEMA.LOB_MAP"
);
conn
.
close
();
conn
.
close
();
File
Object
f
=
FileUtils
.
openFileObject
(
fileName
,
"rw"
);
File
Channel
f
=
FileUtils
.
open
(
fileName
,
"rw"
);
// create a new database
// create a new database
conn
=
getConnection
(
"pageStore"
);
conn
=
getConnection
(
"pageStore"
);
conn
.
close
();
conn
.
close
();
f
=
FileUtils
.
open
FileObject
(
fileName
,
"rw"
);
f
=
FileUtils
.
open
(
fileName
,
"rw"
);
f
.
truncate
(
16
);
f
.
truncate
(
16
);
// create a new database
// create a new database
conn
=
getConnection
(
"pageStore"
);
conn
=
getConnection
(
"pageStore"
);
...
...
This diff is collapsed.
Click to expand it.
h2/src/test/org/h2/test/unit/TestRecovery.java
浏览文件 @
b6ad6d6a
...
@@ -9,12 +9,13 @@ package org.h2.test.unit;
...
@@ -9,12 +9,13 @@ package org.h2.test.unit;
import
java.io.ByteArrayOutputStream
;
import
java.io.ByteArrayOutputStream
;
import
java.io.InputStreamReader
;
import
java.io.InputStreamReader
;
import
java.io.PrintStream
;
import
java.io.PrintStream
;
import
java.nio.ByteBuffer
;
import
java.nio.channels.FileChannel
;
import
java.sql.Connection
;
import
java.sql.Connection
;
import
java.sql.ResultSet
;
import
java.sql.ResultSet
;
import
java.sql.SQLException
;
import
java.sql.SQLException
;
import
java.sql.Statement
;
import
java.sql.Statement
;
import
org.h2.engine.Constants
;
import
org.h2.engine.Constants
;
import
org.h2.store.fs.FileObject
;
import
org.h2.store.fs.FileUtils
;
import
org.h2.store.fs.FileUtils
;
import
org.h2.test.TestBase
;
import
org.h2.test.TestBase
;
import
org.h2.tools.DeleteDbFiles
;
import
org.h2.tools.DeleteDbFiles
;
...
@@ -134,14 +135,14 @@ public class TestRecovery extends TestBase {
...
@@ -134,14 +135,14 @@ public class TestRecovery extends TestBase {
Statement
stat
=
conn
.
createStatement
();
Statement
stat
=
conn
.
createStatement
();
stat
.
execute
(
"create table test(id int, name varchar) as select 1, 'Hello World1'"
);
stat
.
execute
(
"create table test(id int, name varchar) as select 1, 'Hello World1'"
);
conn
.
close
();
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
];
byte
[]
buff
=
new
byte
[
Constants
.
DEFAULT_PAGE_SIZE
];
while
(
f
.
position
()
<
f
.
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
)
{
if
(
new
String
(
buff
).
indexOf
(
"Hello World1"
)
>=
0
)
{
buff
[
buff
.
length
-
1
]++;
buff
[
buff
.
length
-
1
]++;
f
.
position
(
f
.
position
()
-
buff
.
length
);
f
.
position
(
f
.
position
()
-
buff
.
length
);
f
.
write
(
buff
,
0
,
buff
.
length
);
f
.
write
(
ByteBuffer
.
wrap
(
buff
)
);
}
}
}
}
f
.
close
();
f
.
close
();
...
...
This diff is collapsed.
Click to expand it.
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
This diff is collapsed.
Click to expand it.
h2/src/test/org/h2/test/utils/FilePathDebug.java
浏览文件 @
b6ad6d6a
...
@@ -10,8 +10,11 @@ import java.io.FilterInputStream;
...
@@ -10,8 +10,11 @@ import java.io.FilterInputStream;
import
java.io.IOException
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.io.InputStream
;
import
java.io.OutputStream
;
import
java.io.OutputStream
;
import
java.nio.ByteBuffer
;
import
java.nio.channels.FileChannel
;
import
java.nio.channels.FileLock
;
import
java.util.List
;
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.FilePath
;
import
org.h2.store.fs.FilePathWrapper
;
import
org.h2.store.fs.FilePathWrapper
;
...
@@ -116,14 +119,14 @@ public class FilePathDebug extends FilePathWrapper {
...
@@ -116,14 +119,14 @@ public class FilePathDebug extends FilePathWrapper {
return
super
.
size
();
return
super
.
size
();
}
}
public
List
<
FilePath
>
listFiles
()
{
public
List
<
FilePath
>
newDirectoryStream
()
{
trace
(
name
,
"
listFiles
"
);
trace
(
name
,
"
newDirectoryStream
"
);
return
super
.
listFiles
();
return
super
.
newDirectoryStream
();
}
}
public
FilePath
getCanonic
alPath
()
{
public
FilePath
toRe
alPath
()
{
trace
(
name
,
"
getCanonic
alPath"
);
trace
(
name
,
"
toRe
alPath"
);
return
super
.
getCanonic
alPath
();
return
super
.
toRe
alPath
();
}
}
public
InputStream
newInputStream
()
throws
IOException
{
public
InputStream
newInputStream
()
throws
IOException
{
...
@@ -151,9 +154,9 @@ public class FilePathDebug extends FilePathWrapper {
...
@@ -151,9 +154,9 @@ public class FilePathDebug extends FilePathWrapper {
};
};
}
}
public
File
Object
openFileObject
(
String
mode
)
throws
IOException
{
public
File
Channel
open
(
String
mode
)
throws
IOException
{
trace
(
name
,
"open
FileObject
"
,
mode
);
trace
(
name
,
"open"
,
mode
);
return
new
FileDebug
(
this
,
super
.
open
FileObject
(
mode
),
name
);
return
new
FileDebug
(
this
,
super
.
open
(
mode
),
name
);
}
}
public
OutputStream
newOutputStream
(
boolean
append
)
{
public
OutputStream
newOutputStream
(
boolean
append
)
{
...
@@ -211,3 +214,86 @@ public class FilePathDebug extends FilePathWrapper {
...
@@ -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
();
}
}
This diff is collapsed.
Click to expand it.
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
;
}
}
This diff is collapsed.
Click to expand it.
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
;
}
}
This diff is collapsed.
Click to expand it.
h2/src/tools/org/h2/dev/fs/FilePathCrypt.java
浏览文件 @
b6ad6d6a
...
@@ -9,13 +9,22 @@ package org.h2.dev.fs;
...
@@ -9,13 +9,22 @@ package org.h2.dev.fs;
import
java.io.IOException
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.io.InputStream
;
import
java.io.OutputStream
;
import
java.io.OutputStream
;
import
java.nio.ByteBuffer
;
import
java.nio.channels.FileChannel
;
import
java.nio.channels.FileLock
;
import
org.h2.engine.Constants
;
import
org.h2.message.DbException
;
import
org.h2.message.DbException
;
import
org.h2.store.fs.FileObject
;
import
org.h2.security.BlockCipher
;
import
org.h2.store.fs.FileObjectInputStream
;
import
org.h2.security.CipherFactory
;
import
org.h2.store.fs.FileObjectOutputStream
;
import
org.h2.security.SHA256
;
import
org.h2.store.fs.FileBase
;
import
org.h2.store.fs.FileChannelInputStream
;
import
org.h2.store.fs.FileChannelOutputStream
;
import
org.h2.store.fs.FilePath
;
import
org.h2.store.fs.FilePath
;
import
org.h2.store.fs.FilePathWrapper
;
import
org.h2.store.fs.FilePathWrapper
;
import
org.h2.store.fs.FileUtils
;
import
org.h2.store.fs.FileUtils
;
import
org.h2.util.MathUtils
;
import
org.h2.util.StringUtils
;
/**
/**
* A file system that encrypts the contents of the files.
* A file system that encrypts the contents of the files.
...
@@ -40,19 +49,18 @@ public class FilePathCrypt extends FilePathWrapper {
...
@@ -40,19 +49,18 @@ public class FilePathCrypt extends FilePathWrapper {
public
long
size
()
{
public
long
size
()
{
long
len
=
getBase
().
size
();
long
len
=
getBase
().
size
();
return
Math
.
max
(
0
,
len
-
File
ObjectCrypt
.
HEADER_LENGTH
-
FileObject
Crypt
.
BLOCK_SIZE
);
return
Math
.
max
(
0
,
len
-
File
Crypt
.
HEADER_LENGTH
-
File
Crypt
.
BLOCK_SIZE
);
}
}
public
File
Object
openFileObject
(
String
mode
)
throws
IOException
{
public
File
Channel
open
(
String
mode
)
throws
IOException
{
String
[]
parsed
=
parse
(
name
);
String
[]
parsed
=
parse
(
name
);
File
Object
file
=
FileUtils
.
openFileObject
(
parsed
[
2
],
mode
);
File
Channel
file
=
FileUtils
.
open
(
parsed
[
2
],
mode
);
return
new
File
Object
Crypt
(
name
,
parsed
[
0
],
parsed
[
1
],
file
);
return
new
FileCrypt
(
name
,
parsed
[
0
],
parsed
[
1
],
file
);
}
}
public
OutputStream
newOutputStream
(
boolean
append
)
{
public
OutputStream
newOutputStream
(
boolean
append
)
{
try
{
try
{
FileObject
file
=
openFileObject
(
"rw"
);
return
new
FileChannelOutputStream
(
open
(
"rw"
),
append
);
return
new
FileObjectOutputStream
(
file
,
append
);
}
catch
(
IOException
e
)
{
}
catch
(
IOException
e
)
{
throw
DbException
.
convertIOException
(
e
,
name
);
throw
DbException
.
convertIOException
(
e
,
name
);
}
}
...
@@ -60,8 +68,7 @@ public class FilePathCrypt extends FilePathWrapper {
...
@@ -60,8 +68,7 @@ public class FilePathCrypt extends FilePathWrapper {
public
InputStream
newInputStream
()
{
public
InputStream
newInputStream
()
{
try
{
try
{
FileObject
file
=
openFileObject
(
"r"
);
return
new
FileChannelInputStream
(
open
(
"r"
));
return
new
FileObjectInputStream
(
file
);
}
catch
(
IOException
e
)
{
}
catch
(
IOException
e
)
{
throw
DbException
.
convertIOException
(
e
,
name
);
throw
DbException
.
convertIOException
(
e
,
name
);
}
}
...
@@ -99,3 +106,245 @@ public class FilePathCrypt extends FilePathWrapper {
...
@@ -99,3 +106,245 @@ public class FilePathCrypt extends FilePathWrapper {
}
}
}
}
/**
* An encrypted file.
*/
class
FileCrypt
extends
FileBase
{
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
FileChannel
file
;
private
final
BlockCipher
cipher
,
cipherForInitVector
;
private
byte
[]
bufferForInitVector
;
public
FileCrypt
(
String
name
,
String
algorithm
,
String
password
,
FileChannel
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
);
FileUtils
.
writeFully
(
file
,
ByteBuffer
.
wrap
(
HEADER
));
file
.
position
(
SALT_POS
);
FileUtils
.
writeFully
(
file
,
ByteBuffer
.
wrap
(
salt
));
}
else
{
salt
=
new
byte
[
SALT_LENGTH
];
file
.
position
(
SALT_POS
);
FileUtils
.
readFully
(
file
,
ByteBuffer
.
wrap
(
salt
));
}
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
FileChannel
position
(
long
pos
)
throws
IOException
{
file
.
position
(
pos
+
HEADER_LENGTH
);
return
this
;
}
public
void
force
(
boolean
metaData
)
throws
IOException
{
file
.
force
(
metaData
);
}
public
synchronized
FileLock
tryLock
(
long
position
,
long
size
,
boolean
shared
)
throws
IOException
{
return
file
.
tryLock
();
}
public
void
implCloseChannel
()
throws
IOException
{
file
.
close
();
}
public
FileChannel
truncate
(
long
newLength
)
throws
IOException
{
if
(
newLength
>=
size
())
{
return
this
;
}
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
);
}
return
this
;
}
public
int
read
(
ByteBuffer
dst
)
throws
IOException
{
int
len
=
dst
.
remaining
();
if
(
len
==
0
)
{
return
0
;
}
long
pos
=
position
();
len
=
(
int
)
Math
.
min
(
len
,
size
()
-
pos
);
if
(
len
<=
0
)
{
return
-
1
;
}
int
posMod
=
(
int
)
(
pos
%
BLOCK_SIZE
);
if
(
posMod
==
0
&&
len
%
BLOCK_SIZE
==
0
)
{
readAligned
(
pos
,
dst
.
array
(),
dst
.
position
(),
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
,
dst
.
array
(),
dst
.
position
(),
len
);
}
finally
{
position
(
pos
+
len
);
}
}
dst
.
position
(
dst
.
position
()
+
len
);
return
len
;
}
public
int
write
(
ByteBuffer
src
)
throws
IOException
{
int
len
=
src
.
remaining
();
if
(
len
==
0
)
{
return
0
;
}
write
(
src
.
array
(),
src
.
position
(),
len
);
src
.
position
(
src
.
position
()
+
len
);
return
len
;
}
private
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
);
FileUtils
.
writeFully
(
file
,
ByteBuffer
.
wrap
(
new
byte
[
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
);
FileUtils
.
writeFully
(
file
,
ByteBuffer
.
wrap
(
new
byte
[
1
]));
file
.
position
(
pos
);
}
}
private
void
readAligned
(
long
pos
,
byte
[]
b
,
int
off
,
int
len
)
throws
IOException
{
FileUtils
.
readFully
(
file
,
ByteBuffer
.
wrap
(
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
;
}
}
}
FileUtils
.
writeFully
(
file
,
ByteBuffer
.
wrap
(
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
;
}
}
This diff is collapsed.
Click to expand it.
h2/src/tools/org/h2/dev/fs/FilePathZip2.java
浏览文件 @
b6ad6d6a
...
@@ -10,16 +10,20 @@ import java.io.FileNotFoundException;
...
@@ -10,16 +10,20 @@ import java.io.FileNotFoundException;
import
java.io.IOException
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.io.InputStream
;
import
java.io.OutputStream
;
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.ArrayList
;
import
java.util.zip.ZipEntry
;
import
java.util.zip.ZipEntry
;
import
java.util.zip.ZipInputStream
;
import
java.util.zip.ZipInputStream
;
import
org.h2.engine.Constants
;
import
org.h2.engine.Constants
;
import
org.h2.message.DbException
;
import
org.h2.message.DbException
;
import
org.h2.store.fs.File
Object
;
import
org.h2.store.fs.File
Base
;
import
org.h2.store.fs.File
Object
InputStream
;
import
org.h2.store.fs.File
Channel
InputStream
;
import
org.h2.store.fs.FilePath
;
import
org.h2.store.fs.FilePath
;
import
org.h2.store.fs.FilePathDisk
;
import
org.h2.store.fs.FilePathDisk
;
import
org.h2.store.fs.FileUtils
;
import
org.h2.store.fs.FileUtils
;
import
org.h2.util.IOUtils
;
import
org.h2.util.New
;
import
org.h2.util.New
;
/**
/**
...
@@ -184,7 +188,7 @@ public class FilePathZip2 extends FilePath {
...
@@ -184,7 +188,7 @@ public class FilePathZip2 extends FilePath {
}
}
}
}
public
ArrayList
<
FilePath
>
listFiles
()
{
public
ArrayList
<
FilePath
>
newDirectoryStream
()
{
String
path
=
name
;
String
path
=
name
;
try
{
try
{
if
(
path
.
indexOf
(
'!'
)
<
0
)
{
if
(
path
.
indexOf
(
'!'
)
<
0
)
{
...
@@ -218,16 +222,15 @@ public class FilePathZip2 extends FilePath {
...
@@ -218,16 +222,15 @@ public class FilePathZip2 extends FilePath {
}
}
}
}
public
FilePath
getCanonic
alPath
()
{
public
FilePath
toRe
alPath
()
{
return
this
;
return
this
;
}
}
public
InputStream
newInputStream
()
throws
IOException
{
public
InputStream
newInputStream
()
throws
IOException
{
FileObject
file
=
openFileObject
(
"r"
);
return
new
FileChannelInputStream
(
open
(
"r"
));
return
new
FileObjectInputStream
(
file
);
}
}
public
File
Object
openFileObject
(
String
mode
)
throws
IOException
{
public
File
Channel
open
(
String
mode
)
throws
IOException
{
String
entryName
=
getEntryName
();
String
entryName
=
getEntryName
();
if
(
entryName
.
length
()
==
0
)
{
if
(
entryName
.
length
()
==
0
)
{
throw
new
FileNotFoundException
();
throw
new
FileNotFoundException
();
...
@@ -239,7 +242,7 @@ public class FilePathZip2 extends FilePath {
...
@@ -239,7 +242,7 @@ public class FilePathZip2 extends FilePath {
break
;
break
;
}
}
if
(
entry
.
getName
().
equals
(
entryName
))
{
if
(
entry
.
getName
().
equals
(
entryName
))
{
return
new
File
Object
Zip2
(
name
,
entryName
,
in
,
size
());
return
new
FileZip2
(
name
,
entryName
,
in
,
size
());
}
}
in
.
closeEntry
();
in
.
closeEntry
();
}
}
...
@@ -302,3 +305,113 @@ public class FilePathZip2 extends FilePath {
...
@@ -302,3 +305,113 @@ public class FilePathZip2 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
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
This diff is collapsed.
Click to expand it.
h2/src/tools/org/h2/dev/fs/FileShell.java
浏览文件 @
b6ad6d6a
...
@@ -14,6 +14,7 @@ import java.io.InputStream;
...
@@ -14,6 +14,7 @@ import java.io.InputStream;
import
java.io.InputStreamReader
;
import
java.io.InputStreamReader
;
import
java.io.OutputStream
;
import
java.io.OutputStream
;
import
java.io.PrintStream
;
import
java.io.PrintStream
;
import
java.nio.channels.FileChannel
;
import
java.sql.SQLException
;
import
java.sql.SQLException
;
import
java.sql.Timestamp
;
import
java.sql.Timestamp
;
import
java.util.ArrayList
;
import
java.util.ArrayList
;
...
@@ -24,7 +25,6 @@ import org.h2.command.dml.BackupCommand;
...
@@ -24,7 +25,6 @@ import org.h2.command.dml.BackupCommand;
import
org.h2.constant.SysProperties
;
import
org.h2.constant.SysProperties
;
import
org.h2.engine.Constants
;
import
org.h2.engine.Constants
;
import
org.h2.message.DbException
;
import
org.h2.message.DbException
;
import
org.h2.store.fs.FileObject
;
import
org.h2.store.fs.FileUtils
;
import
org.h2.store.fs.FileUtils
;
import
org.h2.util.IOUtils
;
import
org.h2.util.IOUtils
;
import
org.h2.util.New
;
import
org.h2.util.New
;
...
@@ -127,7 +127,7 @@ public class FileShell extends Tool {
...
@@ -127,7 +127,7 @@ public class FileShell extends Tool {
if
(
reader
==
null
)
{
if
(
reader
==
null
)
{
reader
=
new
BufferedReader
(
new
InputStreamReader
(
in
));
reader
=
new
BufferedReader
(
new
InputStreamReader
(
in
));
}
}
println
(
FileUtils
.
getCanonic
alPath
(
currentWorkingDirectory
));
println
(
FileUtils
.
toRe
alPath
(
currentWorkingDirectory
));
while
(
true
)
{
while
(
true
)
{
try
{
try
{
print
(
"> "
);
print
(
"> "
);
...
@@ -212,7 +212,7 @@ public class FileShell extends Tool {
...
@@ -212,7 +212,7 @@ public class FileShell extends Tool {
}
}
end
(
list
,
i
);
end
(
list
,
i
);
println
(
dir
);
println
(
dir
);
for
(
String
file
:
FileUtils
.
listFiles
(
dir
))
{
for
(
String
file
:
FileUtils
.
newDirectoryStream
(
dir
))
{
StringBuilder
buff
=
new
StringBuilder
();
StringBuilder
buff
=
new
StringBuilder
();
buff
.
append
(
FileUtils
.
isDirectory
(
file
)
?
"d"
:
"-"
);
buff
.
append
(
FileUtils
.
isDirectory
(
file
)
?
"d"
:
"-"
);
buff
.
append
(
FileUtils
.
canWrite
(
file
)
?
"rw"
:
"r-"
);
buff
.
append
(
FileUtils
.
canWrite
(
file
)
?
"rw"
:
"r-"
);
...
@@ -236,7 +236,7 @@ public class FileShell extends Tool {
...
@@ -236,7 +236,7 @@ public class FileShell extends Tool {
FileUtils
.
moveTo
(
source
,
target
);
FileUtils
.
moveTo
(
source
,
target
);
}
else
if
(
"pwd"
.
equals
(
c
))
{
}
else
if
(
"pwd"
.
equals
(
c
))
{
end
(
list
,
i
);
end
(
list
,
i
);
println
(
FileUtils
.
getCanonic
alPath
(
currentWorkingDirectory
));
println
(
FileUtils
.
toRe
alPath
(
currentWorkingDirectory
));
}
else
if
(
"rm"
.
equals
(
c
))
{
}
else
if
(
"rm"
.
equals
(
c
))
{
if
(
"-r"
.
equals
(
list
[
i
]))
{
if
(
"-r"
.
equals
(
list
[
i
]))
{
i
++;
i
++;
...
@@ -311,9 +311,9 @@ public class FileShell extends Tool {
...
@@ -311,9 +311,9 @@ public class FileShell extends Tool {
}
}
private
void
truncate
(
String
fileName
,
long
length
)
{
private
void
truncate
(
String
fileName
,
long
length
)
{
File
Object
f
=
null
;
File
Channel
f
=
null
;
try
{
try
{
f
=
FileUtils
.
open
FileObject
(
fileName
,
"rw"
);
f
=
FileUtils
.
open
(
fileName
,
"rw"
);
f
.
truncate
(
length
);
f
.
truncate
(
length
);
}
catch
(
IOException
e
)
{
}
catch
(
IOException
e
)
{
error
(
e
);
error
(
e
);
...
@@ -340,7 +340,7 @@ public class FileShell extends Tool {
...
@@ -340,7 +340,7 @@ public class FileShell extends Tool {
fileOut
=
FileUtils
.
newOutputStream
(
zipFileName
,
false
);
fileOut
=
FileUtils
.
newOutputStream
(
zipFileName
,
false
);
ZipOutputStream
zipOut
=
new
ZipOutputStream
(
fileOut
);
ZipOutputStream
zipOut
=
new
ZipOutputStream
(
fileOut
);
for
(
String
fileName
:
source
)
{
for
(
String
fileName
:
source
)
{
String
f
=
FileUtils
.
getCanonic
alPath
(
fileName
);
String
f
=
FileUtils
.
toRe
alPath
(
fileName
);
if
(!
f
.
startsWith
(
base
))
{
if
(!
f
.
startsWith
(
base
))
{
DbException
.
throwInternalError
(
f
+
" does not start with "
+
base
);
DbException
.
throwInternalError
(
f
+
" does not start with "
+
base
);
}
}
...
@@ -432,7 +432,7 @@ public class FileShell extends Tool {
...
@@ -432,7 +432,7 @@ public class FileShell extends Tool {
private
void
addFilesRecursive
(
String
f
,
ArrayList
<
String
>
target
)
{
private
void
addFilesRecursive
(
String
f
,
ArrayList
<
String
>
target
)
{
if
(
FileUtils
.
isDirectory
(
f
))
{
if
(
FileUtils
.
isDirectory
(
f
))
{
for
(
String
c
:
FileUtils
.
listFiles
(
f
))
{
for
(
String
c
:
FileUtils
.
newDirectoryStream
(
f
))
{
addFilesRecursive
(
c
,
target
);
addFilesRecursive
(
c
,
target
);
}
}
}
else
{
}
else
{
...
@@ -447,7 +447,7 @@ public class FileShell extends Tool {
...
@@ -447,7 +447,7 @@ public class FileShell extends Tool {
String
unwrapped
=
FileUtils
.
unwrap
(
f
);
String
unwrapped
=
FileUtils
.
unwrap
(
f
);
String
prefix
=
f
.
substring
(
0
,
f
.
length
()
-
unwrapped
.
length
());
String
prefix
=
f
.
substring
(
0
,
f
.
length
()
-
unwrapped
.
length
());
f
=
prefix
+
currentWorkingDirectory
+
SysProperties
.
FILE_SEPARATOR
+
unwrapped
;
f
=
prefix
+
currentWorkingDirectory
+
SysProperties
.
FILE_SEPARATOR
+
unwrapped
;
return
FileUtils
.
getCanonic
alPath
(
f
);
return
FileUtils
.
toRe
alPath
(
f
);
}
}
private
void
showHelp
()
{
private
void
showHelp
()
{
...
...
This diff is collapsed.
Click to expand it.
h2/src/tools/org/h2/dev/ftp/server/FtpServer.java
浏览文件 @
b6ad6d6a
...
@@ -292,7 +292,7 @@ public class FtpServer extends Tool implements Service {
...
@@ -292,7 +292,7 @@ public class FtpServer extends Tool implements Service {
*/
*/
String
getDirectoryListing
(
String
directory
,
boolean
listDirectories
)
{
String
getDirectoryListing
(
String
directory
,
boolean
listDirectories
)
{
StringBuilder
buff
=
new
StringBuilder
();
StringBuilder
buff
=
new
StringBuilder
();
for
(
String
fileName
:
FileUtils
.
listFiles
(
directory
))
{
for
(
String
fileName
:
FileUtils
.
newDirectoryStream
(
directory
))
{
if
(!
FileUtils
.
isDirectory
(
fileName
)
||
(
FileUtils
.
isDirectory
(
fileName
)
&&
listDirectories
))
{
if
(!
FileUtils
.
isDirectory
(
fileName
)
||
(
FileUtils
.
isDirectory
(
fileName
)
&&
listDirectories
))
{
appendFile
(
buff
,
fileName
);
appendFile
(
buff
,
fileName
);
}
}
...
@@ -327,7 +327,7 @@ public class FtpServer extends Tool implements Service {
...
@@ -327,7 +327,7 @@ public class FtpServer extends Tool implements Service {
if
(
"-ftpPort"
.
equals
(
a
))
{
if
(
"-ftpPort"
.
equals
(
a
))
{
port
=
Integer
.
decode
(
args
[++
i
]);
port
=
Integer
.
decode
(
args
[++
i
]);
}
else
if
(
"-ftpDir"
.
equals
(
a
))
{
}
else
if
(
"-ftpDir"
.
equals
(
a
))
{
root
=
FileUtils
.
getCanonic
alPath
(
args
[++
i
]);
root
=
FileUtils
.
toRe
alPath
(
args
[++
i
]);
}
else
if
(
"-ftpRead"
.
equals
(
a
))
{
}
else
if
(
"-ftpRead"
.
equals
(
a
))
{
readUserName
=
args
[++
i
];
readUserName
=
args
[++
i
];
}
else
if
(
"-ftpWrite"
.
equals
(
a
))
{
}
else
if
(
"-ftpWrite"
.
equals
(
a
))
{
...
@@ -351,7 +351,7 @@ public class FtpServer extends Tool implements Service {
...
@@ -351,7 +351,7 @@ public class FtpServer extends Tool implements Service {
}
}
public
void
start
()
{
public
void
start
()
{
root
=
FileUtils
.
getCanonic
alPath
(
root
);
root
=
FileUtils
.
toRe
alPath
(
root
);
FileUtils
.
createDirectories
(
root
);
FileUtils
.
createDirectories
(
root
);
serverSocket
=
NetUtils
.
createServerSocket
(
port
,
false
);
serverSocket
=
NetUtils
.
createServerSocket
(
port
,
false
);
port
=
serverSocket
.
getLocalPort
();
port
=
serverSocket
.
getLocalPort
();
...
...
This diff is collapsed.
Click to expand it.
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论