Is there a way to search an entire computer for a String value representing a file name in Java? This would be without knowing the names of the drives on the computer.
You can iterate through the file system by looking at file names, getting the contents if it's a directory, etc. recursively.
If the sticking point is how to get the drives on the computer, look at the File.listRoots() function to get a list of the drive letters.
ETA:
To be absolutely safe, you'll want to include some limits on recursive processing. It's possible to have loops in the file system with symbolic links and such (especially in LINUX/UNIX, but third party tools can enable this in Windows as well).
To make sure you don't get into a loop when dealing with symbolic links, use the File.getCanonicalPath methods to get the "real" path for the directory and keep track of all visited canonical paths. You could also use getCanonicalFile and keep track of all the files, but that's probably not needed unless you really want to avoid the occasional instance where you'll process the same file twice.
You can use the File object to determine whether you are looking at a file or a directory:
File file = new File("/"); //root
Then as you are recursing (or iterating depending on your preference) you have a simple check:
if(tempFile.isDirectory())
//do recursive call on that directory
else
//perform check on file name
Also not forget exceptions in recursive processing. Some folders may not be accessible due to access right restrictions. Also, the Windows system folder "System Volume Information" cannot be entered in Windows Explorer, so I suppose it will throw an exception if you try to get inside programmaticaly.
You can use a recursive call through the entire file system: You can use the following methods of java.io.File:
listRoots(): list the root files (In Windows it's the drives, on Mac OS X and linux it's '/').
listFiles(): list the enclosing files of a directory
Related
Linux Api has O_TMPFILE flag to be specified with open system call creating unnamed temporary file which cannot be opened by any path. So we can use this to write data to the file "atmoically" and the linkat the given file to the real path. According to the open man page it can be implemented as simple as
char path[1000];
int fd = open("/tmp", O_TMPFILE | O_WRONLY, S_IWUSR);
write(fd, "123456", sizeof("123456"));
sprintf(path, "/proc/self/fd/%d", fd);
linkat(AT_FDCWD, path, AT_FDCWD, "/tmp/1111111", AT_SYMLINK_FOLLOW);
Is there a Java alternative (probably non crossplatform) to do atomic write to a file without writing Linux-specific JNI function? Files.createTempFile does completely different thing.
By atomic write I mean that either it cannot be opened and be read from or it contains all the data required to be writted.
I don't believe Java has an API for this, and it seems to depend on both the OS and filesystem having support, so JNI might be the only way, and even then only on Linux.
I did a quick search for what Cygwin does, seems to be a bit of a hack just to make software work, creating a file with a random name then excluding it only from their own directory listing.
I believe the closest you can get in plain Java is to create a file in some other location (kinda like a /proc/self/fd/... equivalent), and then when you are done writing it, either move it or symbolic link it from the final location. To move the file, you want it on the same filesystem partition so the file contents don't actually need to be copied. Programs watching for the file in say /tmp/ wouldn't see it until the move or sym link creation.
You could possibly play around with user accounts and filesystem permissions to ensure that no other (non SYSTEM/root) program can see the file initially even if they tried to look wherever you hid it.
I am sure this is a relatively simple question, and I actually think it may be more of a problem with Windows than with Java.
I have a method for copying a file to a new directory, which takes two File objects, a File created with the path of the original, and a File created with the desired path of the copy. I am sure that the method works because I have used it to successfully copy a file onto my Desktop.
However, using my actual desired path creates an error:
java.io.FileNotFoundException: PATH (The system cannot find the path
specified)
Where the PATH is the path that I am attempting to use.
Here is my guess:
I am making this program for use on another machine. As such, the path that I am trying to use is:
C:\Users\XXXXXX\rest_of_path\filename.file
where XXXXXX is the primary user on the machine which I am writing the program for.
This directory exists on my system, but XXXXXX is not a user on my system. So I am guessing that Windows is causing a problem because of that.
I'm now changing my code to use a solution which depends on the machine, and is not hardcoded (System.getProperty).
However, I'd really like to know why this problem is occurring, from an academic standpoint, as a Windows and Java user.
Thanks in advance.
EDIT: accidentally used forward slashes when I meant double backslashes. To ensure that it was not a spelling error, I simply copied the directory using windows, and pasted it into my program (then doubled up on the backslashes).
EDIT: several users have suggested something which is far more clean than what I am trying to do in the first place. I'm leaving this question open because I'm curious why it is not working.
EDIT: I used the solution above and I'm completely happy with it. I still don't know why Windows will not allow me to access the original path, but I guess I really don't care at this point. Thanks, everybody!
In java, and generally most programming languages, you don't always have to provide the exact directory of your file. Although it would be nice to see the code you're using to get the file, I'll provide how it can be done.
I'm assuming you aren't using new File("file.txt") because that retrieves files from the folder your program is in, and doesn't require an entire address like C:\...\...\.... You certainly don't want to use an entire address because different operating systems use different paths, obviously.
The best you can do is put your files and requested folders somewhere relative to your program is (whether it's class files or a .jar file).
But with Windows you can be sure that with System.getProperty("...") you can retrieve directory URLs as relative paths for your files/folders.
Documentation on System.getProperty here: http://docs.oracle.com/javase/tutorial/essential/environment/sysprop.html
I may not have helped or answered your question at all. But hopefully you'll find a solution.
Is there any way in Java to write out to a temporary file securely?
As far as I can tell, the only way to create a temporary file (createTempFile) does't actually open it at the same time, so there's a race condition between file open & file write. Am I missing something? I couldn't find the C source code behind createFileExclusively(String) in UnixFileSystem.java, but I doubt it can really do anything since the file open occurs in the Java code after the temp file is created (unless it tries to do something with file locks?).
The problem
Between when the temporary file is created & you open it, a malicious attacker could unlink that temporary file & put malicious stuff there. For example, an attacker could create a named pipe to read sensitive data. Or similarly if you eventually copy the file by reading it, then the named pipe could just ignore everything written & supply malicious content to be read.
I remember reading of numerous examples of temporary file attacks in the past 10+ years that exploit the race condition between when the name appears in the namespace and when the file is actually opened.
Hopefully a mitigating factor is that Java set's the umask correctly so a less-privileged user can't read/write to the file and typically the /tmp directory restricts permissions properly so that you can't perform an unlink attack.
Of course if you pass a custom directory for the temporary file that's owned by a less-privileged user who's compromised, the user could do an unlink attack against you. Hell, with inotify, it's probably even easier to exploit the race condition than just a brute force loop that does a directory listing.
http://kurt.seifried.org/2012/03/14/creating-temporary-files-securely/
Java
use java.io.File.createTempFile() – some interesting info at http://www.veracode.com/blog/2009/01/how-boring-flaws-become-interesting/
for directories there is a helpful posting at How to create a temporary directory/folder in Java?
Java 7
for files use java.io.File.createTempFile()
for directories use createTempDirectory()
http://docs.oracle.com/javase/7/docs/api/java/nio/file/Files.html
Since Java 7 we have OpenOption.
An object that configures how to open or create a file.
Objects of this type are used by methods such as newOutputStream, newByteChannel, FileChannel.open, and AsynchronousFileChannel.open when opening or creating a file.
Of particular interest is StandardOpenOptions.CREATE_NEW.
Create a new file, failing if the file already exists. The check for the existence of the file and the creation of the file if it does not exist is atomic with respect to other file system operations.
So, you can do something like this:
FileChannel mkstemp() {
Path path = Files.createTempFile(null, null);
Files.delete(path);
return FileChannel.open(path, WRITE, CREATE_NEW);
}
Implementing the same template behaviour is left as exercise to the reader.
Keep in mind that on many systems, just because a file doesn't have a name doesn't at all mean it's inaccessible. For example, on Linux open file descriptors are available in /proc/<pid>/fd/<fdno>. So you should make sure that your use of temporary files is secure even if someone knows / has a reference to the open file.
You might get a more useful answer if you specify exactly what classes of attacks you are trying to prevent.
Secure against other ordinary userid's? Yes, on any properly functioning multi-user system.
Secure against the your own userid or the superuser? No.
I need to move a file from one directory to another in the android filesystem. How can I programmatically check if the two paths is on the same mountpoint?
The reason I want to know this is because if they are, we need to copy the bits instead of using File.rename(newPath).
Examples when the paths is on different mountpoints:
The user wants to move a file from the internal to external storage.
The user wants to move a file from /sdcard/files to /sdcard/external_sd/files on a samsungdevice.
Call File.rename. If it succeeds, they're on the same mountpoint.
One way to determine which filesystem a file resides on from within an Android app:
get the file's canonical path by calling File.getCanonicalPath() on it.
then get the list of currently mounted filesystems & their mount point paths from /proc/mounts
and find which mount point path is the most complete string match for the canonical path of the file in question, this should give you the mount point / filesystem of the file.
Compare results from the two files.
I wish to place a file named as myFile.file in
C:/Windows/System32/ location.
Here is use java code to place my file. while I execute my program it throws "Access Denied:C:/Windows/System32/myFile.file".
why is it happening? Is it possible to place in that location?
That (and many other) system locations are restricted for admin users/elevated applications.
Application data should be stored in the user application data files in the user profile (or the common application data).
If you really must write into the system folder, then you will need to ask the user for permission via UAC, either by using ShellExecute() with the runas verb to run another program, or COM elevation (if that's possible in Java)
Update
See Andrew's answer for a method to get the correct path in Java.
Put myFile.file in a sub-directory of user.home.
The sub-directory could be the package name of the class saving the file. E.G. if your main class is our.com.Main, store the file at ${user.home}/our/com/myFile.file. The reason to use a sub-directory is to help prevent another apps. myFile.file from overwriting or interfering with your own version.
To get the location of user.home, see:
System.getProperty("user.home");
The value of user.home here, is:
Name Value
user.home C:\Users\Andrew
This technique will work reliably for Mac. & *nix, as well as Windows.