Calling ChangeFileEncryption with a wrong password will correctly throw an
exception.
However, calling it a second time - this time with the correct password -
will still throw an exception ... at least when running on Windows 7. It
does not happen on OS X or Ubuntu.
This is the exception when we call it the second time:
[org.h2.jdbc.JdbcSQLException: Fehler beim Umbenennen der Datei
"C:/Users/jenshohm/AppData/Local/SFX/SFX2Database.h2.db" nach
"C:/Users/jenshohm/AppData/Local/SFX/temp.db"
Error while renaming file
"C:/Users/jenshohm/AppData/Local/SFX/SFX2Database.h2.db" to
"C:/Users/jenshohm/AppData/Local/SFX/temp.db" [90024-173]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:331)
at org.h2.message.DbException.get(DbException.java:171)
at org.h2.store.fs.FilePathDisk.moveTo(FilePathDisk.java:104)
at org.h2.store.fs.FileUtils.moveTo(FileUtils.java:114)
at org.h2.tools.ChangeFileEncryption.process(ChangeFileEncryption.java:162)
at org.h2.tools.ChangeFileEncryption.execute(ChangeFileEncryption.java:128)
The problems seems to be that ChangeFileEncryption opens a FileStore but
never closes it which will keep the file locked after the failed first
attempt (at least on Windows 7). This will prevent the file to be renamed
on the second run.
I think the process() method should close the FileStore that it opens here:
https://code.google.com/p/h2database/source/browse/trunk/h2/src/main/org/h2/tools/ChangeFileEncryption.java#204
which
try { // added
in.init();
copy(fileName, in, encrypt);
} finally { // added
in.close(); // added
} // added
I've attached a Junit 4 Test to reproduce the problem when it is run on
Windows 7.
Thanks!
Best regards,
Jens
PS: I've just made a copy of ChangeFileEncryption.java and added the try /
finally blocks to close the FileStore and it seems to have fixed the issue
for us.
--
You received this message because you are subscribed to the Google Groups "H2
Database" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/h2-database.
For more options, visit https://groups.google.com/d/optout.
import org.h2.store.fs.FilePath;
import org.h2.tools.ChangeFileEncryption;
import org.junit.Before;
import org.junit.Test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
import static org.junit.Assert.fail;
public class DbChangeFileEncryptionLockBugTest {
private final String dbUrl = "jdbc:h2:file-encryption;CIPHER=AES";
@Before
public void before() throws Exception {
FilePath.get("./file-encryption.h2.db").delete();
Class.forName("org.h2.Driver");
}
@Test
public void test() throws Exception {
checkConnection("oldpass userpass");
try {
changeEncryption("wrongpass", "newpass");
fail("expected exception");
} catch (Exception e) {
// this is an expected exception because the wrong pass is given
}
// on Windows 7 the following line will fail with an:
//
// org.h2.jdbc.JdbcSQLException: Fehler beim Umbenennen der Datei ... [90024-173]
// at org.h2.message.DbException.getJdbcSQLException(DbException.java:331)
// at org.h2.message.DbException.get(DbException.java:171)
// at org.h2.store.fs.FilePathDisk.moveTo(FilePathDisk.java:104)
// at org.h2.store.fs.FileUtils.moveTo(FileUtils.java:114)
// at org.h2.tools.ChangeFileEncryption.process(ChangeFileEncryption.java:162)
// at org.h2.tools.ChangeFileEncryption.execute(ChangeFileEncryption.java:128)
changeEncryption("oldpass", "newpass");
checkConnection("newpass userpass");
}
private void changeEncryption(final String oldPass, final String newPass) throws SQLException {
ChangeFileEncryption.execute(
".", "file-encryption", "AES", oldPass.toCharArray(), newPass.toCharArray(), false);
}
private void checkConnection(final String password) throws SQLException {
try (Connection conn = DriverManager.getConnection(dbUrl, makeProp(password))) {
Statement statement = conn.createStatement();
statement.executeUpdate("SHUTDOWN");
}
}
private Properties makeProp(final String password) {
Properties prop = new Properties();
prop.put("user", "username");
prop.put("password", password);
return prop;
}
}