1

I recently migrated a tomcat application from one Linux server to another. Since then, I am facing a new file creation issue on the new server. In the new server, when I try to create a file it fails, which works fine in the old server:

File convFile = new File(file.getOriginalFilename());
convFile.createNewFile(); //this FAILS
FileOutputStream fos = new FileOutputStream(convFile);
fos.write(file.getBytes());
fos.close();

To investigate the issue, I printed the working directory using:

String cwd = new File("").getAbsolutePath();
System.out.println(cwd);

And this debugging revealed the root cause behind the issue: The old server returned: var/lib/tomcat, whereas the new server returned: / (the root directory) As the tomcat user did not (and should not) have write permission on root directory, it failed to create the file.

My question, which factor decides the current working directory of Tomcat, and how to configure it?

Here are my Tomcat and java environment variables.

Environment="JAVA_HOME=/usr/lib/jvm/jre"
Environment="JAVA_OPTS=-Djava.security.egd=file:///dev/urandom"

Environment="CATALINA_BASE=/opt/tomcat"
Environment="CATALINA_HOME=/opt/tomcat"

Update: I tried -Duser.dir to configure the working directory. After using this, I get expected result from System.out.println(cwd);. But the issue still persists, the file creation fails. apparently, this does not work for FileOutputStreams.

Source: Changing the current working directory in Java?

The ownership and permissions are handled properly. I am looking for a system-side solution without making any code change, as the same code is working in the old server.

jww
  • 97,681
  • 90
  • 411
  • 885
Md.
  • 496
  • 4
  • 11
  • 3
    A web application should ***never*** rely on the working directory. A servlet container can serve multiple web applications, and they might otherwise want different working directories, and that cannot happen, so don't ever rely on working directory for anything in a web application. Always use absolute paths any time the code needs to use the file system, which should in itself be rare, other than temporary files. – Andreas Oct 28 '19 at 22:17
  • How convFile.createNewFile(); fails? What is the Exception and message ? – jordiburgos Oct 28 '19 at 22:26
  • You should be using `ServletContext.getRealPath()`, not the current working directory, so as to get a per-servlet path. – user207421 Oct 28 '19 at 22:29
  • @jordiburgos Here is the details: 25-Oct-2019 11:52:37.029 SEVERE [ajp-nio-8009-exec-45] controller.FileUploadController.convert null java.io.IOException: Permission denied at java.io.UnixFileSystem.createFileExclusively(Native Method) at java.io.File.createNewFile(File.java:1012) at ca.pbl.smart.controller.FileUploadController.convert(FileUploadController.java:449) – Md. Oct 28 '19 at 22:33
  • So, "Permission denied", change the folder where you try to create the new file. – jordiburgos Oct 28 '19 at 22:36
  • @jordiburgos I am looking for a system-side solution without making any code change, as the same code is working in the old server. – Md. Oct 28 '19 at 22:40
  • In fact `createNewFile()` is redundant and wasteful here, as `new FileOutputStream()` will now have to delete it and create another one. Remove. – user207421 Oct 28 '19 at 22:41
  • `getRealPath()` will work on both servers, but there is something wrong with the way you are starting this Tomcat. – user207421 Oct 28 '19 at 22:42

1 Answers1

1

I'm doing startup with systemd on RHEL 8.3.

For that, I found that adding this stanza before the ExecStart got desired result:

WorkingDirectory=/data/desired/catalina_base

YMMV with other flavours and startup options - just use absolute path for both ExecStart & WorkingDirectory

Full platform:

Server version name:   Apache Tomcat/9.0.54
Server built:          Sep 28 2021 13:51:49 UTC
Server version number: 9.0.54.0
OS Name:               Linux
OS Version:            4.18.0-240.22.1.el8_3.x86_64
Architecture:          amd64
Java Home:             /usr/lib/jvm/java-11-openjdk-11.0.10.0.9-4.el8_3.x86_64
JVM Version:           11.0.10+9-LTS
JVM Vendor:            Red Hat, Inc.
Jacob Zwiers
  • 1,092
  • 1
  • 13
  • 33