Permissions and File.renameTo in Java 6 strange behavior - java

I have a Java program (running under Java 6), that monitors a directory parses the name of found files and runs actions (including copying the file) according to meta data and file content then, depending on the success or failure of the process, moves the files to a OK or KO directory.
I run my program as a simple user.
I tried, for the test, to put files belonging to root in my monitored directory.
Furthermore, I gave them 000 permissions.
The program would find the files but fail on the copy of the file.
For the record, the actual copy is done on this model:
FileOutputStream fos = new FileOutputstrem(DestFile)
FileInputStream stream = new FileInputStream(File);
byte buffer[] = new byte[bufferSize];
int nbRead;
while (-1 != (nbRead = fin.read(buffer)))
fos.write(buffer, 0, nbRead);
So far, seeing the program fail is exactly what I expected, 000 permissions on a un-owned file, that cannot be read.
But what is strange is that my files were moved to the KO box.
The move is done with
File failedFileName = new File(KOdirectory, myFile.getName());
myFile.renameTo(failedFileName);
Should that work? (given they are onwed by root and with 000 permissions)?
They end up in the KO directory, still owned by root with 000 permissions.
When I add read permissions (so my files are 444 root-owned) and reinject them into the monitored folder, the whole process runs smoothly and files end up in the OK directory (still root-owned and 444 permissions).
How is it possible to move files on which one has only reading rights?
How does this reading, moving, deleting works depending on the OS? on the distro?
Maybe I should add I run this on Ubuntu whose awkward root user (it exists, but not completely) concept might be messing with this.

Moving and renaming files does nothing to the file contents; instead, it changes the directory entries. So you need write permission on the directory, not the file itself.
Try it: if you remove the write permission to the directory, and give write permission to the file, you won't be able to rename or move the file anymore.
There are commands like mv or rm that actually check the file permission, and ask for confirmation if you want to move or change them. But that's extra code in the command and does not come from the operating system itself.
This is the same on all linux/unix systems. Reading/changing a file's content checks the permissions on the file; changing the file name or moving it to a different directory checks the permissions on the directory(/ies). This does not depend on the distro, it's the same on all linux systems, as well as Solaris, AIX, HP/UX and what other commercial unixes there are.

Moving a file from one directory to another only requires modification of directory entries for the directories in question. This means that you need only write and search permissions to the directories. The permissions or the owner of the file being moved do not matter.
You can read more about this in the appropriate man pages, such as the page for rename(2) and path_resolution(7).

A file has permission and this determines if you can read, modify or execute this file.
A file exists in one or more directories and it is the permission of the directory, not the file, which determines if the directory can be listed, modified or used.
So when you move a file, you are changing the directory, not the file.

Related

Windows 10 - ObjectOutputStream can't find relative paths because current working directory is System32

When I call method
System.out.print(new File("").getAbsolutePath())
from main I get the project workspace
C:\Users\darkr\Desktop\NuovoWorkSpace\ProjectName.
When it gets called by our save() method, which serializes what we need, suddenly the absolute path given from
new File("").getAbsolutePath()
becomes System32 (for me) and Desktop directory for my colleagues.
We're using gitHub to share our changes but this makes it almost impossible.
The code you have new File("").getAbsolutePath() is commonly used to determine the current directory from where you launched your application's main(String[]) method. So it looks like you are running from C:\Windows\System32 not on desktop folder.
The easiest way to fix your issue is to edit your application shortcut (see .lnk file and set "Start in" folder), or cd to be in an appropriate writable directory before running your application, or change your application to use file chooser to pick the target location for saves.
Alternatively pick sensible output paths for writing to instead of "", some good candidates are:
// Local user profile
File folder = new File(System.getenv("LOCALAPPDATA"), "myfolder");
// Roaming user profile
File folder = new File(System.getenv("APPDATA"), "myfolder");
// Temp folder:
File folder = new File(System.getProperty("java.io.tmpdir"), "myfolder")
Some sites suggest one of the following lines to locate Desktop, but this is unreliable because it will not work if the folder has been moved or run on some non-English installations:
File maybeDesktop = new File(System.getProperty("user.home"), "Desktop");
Path maybeDesktop = Path.of(System.getProperty("user.home"), "Desktop");
If you want to read the exact location of user Desktop from Java, you need to use JNI/JNA/Panama call to Windows API functions SHGetFolderPath or SHGetKnownFolderPath.

