Does the File Separator Matter for Java File Paths? - java

I'm pentesting a Java web application that uploads a file to the server. It uses an old library - com.jspsmart.upload.smartupload - which as far as I know should work. The saveAs method requires a path where the file should be saved. I've tried uploading files and cannot get it to work. I feel like the issue might be with the file path. If the install directory is something like C:\my_app the path would be C:\my_app\uploads/filename.txt. Does this matter? Or might something else be causing it not to upload? The upload code is surrounded by a try/catch and doesn't return an exception, so I'm not sure why it wouldn't work.
Some documentation I found on the library: http://demo.easyhis.com/jspsmartupload/help/doc/com/jspsmart/upload/File.html
Sample code:
private static string FS = System.getProperty("file.separator");
try {
myFile = myUpload.getFiles().getFile(0);
importFolder = Globals.getInstallDir() + FS + "uploads";
myFile.saveAs( importFolder + "/" + request.getParameter("import_file_name"), SmartUpload.SAVE_PHYSICAL);
} catch (Exception e) {
// outputs error
}

Java can indifferently use / or \ as a file separator under Windows, but it is one or the other -- don't do both!
Anyway, use Path, you will then be sure that you get a correct path to work with:
Paths.get(Globals.getInstallDir()).resolve(FS).resolve("uploads")
.resolve("import_file_name").toString();
Note that FS should NOT be absolute here (ie, no beginning / or \).

Use File.separator. It returns the system's default path to a specific file separator.
private static string FS = File.separator;

Related

How to Write Output Files from a JAR Program to Directory Outside the JAR?

tl;dr I'm more used to writing command-line scripts that can just output based on the current working directory, so I'm unsure what directory to use for output files in a program that will be launched from a JAR.
Program Description:
My program builds an HTML file from data given to it from the rest of the program, and then is supposed to write it to a file that we'll call "Output.html" for simplicity.
Relevant Code:
public void outputHTML()
{
String output = buildHTML();
// Expanded to explain my confusion better
String fileDirectory = ""; // ???
String fileName = "Output.html";
String fullPath = fileDirectory + "\\" + fileName;
try (BufferedWriter writer = new BufferedWriter(new FileWriter(fullPath)))
{
writer.write(output);
writer.close();
} catch (IOException e)
{
System.out.println("File not found.");
e.printStackTrace();
}
}
Problem
I don't know what to put the file directory as. Usually I run my programs from the command line and use ".\\Output.txt" as my output path, but I don't know where to put it if it's being run from a JAR.
The desired file structure is as follows:
Encompassing Folder
Program.jar
output
Output.html
Or alternatively (not sure if this makes it easier to understand or harder):
main\
main\Program.jar
main\output\
main\output\Output.html
Everything I can find on SE only relates to reading files that are both immutable and internal, but I'm trying to output a non-static file to a location outside of my jar.
Can anyone help with this? Thanks!
Misc Details
I'm using Eclipse without Gradle currently, because I don't know what Gradle is and new things are scary. If this particular problem would be easier to solve with Gradle, let me know and I'll look up more about it.
EDIT:
Added syntax highlighting to code block.
Formatted everything a bit better
Changed title to be more descriptive
You can use an absolute path: e.g. fileDirectory = "\\project\\test\\main\\output";
using normal slash should also work even on Windows ("/project/test/main/output")
Or use a relative path - this will start from the current working directory (user directory), the one where the JVM was started in - e.g. fileDirectory = "main\\output";

Is there a way to get the path of a File with "/" instead of "\"?

