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;
    }
}

Reply via email to