Cannot write file to Documents folder

I'm trying to write to a file in Java, or create a new file if the file doesn't exist. (Using JDK 14). However, when I run the following code I get an IOException at the if statement condition that reads The system could not find the file specified if the file doesn't exist, and Access is denied if the file does.
File file = new File(filePath);
System.out.println(filePath); // C:\Users\username\Documents\test.txt
if (file.createNewFile()) {
System.out.println("File successfully created");
} else {
System.out.println("File already exists");
}
The code works when I attempt to save it to the desktop folder and saves the file successfully, but for whatever reason isn't allowed to touch Documents.
The user I'm running IntelliJ as has full access to all files on the computer, and running the IDE as administrator did not fix the problem. However, I can save to the user folder and the desktop. It is only Documents or child directories of it that I can't save to.
There are a few similar questions on the site such as this one, however the cause is not the same as in my case this is a permissions issue, and not an issue of a missing directory.
I've just hit this same issue. It seems that JFileChooser() on some Windows 10 installations doesn't tell the os that the user has selected a folder and as such Sandboxing, Malware Control, Access control blocks access to create a file even though the user had full access (permission checks are OK but file write fails with IOException 13 or Access Denied). However FileDialog() DOES work where JFileChooser fails...
Heres what I would do to try to debug this:
Should you be trying to save to 'My Documents' as opposed to 'Documents'?
Try to save the file to C:\Users\username\test.txt (I suspect that will work)
Try to save the file to C:\Users\username\My Documents\test.txt
If you really do want to save it to 'Documents' make sure the 'Documents' director exists.
If thats the case, open the properties on Documents under the security tab select Everyone under 'Group our user names' and 'Full control' under permissions. that will open it wide up and should allow file creation. you might want to take note of what the settings where so you can put them back as setting a directory to wide open permissions can be 'problematic'. try running the program again.
1
if you want write data to file just user any Writer For example:
FileWriter writer = new FileWriter(yourFile);
You can use stream filtering for faster action.
Show more your code. You've just showed condition for existing file.
2
if you want create file in Documents folder, get a path, then make a:
File file = new File(documentPath);
while(!file.exists())
file.createNewFile();
//condition for file existing...`
If I don't help, comment below, just I can't understand your question :). Good Luck

Passing a .JAR program (ran from terminal) a text file as input

I have created a java program that other testers will use to help with their testing. I will be sending them a zip file with the .jar, a readme.txt, and main.properties.txt file.
The main.properties.txt file is a template for the testers to input their DB access credentials. They will update the main.properties file with their db cred's and then attempt to run the .jar from the terminal or command line. The issue I am running into is this. My program needs this updated main.properties.txt file so it can create the connections to our DB's.
What instructions do I need to give in my readme so my program can successfully find the main.properties.txt? Does the main.properties need to be in the same directory as the .jar? Can the testers just create a file on their desktop or documents folders to put the .jar and main.props?
The other question I have is how do I pass this file to my program once its ran from the terminal? Currently it is really easy, because the main.props is part of my program and I can just do something like
Properties prop = new Properties();
FileInputStream in = new FileInputStream("src/main/resources/main.properties");
prop.load(in);
in.close();
But now main.properties is not part of the project anymore. I don't know how to change the code above so that it can find the text from a directory on the local. The location in which they wish to put their main.properties is out of my control so writing a static path will not work. Please help!
There are many ways, I'll show you two.
You need a File object that points to the main.properties file. Then you create a stream on this object new FileInputStream(File) , as you already did by using a String.
The problem of course is to get a relative path to main.properties.txt which works on all systems, regardless where the jar-File is located.
1. Desktop
In this case the main.properties.txt is located at the users desktop. Here is how you access it:
File desktop = new File(System.getProperty("user.home"), "Desktop");
File target = new File(desktop, "main.properties.txt");
Alernativly, if you plan to distribute configuration and property files that do not require user interaction, you may want to use locations like Temp or Documents (Windows).
2. Relative to the jar
Probably one of your best options. Assume the target is in the same folder than the jar-File (or at least in a fix structure relative to the jar). Here is how you access it (related question: how-to-get-the-path-of-a-running-jar-file):
CodeSource codeSource = YourMainClass.class.getProtectionDomain().getCodeSource();
File jarFile = new File(codeSource.getLocation().toURI().getPath());
File jarDir = jarFile.getParentFile();
File target = new File(jarDir, "main.properties.txt");

