ResourceFinder ( rn-find )
|Righteo. Here’s to 2015 and my ability to write things on an infrequent basis.
*rummages through old code*
Here’s some possibly buggy code that someone else might find useful. It’s called ResourceFinder (a.k.a. rn-find
) and it finds resources [1].
Preamble
It’s a bit like the unix ‘find
‘ command, except that it will also descend within archive files (currently, just .zip
and .zip
-like archives; e.g. .jar
, .war
, .ear
, .har
(not those hars, these hars) and .rar
(not those rars, these rars).
This is handy since Java uses the zip format for packaging most things, and third-party indexers, if they support searching zip files, are usually out-of-date as soon as you recompile or redeploy things, which is fairly often.
It’s in the randomnoun common-public JAR as of version 0.2.2, which you can download from this page or the over here and copy into c:\util\java or /usr/local/java depending on your OS, together with log4j-good-bits.
I usually run it from a command-line using a .cmd or .sh wrapper, which sets up the classpath and invokes the CLI class.
If you’re on Windows, pop this in, say, c:\util\bin
, and then add that to your PATH:
Or if you use linux, put this in /usr/local/bin
instead (and chmod +x
it):
If you run it without any command-line parameters, you get a short usage description:
C:\Users\knoxg> c:\util\bin\rn-find Usage: java com.randomnoun.common.ResourceFinder [options] searchTerm or java com.randomnoun.common.ResourceFinder [options] -a where [options] are: -h -? displays this helptext -f follow symlinks -a show all resources found (i.e. do not use searchTerm) Search criteria: -i case-insensitive match -sc if present, searchTerm matches within filename (default) -ss if present, searchTerm matches start of filename -se if present, searchTerm matches exact filename -sr if present, searchTerm matches filename as a regular expression -mf n max filesystem folder depth (0 = do not descend into subfolders) -ma n max archive depth (0 = do not descend into archives) -x if present, will attempt to recover if errors occur reading archives (errors sent to stderr) Action when resource found: -v verbose; display filenames with file sizes and timestamps -vv display MD5/SHA1 hashes of resources (NB: modifies display order) -d n dump/display the contents of the n'th resource found -d all dump the name and contents of all resources found -d names dump just the names of all resources found (default) -d n1,n2... dump the name and contents of the n1'th, n2'nd etc... resources found -dm n|all as per -d, but performs manifest unmangling on resource (fixes linewraps) -dj n|all as per -d, but performs class decompiling (requires jad to be in PATH) -c text search for text in contents of resource (uses UTF-8 encoding) -ci text case-insensitive search for text in contents of resources * A maximum of one -d switch should be present * The -d and -c switches are mutually exclusive Exception in thread "main" java.lang.IllegalArgumentException: Expected resource search term or options at com.randomnoun.common.ResourceFinder.main(ResourceFinder.java:1102)
A few use-cases are probably in order then:
Default search
With just a searchTerm argument, this will search all files in the current working directory and any subdirectories for files that contain the searchTerm (in the example below, the word ‘mushroom’ in lower case).
Each file will displayed one per line, with a 0-based index shown at the start of the line; e.g.
c:\some\path> rn-find mushroom [0] mushroom.bat [1] java/mushroom.jar [2] java/mushroom.jar#recipes.jar#mushroom.txt [3] java/mushroom.jar#recipes.jar#mushroom.png
You’ll notice that files contained within archives have a ‘#
‘ character between the archive name and the contained filename; also that archives can be contained in archives (to any depth).
Case-insensitive search
if you want case-insensitivity, add the -i flag:
knoxg@bnedev03:/ooh/now/im/on/linux$ rn-find -i mushroom [0] mushroom.bat [1] java/mushroom.jar [2] java/mushroom.jar#com/example/contrived/recipes/OmeletteWithMushroom.class [3] java/mushroom.jar#recipes.jar#mushroom.txt [4] java/mushroom.jar#recipes.jar#mushroom.png
Display resource contents
If you want to see what’s in the mushroom.txt file above (contained two archives deep), use the -d
flag:
$ # display the contents of the file next to the [3] marker $ rn-find -d 3 -i mushroom This is what's in the mushroom.txt file. Mushrooms are small, round, and can be used in many popular dishes. In ASCII form, they look like this: _______ /_ _\ (___)
You’ll notice the index and filename are suppressed when the -d
flag is used, which will prevent corruption of binary files if piped to a file:
$ # extract the PNG file into the /tmp directory $ rn-find -d 4 -i mushroom > /tmp/mushroom.png
Display decompiled java source
Back in the day, if you wanted to decompile a .class
file into something .java
-ish, you could use the -dj
flag instead of -d
:
$ # decompile the OmeletteWithMushroom.class file $ rn-find -dj 2 -i mushroom # jad output would appear here
This used to work providing jad
was located on your PATH, but since jad
hasn’t tracked any recent changes to the java bytecode specification (it’s broken from about 1.5 on, from memory); and the more recent JD decompiler (and CLI wrapper ) doesn’t seem to work at all, you can probably forget about decompiling until that’s fixed.
Search resource contents
If you want to search within the content of the files, use the -c
flag (or for a case-insensitive content search use the -ci
flag); e.g. to search for the word ‘round‘ inside files having filenames that contain the word ‘mushroom‘, then:
$ rn-find -ci round -i mushroom [3] [line 3, col 21] java/mushroom.jar#recipes.jar#mushroom.txt
Display resource metadata
If you want to list the files with their filesizes and last modified timestamps, use the use the -v
flag, and to add SHA1/MD5 hashes, use the -vv
flag:
$ rn-find -vv -i mushroom [0] mushroom.bat 28391 1/12/2014 03:15:22 4c02e2a5578ae4fb67b4aa77ec7532f9 dcfd5d26ca449e547b1fe96716627f8069fa6b16 [1] java/mushroom.jar 1/12/2014 03:18:15 9ab5bcbcf8a02054d75ad5213417d82a 1504e60a50523b9ecfc820a258e1a9294fa32129 [2] java/mushroom.jar#com/example/contrived/recipes/OmeletteWithMushroom.class 1/12/2014 03:15:22 bff90b08ced5a9640cd6be8b6a6255ba 23ac63d8a57946a17be06b5e79c96269c8ae96bc [3] java/mushroom.jar#recipes.jar#mushroom.txt 1/12/2014 03:24:26 bbbf9b5f668cc6b2f33126633be3e8f9 237c2245439b8b5b27bb13aa6a9e9b8471dc4347 [4] java/mushroom.jar#recipes.jar#mushroom.png 1/12/2014 03:28:11 fb338b621aa80636f3f78b9a2538853d 35d6fe8c4ff25053ce6b03526d49690f2eb3a649
Regular expression search
You can modify the searchTerm (‘mushroom’) to be a regular expression by adding the ‘sr’ flag:
$ rn-find -sr -i mushro+m # one or more oh's in mushrooooom [0] mushroom.bat [1] embedded/mushrom.rom [2] java/mushroom.jar [3] java/mushroom.jar#com/example/contrived/recipes/OmeletteWithMushroom.class [4] java/mushroom.jar#recipes.jar#mushroom.txt
Show all files
And you can display the name of all files by using the -a flag and omitting the searchTerm
$ rn-find -a [0] COPYRIGHT [1] LICENCE [2] mario.exe [3] mushroom.bat [4] embedded/mushrom.rom [5] java/mushroom.jar [6] java/mushroom.jar#com/example/contrived/recipes/OmeletteWithMushroom.class [7] java/mushroom.jar#recipes.jar#mushroom.txt
Postamble
So anyway, that’s the guts of it. There’s a few other switches for other search types, dealing with errors, manifest unmangling, but 90% of the time you’ll probably be searching for file names or content within the file.
If you like, why not run it over your entire filesystem every morning at 3am or so, pipe that to a file, and then use grep
to find things slightly faster. Like locate
does.
If you include the MD5/SHA1 hashes as well you could write a script to detect people changing files on your filesystem, which you could then build a $710 million company around.
Update 12/1/2015 bumped common-public version to 0.2.2 (removed logging, fixed content search)