3

Update 3

Progress! I wrote a CMD script which takes three parameters:

  1. the absolute path to sqlite3cipher.exe
  2. the absolute path to testdb
  3. the absolute path to statements.sql

All the script does is execute the command

path\to\sqlite3cipher.exe path\to\testdb < path\to\statements.sql

This script is being called from within my Java code. And it works like a charm! At least with all the files residing in a folder in my home directory. Having the files in a subfolder of C:\Program Files doesn't work so there might be an issue with privileges which I have to work out with the administrator.


Update 2

I've created a dummy SQL file in my home directory. The code should now read the SQL file from and write the database file to my home directory.

Again omitting cmd /c in the command reads and writes the first line from the SQL file but stops after that (execution of the whole program comes to a halt). Executing the command including cmd /c reads and writes every single line of the SQL file but once EOF is reached (in which case nothing will be written of course) I again get the Access denied message.


Update 1

Taking skarist's comment into account the following command (omitting cmd /c as it isn't mandatory for executing exe-files after all)

String cmdForRuntime = "\"" + prog.getAbsolutePath() + "\" \"" + fDb.getAbsolutePath() + "\"";

which spelled out looks like

"C:\Program Files\Apache Software Foundation\bin\sqlite3cipher.exe" "C:\Program Files\Apache Software Foundation\pages\dbdir\testdb"

doesn't produce any output. Also the code stops executing, so I assume there's something wrong with the I/O?


Problem

In order to encode a database I want to execute sqlite3cipher.exe on the command line in Java.

I ran into quite some diverging results for various approaches. At first the setup (notice that this is a testing environment where right now nothing can be changed regarding where files are located):

  • sqlite3cipher.exeresides in C:\Program Files\Apache Software Foundation\bin\

  • an empty file testdbresides in C:\Program Files\Apache Software Foundation\pages\dbdir\

  • a file containing SQL statements statements.sql resides in the same folder as testdb does

Executing sqlite3cipher.exe -help on the command line prints the usage. Here is an exerpt:

C:\Program Files\Apache Software Foundation\bin\sqlite3cipher.exe [OPTIONS] FILENAME [SQL] 
FILENAME is the name of an SQLite database. A new database is created if the file does not previously exist.

Executing "C:\Program Files\Apache Software Foundation\bin\sqlite3cipher.exe" "C:\Program Files\Apache Software Foundation\pages\dbdir\testdb" < "C:\Program Files\Apache Software Foundation\pages\dbdir\statements.sql" on the command line has the desired effect: testdb now is an encrypted database according to the SQL statements that were put in through the statements.sql.

Now in Java my code looks like this:

String cmdForRuntime = "cmd /C \"" + prog.getAbsolutePath() + "\" \"" + fDb.getAbsolutePath() + "\" < \"" + fSqlScript.getAbsolutePath() + "\"";
Process process = Runtime.getRuntime().exec( cmdForRuntime );

BufferedReader stdIn = new BufferedReader(new InputStreamReader(process.getInputStream()));
String s;

while ((s = stdIn.readLine()) != null) {
    logger.info("OUTPUT FROM PROG: " + s);
}

if (process.waitFor() == 0) {
    logger.info("Process finished");
}
else {
    logger.error("Error!");

    // Get input streams
    BufferedReader stdError = new BufferedReader(new InputStreamReader(process.getErrorStream()));

    System.out.println("Standard error: ");
    while ((s = stdError.readLine()) != null) {
        System.out.println(s);
    }
}

where prog , fDb and fSqlScript are of type File and represent sqlite3cipher.exe, testdb and statements.sql respectively.

I'm not well versed with Process.execute() but what I gathered from reading about it is that cmd /c as part of the command is required on Windows (the test server is running Windows 8) in order to start the command interpreter.