How to detect whether a zip/compressed file is completely unziped/uncompressed?

I have a java program to copy a folder(along with all files in it) from one location to another programatically.Now assume user pasted a zip file in this folder and then unzips it.Meanwhile my program starts,then it copies only the files which got unzipped in the folder.I want to wait till this unzipping of files is finished.
Hence I am looking for a programmatical way using which I can detect that the zip file has been completely uncompressed and then only resume with the normal copying of files.Is there any way to do this?
See if you can rename the file that's beeing unpacked. If it's not "renamable" then the file is probably locked.
There is no reliable way to do this because you have no control over the unzipper; for example, the user could decide to unzip only some of the files. Since the unzipper won't tell you what the user selected in the UI, there is no reliable way to know when "all" files have been unpacked.
Workarounds:
Users must unzip files in a different folder and then move the files into the folder that you watch. Move operations on the same disk are atomic, so this will make sure you get only complete files.
Accept ZIP archives as input and unpack them yourself. That way, you have full control over the unpack process and can make sure you only process complete files. Also, since the ZIP "table of contents" is at the end of the ZIP archive, this will also make sure that you only process complete ZIP archives.

Java: Where to write config without requiring administrative rights

I actually can't believe I'm saying this but since porting my programs to OSX and getting used to permissions, I've realized that what I planned to do on Windows will not work how I want it to. Currently, on windows, my program stores it's setting's in the registry (HKLM) and some user editable resources in a folder next to the program file. For various reasons, I have now decided that the configuration/settings will be stored in a file and the user will be able to in which folder the other resources are kept.
So the question I have now is where to store the configuration file. Obviously it will be updated, but I don't want to program to have to require administrator permissions to run. I would like to offer an option so that all users can use the program (like most programs do), which will of course require Admin, so this leads be onto the second query: where should I store the configuration file (and the folder in which other resources are kept) and how can I detect whether the program has been installed for all users or just one!
Thanks in advance
PS If you didn't guess, the program is written in Java so I would like to know how to programatically get the location you suggest as well please.
Its normal practice in *nix compatible programs to store information in folders starting with name . in the home directory of the users like,
.bash_history
.bashrc
You could use the same on OSX in my opinion and create a directory say,
.myapp
You can store any number of files with any format under that directory.
To get the location of the folder, you can do
String homeDir = System.getProperty("user.home");
File myAppDir = new File(homeDir, ".myapp");
That is roughly the code that can get you your custom config directory for your app.
Please not that dot files / folders are somewhat similar to hidden folders in windows. Your File Manager will not generally show these files / folders by default.
To identify if the program is installed for all the users or not, you could create the configuration at some administrator (root) controlled location like /etc (not sure about Mac) The user configuration can always override the default config. There could be a better way to handle this though.
On both windows and unix, User(usually) has a (home)folder to which it has full permissions. You may create a directory in the home folder and have your user configuration files reside there.

Categories