I am making an HTTP Server in Java so that (on start) it finds all files in a directory (and it's sub-directories) and adds them to the server. But when getting the path of a file and trying to give it to HttpServer.createContext(), it throws a java.lang.IllegalArgumentException: Illegal value for path or protocol. (with the string argument, say "\folder/index.html"). To get this value, I used
file.getParent().substring(24) + "/" + file.getName()
I used substring because I had to exclude the folder the web server is in. The illegal character is the backslash. I have tried extending File to change separator and separatorChar, but that only created 2 new variables. While using String.replace() didn't seem to have any effect. Is there a different method than File.getParent or File.getPath that I can use, or is there a way to use String.replace that I am not seeing?
EDIT:
String.replace() seems to be the best answer... But I am not completely sure how to use it.
EDIT 2: For some reason the backslash isn't showing up, so I changed it.
You have to use the java System.getProperty.
Notice that, in this context, "file.separator" is a key which we are
using to get this property from current system executing the java VM.
Insteady of using a slash (/), you should choose a platform agnostic file separator, as an example it should be:
String separator = System.getProperty("file.separator");
System.out.println(separator);
// unix / , windows \
Have a look at Paths.get(...)
Try Paths.get(".") // current working directory.
Or tell it, on which path it should start:
Use System.getProperty("user.dir"), for current loged in user, home directory.
String pathStr = "/";
Path homeDir = Paths.get(System.getProperty("user.dir"))
Getting from the user directory into the data directory: homeDir.get("data")
Path dataPath = Paths.get(System.getProperty("user.dir"));
File dataFile = dataPath.toFile();
Now use operations on dataFile, to check what files and directories there are, on that location of the file system.

windows - User folder with special character -> class.getResource returns null [duplicate]

The getResourceAsStream-method returns null whenever running the executable jar in a directory which ends with a exclamation mark.
For the following example, I have a Eclipse project the following directory structure:
src\ (Source Folder)
main\ (Package)
Main.java
res\ (Source Folder)
images\
Logo.png
I'm reading the Logo.png as follows:
public static void main(String[] args) throws IOException {
try (InputStream is = Main.class.getClassLoader().getResourceAsStream("images/Logo.png")) {
Image image = ImageIO.read(is);
System.out.println(image);
}
}
See the attachment for 2 test cases. First, the executable jar is started from the directory "D:\test123!##" without any problems. Secondly, the executable jar is started from the directory "D:\test123!##!!!", with problems.
Are directories ending with an exclamation mark not supported? Is the code wrong?
Thanks in advance.
Probably because of this bug or any of the many similar bugs in the Java bug database:
http://bugs.sun.com/view_bug.do?bug_id=4523159
The reason is that "!/" in a jar URL is interpreted as the separator between the JAR file name and the path within the JAR itself. If a directory name ends with !, the "!/" character sequence at the end of the directory is incorrectly interpreted. In your case, you are actually trying to access a resource with the following URL:
jar:file:///d:/test1231##!!!/test.jar!/images/Logo.png
The bug has been open for almost 12 years and is not likely to be fixed. Actually I don't know how it can be fixed without breaking other things. The problem is the design decision to use ! as a character with a special meaning (separator) in the URL scheme for JAR files:
jar:<URL for JAR file>!/<path within the JAR file>
Since the exclamation mark is an allowed character in URLs, it may occur both in the URL to the JAR file itself, as well as in the path within the JAR file, making it impossible in some cases to find the actual "!/" separator.
A simple work around for Windows is to use "\" instead of "/" in the path. That would mean the "!/" character sequence is found after the full path. For instance:
new URL("jar:file:\\d:\\test1231##!!!\\test.jar!/images/Logo.png");
My Code:
File jar = new File(jarPath + "/" + jarName);
URL url = new URL("jar:" + jar.toURI() + "!" + dataFilePath);
InputStream stream = null;
try {
stream = url.openStream();
} catch (FileNotFoundException e) {
// Windows fix
URL urlFix = new URL("jar:" + jar.toURI().toString().replace('/', '\\')
+ "!" + dataFilePath);
stream = urlFix.openStream();
}
I use toURI() because it handles things like spaces.
Fixes:
The fix itself would be for Java to check if the file exists and if not continue to the next separator (the "!/" part of the url) until the separators are exhausted, then throw the exception. So it would see that "d:\test1231##!!" throws a java.io.FileNotFoundException and would then try "d:\test1231##!!!\test.jar" which does exist. This way it does not matter if there are "!" in the file path or in the jar's files.
Alternatively the "!/" can be switched to something else that is an illegal file name or to something specific (like "jarpath:").
Alternatively make the jar's file path use another parameter.
Note:
It may be possible to override something, swap a handler, or change the code to open the file first then look inside the jar file later but I have not looked.

Convert Windows style path into unix path in java code

I am working in a java code that was designed to run on windows and contains a lot of references to files using windows style paths "System.getProperty("user.dir")\trash\blah". I am in charge to adapt it and deploy in linux. Is there an efficient way to convert all those paths(\) to unix style (/) like in "System.getProperty("user.dir")/trash/blah". Maybe, some configuration in java or linux to use \ as /.
My approach is to use the Path object to hold the path information, handle concatenate and relative path. Then, call Path's toString() to get the path String.
For converting the path separator, I preferred to use the apache common io library's FilenameUtils. It provides the three usefule functions:
String separatorsToSystem(String path);
String separatorsToUnix(String path);
String separatorsToWindows(String path)
Please look the code snippet, for relative path, toString, and separator changes:
private String getRelativePathString(String volume, Path path) {
Path volumePath = Paths.get(configuration.getPathForVolume(volume));
Path relativePath = volumePath.relativize(path);
return FilenameUtils.separatorsToUnix(relativePath.toString());
}
I reread your question and realize you likely don't need help writing paths. For what you're trying to do I am not able to find a solution. When I did this in a project recently I had to take time to convert all paths. Further, I made the assumption that working out of the "user.home" as a root directory was relatively sure to include write access for that user running my application. In any case, here are some path problems I addressed.
I rewrote the original Windows code like so:
String windowsPath = "C:\temp\directory"; //no permission or non-existing in osx or linux
String otherWindowsPath = System.getProperty("user.home") + "\Documents\AppFolder";
String multiPlatformPath = System.getProperty("user.home") + File.separator + "Documents" + File.separator + "AppFolder";
If you're going to be doing this in a lot of different places, perhaps write a utility class and override the toString() method to give you your unix path over and over again.
String otherWindowsPath = System.getProperty("user.home") + "\Documents\AppFolder";
otherWindowsPath.replace("\\", File.separator);
Write a script, replace all "\\" with a single forward slash, which Java will convert to the respected OS path.

Reading .txt File From Relative Path in Java

I know this question has been asked in a myriad of variations, but today I wish to emphasize one particular scenario when one wishes to read from a .txt file without specifying the absolute path.
Suppose we have the following set up in Eclipse.
projectName/packageName/subPackage/
and we have a class named Read.java inside the subPackage. The class will be attempting to read from the input1.txt.
We also have input1.txt inside the very same subPackage.
If one uses absolute paths, the code inside Read.java will be something of the following (let's assume now that input1.txt is placed on my Desktop for illustration purposes):
// Create a list to store the list of strings from each line of the input1.txt.
LinkedList<String> inputStrings = new LinkedList<String>();
BufferedReader bufferedTextIn = null;
try {
String line;
// Specify the file
String fileName = "C:" + File.separator
+ "Users" + File.separator
+ "Kevin" + File.separator
+ "Desktop" + File.separator
+ "input1.txt";
bufferedTextIn = new BufferedReader(new FileReader(fileName));
while ((line = bufferedTextIn.readLine()) != null) {
inputStrings.add(line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (bufferedTextIn != null) {
bufferedTextIn.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
The problem with the above is the use of absolute paths to my desktop. If I passed the code to my friend, he would need to manually change the path to his desktop. Even if I put input1.txt in my project folder, my friend would still need to manually change the path to make it work.
Note that using File.separator is a good practice because different OS interprets separators a bit differently, but it is still insufficient.
So what do we do instead?
Here is my solution.
String fileName = Read.class.getResource("input1.txt").getPath();
System.out.println(fileName);
bufferedTextIn = new BufferedReader(new FileReader(fileName));
Let's recap the scenario. We have our input1.txt file placed in the SAME FOLDER as the Read.java. So, the code above attempts to go to where Read.class exists (which is somewhere in the bin folder in Eclipse), and look for input1.txt. This is the path RELATIVE to where Read.class is located (in this case, it is trivially in the same folder, but you could very well specify another folder relative to where Read.class is located). The print statement lets you know exactly where it is located and is a good practice while debugging.
When you build in Eclipse, the .java files in the src folder would be compiled into .class files and be placed in the bin folder. The neat thing is that input1.txt is ALSO copied over the bin folder (and all the package hierarchies are maintained).
An important thing to note is to use getPath() rather than toString(), because the latter will add some extra text to the front of the path (I only knew that because I printed it out) and thus you get a NULL pointer exception because the fileName was not formatted correctly.
Another important thing to note is that I used Read.class.getResource("input1.txt").getPath(); instead of this.getClass().getResource("input1.txt").getPath(); because the code was called in a static context (in my main method). If you create an object, then feel free to use the latter.
If you're interested in more advanced features, you can check out the link below:
What is the difference between Class.getResource() and ClassLoader.getResource()?
I hope this helps!
Edit:
You could use the following to get the directory where Read.class resides in also.
String fileName = Read.class.getResource(".").getPath();
Specifying getResource("..") would go to the parent directory.
String fileName = Read.class.getResource("..").getPath();
The above may be useful if you want to have more control specifying the path (e.g. if you want to create output.txt inside the directory where Read.class resides, use
String fileName = Read.class.getResource(".").getPath() + "output.txt";
If you knew the file was going to be located in the same folder in each system this program was run on, you could use system variables to ensure any path defined would still work with different users. For windows, I've used:
String user = new com.sun.security.auth.module.NTSystem().getName();
to get a user name. This could then be substituted in your example to be:
String fileName = "C:" + File.separator
+ "Users" + File.separator
+ user + File.separator
+ "Desktop" + File.separator
+ "input1.txt";
I'm not sure how this would work outside of Windows however.

Categories

Resources