On execution this code returns Access denied on the command line (via the process's streams). Executing this exact command (including cmd /c) on the command line directly returns the same result: Access denied. Even if I start the command line as administrator.

Leaving cmd /c out of the command (because it had worked without on the command line before), I get the message that there are too many options. On further investigation, I learned that this problem is caused by the < operator, used in the command to redirect the input. The exec() method won't recognize < as an operator and it was suggested to use the process's OutputStream. So I changed my code to look like this:

String cmdForRuntime = "cmd /c \"" + prog.getAbsolutePath() + "\" \"" + fDb.getAbsolutePath() + "\"";
Process process = Runtime.getRuntime().exec( cmdForRuntime );

BufferedWriter bufferedwriter = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
BufferedReader br = new BufferedReader(new FileReader(fSqlScript.getAbsolutePath()));

BufferedReader stdIn = new BufferedReader(new InputStreamReader(process.getInputStream()));
String s;
String fileInput = br.readLine();

while (fileInput != null) {

    bufferedwriter.write(fileInput);

    while ((s = stdIn.readLine()) != null) {
        logger.info("OUTPUT FROM PROG: " + s);
    }

    fileInput = br.readLine();
}

if (process.waitFor() == 0) {
    logger.info("Process finished");
}
else {
    logger.error("Error!");

    // Get input streams
    BufferedReader stdError = new BufferedReader(new InputStreamReader(process.getErrorStream()));

    System.out.println("Standard error: ");
    while ((s = stdError.readLine()) != null) {
        System.out.println(s);
    }
}

As I understand it is important to read what the external program prints out so it won't block or stop working. That's why I read a line from statements.sql (through the BufferedReader br) and write it to the process's OutputStream. Then I read what the program will print out (logging that output). If there is nothing (left) to read I read the next line from the statements.sql. This will be repeated until there is nothing left to read from said file.

If I execute this code, my logger will log the following:

INFO  Executing command: cmd /c "C:\Program Files\Apache Software Foundation\bin\sqlite3cipher.exe" "C:\Program Files\Apache Software Foundation\pages\dbdir\testdb"
ERROR Error!
Standard error: 
Access denied

In this case, the code at least terminates resulting in an empty file testdb. In another approach I left cmd in the command but skipped the /c resulting in following output:

INFO  Executing command: cmd "C:\Program Files\Apache Software Foundation\bin\sqlite3cipher.exe" "C:\Program Files\Apache Software Foundation\pages\dbdir\testdb"
INFO  OUTPUT FROM PROG: Microsoft Windows [Version 6.3.9600]
INFO  OUTPUT FROM PROG: (c) 2013 Microsoft Corporation. Alle Rechte vorbehalten.
INFO  OUTPUT FROM PROG: 

The output is the same you get when you type cmd on the command line. And that's where execution stops.


tl;dr

  • execution on command line directly works like a charm
  • exact same command executed from Java doesn't work
  • command prepended by cmd /c (as it apparently should be) and usage of the process's InputStream and OutputStream doesn't work: Access denied

I'm not sure what to do next, so I sincerely hope someone can help me.

8
  • Why do you think you need the "cmd /C". You don't need the command interperted to execute .exe files. Check this link here: stackoverflow.com/questions/13991007/… Commented Jul 10, 2014 at 11:48
  • I've updated the post. I've omitted cmd /c in the command resulting with the execution to stop. No output is read. Commented Jul 10, 2014 at 12:36
  • seems like UAC issue! is ur program running in Elevated mode? Commented Jul 10, 2014 at 12:36
  • I've started Tomcat (who then executes said code) in elevated mode. Once with cmd /c in the command (again Access denied), once without (no output at all and code execution stops). Commented Jul 10, 2014 at 12:54
  • Any antivirus running? Try to disable. Can you try in safe mode (I assumed you are using windows) Commented Jul 10, 2014 at 14:40

2 Answers 2

1

So I solved the problem with the workaround I mentioned in update 3.

My Java code now looks like this (besides the cmdForRuntime variable it should be pretty much the same code as in the beginning, when I asked this question):

try {
        File fDb = new File(this.inputDirectory + File.separator + dbName);

        String cmdForRuntime =  "\"" + cmdScript.getAbsolutePath() + "\"" + " " +       // the script to be executed 
                                "\"" + prog.getAbsolutePath() + "\"" + " " +            // sqlite3cipher.exe
                                "\"" + fDb.getAbsolutePath() + "\"" + " " +             // testdb
                                "\"" + fSqlScript.getAbsolutePath() + "\"";             // statements.sql

        logger.info("Executing command: " + cmdForRuntime );

        Process process = Runtime.getRuntime().exec( cmdForRuntime );

        BufferedReader stdIn = new BufferedReader(new InputStreamReader(process.getInputStream()));
        String s;

        while ((s = stdIn.readLine()) != null) {
            logger.info("OUTPUT FROM PROG: " + s);
        }

        if (process.waitFor() == 0) {
            logger.info("Process finished");
        }
        else {
            logger.error("!!!! error !!!!");
            // Get input streams
            BufferedReader stdError = new BufferedReader(new InputStreamReader(process.getErrorStream()));

            System.out.println("Standard error: ");
            while ((s = stdError.readLine()) != null) {
                System.out.println(s);
            }
        }
    }
    catch(Exception ioe) {
        ioe.printStackTrace();
    }       

cmdForRuntime will read something like this (I will omit the paths, the only add to the confusion):

"SQLiteCipher.cmd" "sqlite3cipher.exe" "testdb" "statements.sql"

The content of the script looks like this:

%1 %2 < %3

This will invoke the sqlite3cipher.exe with the parameter testdb and a redirected input coming from statements.sql.

Critical is that the location of the script as well as the location of the exe is not a system folder.

If all these criteria are met everything works like a charm.

Sign up to request clarification or add additional context in comments.

Comments

0

You are having User Account Control issue.

It seems like the program is running in non-elevated mode, to make changes to system directories the application need to run in elevated mode.

Running you program in elevated mode should solve the problem.

1 Comment

I'm afraid not. I've started Tomcat in elevated mode (Run as administrator) with the exact same outcome.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.