Created
February 5, 2010 02:06
-
-
Save atr000/295410 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// hfsfind - find files and folders on HFS+ mounted volumes on Mac OS X | |
// | |
// findfile.m | |
// | |
// Created by John Chang on 2007-06-18. | |
// This code is Creative Commons Public Domain. You may use it for any purpose whatsoever. | |
// http://creativecommons.org/licenses/publicdomain/ | |
// | |
// For the original source code by John Chang please see: | |
// Searching for files by name, http://cocoacafe.wordpress.com/2007/06/17/fscatalogsearch/ | |
// | |
// Additions to the abovementioned original source code were made by jv (2009-05-12). | |
// License of additions made by jv: | |
// Creative Commons Public Domain (http://creativecommons.org/licenses/publicdomain/) | |
// | |
// Use hfsfind at your own risk! | |
// | |
// Compile command: | |
// | |
// # requires Xcode, http://developer.apple.com/technology/xcode.html | |
// gcc -g -Wall -O3 -x objective-c -fobjc-exceptions -framework Foundation -framework CoreServices -o hfsfind findfile.m | |
// | |
// | |
// For the Unix time and year 2038 problem please see: | |
// | |
// - http://en.wikipedia.org/wiki/Unix_time | |
// - http://en.wikipedia.org/wiki/Year_2038_problem | |
// - http://en.wikipedia.org/wiki/Time_t | |
// - http://members.dslextreme.com/users/rogermw/Y2038.html | |
// - http://www.deepsky.com/~merovech/2038.html | |
// - http://cr.yp.to/libtai.html | |
// - egrep -Irs 'typedef.*time_t' /usr/include | |
// -> typedef __darwin_time_t time_t; | |
// -> typedef long __darwin_time_t; /* time() */ | |
// | |
// | |
// See also: | |
// | |
// - man 1 find | |
// - man 3 fts (cf. http://keramida.wordpress.com/2009/07/05/fts3-or-avoiding-to-reinvent-the-wheel/ ) | |
// - http://www.gnu.org/software/findutils/ | |
// - http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.bin/find/ | |
// - DirectoryScanner, http://code.google.com/p/polkit/ (for Mac OS X 10.5 or later) | |
// - mac-robber (basic UNIX-based directory scanner to get modify-access-change data of files & directories), | |
// http://www.sleuthkit.org/mac-robber/desc.php and http://codesnippets.joyent.com/posts/show/1808 | |
// - File Manager Reference: FSCatalogSearch, | |
// http://developer.apple.com/documentation/Carbon/Reference/File_Manager/Reference/reference.html#//apple_ref/c/func/FSCatalogSearch | |
// - Iterating Directory Contents: Iterating Directories in Carbon (FSGetCatalogInfoBulk), | |
// http://developer.apple.com/documentation/Performance/Conceptual/FileSystem/Articles/IteratingFiles.html | |
// | |
#import <Foundation/Foundation.h> | |
#include <unistd.h> // getopt | |
// added | |
#import <CoreServices/CoreServices.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <time.h> | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
static void usage() | |
{ | |
fprintf(stderr, "\nusage:\n\nhfsfind -07adfhnv [-m <minus secs>] [-p <plus secs>] [-r </Volumes/volume>] [-s <minus secs>] [-t <date in epoch secs>] <substring>\n\n"); | |
fprintf(stderr, \ | |
"Note: hfsfind defaults to searching for files with substring \"\" in (HFS+ mounted) volume / !\n\ | |
Using \"\" for <substring> will lead to a search for all files!\n\ | |
<substring> is case-insensitive and always refers to the file name, not the entire file path!\n\n\ | |
-0: terminate file paths written to stdout with the null character (aka -print0)\n\ | |
-7: print the file path and the modification date in epoch secs to stdout in the form: \n\ | |
filepath\\777epochsecs\\000 (requires: -0)\n\ | |
-a: search for all file system items, i. e. both files and directories\n\ | |
-d: search for directories only\n\ | |
-f: search for files only\n\ | |
-h: show this help message\n\ | |
-n: search for file or folder names only (i.e. do NOT get & process the modification dates of files or folders)\n\ | |
-v: verbose\n\n\ | |
-m <minus seconds> (will be subtracted from <date in epoch secs>)\n\ | |
-p <plus seconds> (will be added to <date in epoch secs>)\n\ | |
-s <seconds> (same as -m)\n\ | |
-t <date in epoch secs> (specify the modification date of files or folder to be searched for\n\ | |
in UNIX time, i. e. number of seconds elapsed since 1970-01-01 00:00:00 UTC)\n\n"); | |
fprintf(stderr, \ | |
"Examples:\n\n\ | |
hfsfind -h # show help message\n\ | |
hfsfind -v # list all files on volume /\n\ | |
hfsfind -av .menu # list all files & folders with substring \".menu\" on volume /\n\ | |
hfsfind -anv .menu # same (no processing of modification dates)\n\ | |
hfsfind -v -s $[5*60] # find files modified within the last 5 minutes\n\ | |
hfsfind -av -s $[5*3600] # find files & folders modified within the last 5 hours\n\ | |
hfsfind -av -s $[5*86400] # find files & folders modified within the last 5 days\n\n\ | |
hfsfind -v -m $[22*86400] -p $[14*86400] -t $(gnudate -d \"2001-08-30 10:37:51\" +%%s) -r / '.txt'\n\n\ | |
while read -d $'\\0' filemod; do\n\ | |
declare IFS=$'\\777'\n\ | |
array=( ${filemod} )\n\ | |
declare IFS=$' \\t\\n'\n\ | |
printf \"%%s\\n\" \"${array[0]}\" # file path\n\ | |
printf \"%%s\\n\" \"${array[1]}\" # modification date\n\ | |
done < <(hfsfind -07 -f .txt 2>/dev/null) # Bash\n\ | |
\n"); | |
} | |
int isULInt(const char *input, unsigned long int *i) | |
{ | |
char *eos = 0; | |
long l; | |
l=strtoul(input,&eos,0); | |
if(*eos != 0) | |
{ | |
fprintf(stderr, "No valid unsigned long integer: %s\n", input); | |
return 1; | |
} | |
if ( strlen(input) > 10 ) | |
{ | |
fprintf(stderr, "Input number too big: %s\n", input); | |
return 1; | |
} | |
*i=(unsigned long int)l; | |
return 0; | |
} | |
void find_all(int print0, NSString * query, NSString * volumeRoot, int verbose) | |
{ | |
if ( verbose == 1 ) | |
{ | |
printf("\nSearch date: %s\n", [[[NSDate date] description] UTF8String]); | |
printf("\nSearch for files & folders in HFS+ volume: %s\n", [volumeRoot UTF8String]); | |
printf("\nSearch for names of files & folders containing substring: %s\n", [query UTF8String]); | |
printf("\nModification date is irrelevant!\n\n"); | |
} | |
OSErr err; | |
FSRef container; | |
err = FSPathMakeRef((const UInt8 *)[volumeRoot UTF8String], &container, NULL); | |
if (err == fnfErr) | |
{ | |
fprintf(stderr, "findfile: No such volume '%s'\n", [volumeRoot UTF8String]); | |
return; | |
} | |
assert(err == noErr); | |
FSIterator iterator; | |
err = FSOpenIterator(&container, kFSIterateSubtree, &iterator); | |
assert(err == noErr); | |
FSSearchParams searchParams = {}; | |
searchParams.searchBits = fsSBPartialName; | |
searchParams.searchNameLength = [query length]; | |
searchParams.searchName = calloc([query length], sizeof(unichar)); | |
[query getCharacters:(unichar *)searchParams.searchName]; | |
// call FSCatalogSearch until the iterator is exhausted | |
if (print0 == 0) // print0 is set to 0 (false) | |
{ | |
ItemCount maximumObjects = 1; | |
while (err != errFSNoMoreItems) | |
{ | |
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; | |
ItemCount count; | |
FSRef refs[maximumObjects]; // the size of the buffer is doubled during each iteration | |
err = FSCatalogSearch(iterator, &searchParams, maximumObjects, &count, NULL, kFSCatInfoNone, NULL, refs, NULL, NULL); | |
assert(err == noErr || err == errFSNoMoreItems); | |
int i; | |
for (i=0; i<count; i++) | |
{ | |
FSRef ref = refs[i]; | |
CFURLRef url = CFURLCreateFromFSRef(kCFAllocatorDefault, &ref); | |
printf("%s\n", [[(id)url path] UTF8String]); | |
} // for | |
if (maximumObjects < 128) | |
maximumObjects *= 2; | |
[pool release]; | |
} // while | |
} else { // print0 is set to 1 (true) | |
ItemCount maximumObjects = 1; | |
while (err != errFSNoMoreItems) | |
{ | |
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; | |
ItemCount count; | |
FSRef refs[maximumObjects]; // the size of the buffer is doubled during each iteration | |
err = FSCatalogSearch(iterator, &searchParams, maximumObjects, &count, NULL, kFSCatInfoNone, NULL, refs, NULL, NULL); | |
assert(err == noErr || err == errFSNoMoreItems); | |
int i; | |
for (i=0; i<count; i++) | |
{ | |
FSRef ref = refs[i]; | |
CFURLRef url = CFURLCreateFromFSRef(kCFAllocatorDefault, &ref); | |
printf("%s", [[(id)url path] UTF8String]); // print: filepath | |
putchar(0); // print \000 to stdout | |
} // for | |
if (maximumObjects < 128) | |
maximumObjects *= 2; | |
[pool release]; | |
} // while | |
} // if print0 | |
free((void *)searchParams.searchName); | |
searchParams.searchName = 0; // avoid dangling pointer | |
FSCloseIterator(iterator); | |
return; | |
} // void find_all | |
void find_files(int print0, int search_dir, NSString * query, NSString * volumeRoot, int verbose) | |
{ | |
if ( verbose == 1 ) | |
{ | |
printf("\nSearch date: %s\n", [[[NSDate date] description] UTF8String]); | |
if (search_dir == 0) | |
{ | |
printf("\nSearch for files in HFS+ volume: %s\n", [volumeRoot UTF8String]); | |
printf("\nSearch for file names containing substring: %s\n", [query UTF8String]); | |
printf("\nModification date is irrelevant!\n\n"); | |
}else{ | |
printf("\nSearch for folders in HFS+ volume: %s\n", [volumeRoot UTF8String]); | |
printf("\nSearch for folder names containing substring: %s\n", [query UTF8String]); | |
printf("\nModification date is irrelevant!\n\n"); | |
} | |
} | |
OSErr err; | |
FSRef container; | |
err = FSPathMakeRef((const UInt8 *)[volumeRoot UTF8String], &container, NULL); | |
if (err == fnfErr) | |
{ | |
fprintf(stderr, "findfile: No such volume '%s'\n", [volumeRoot UTF8String]); | |
return; | |
} | |
assert(err == noErr); | |
FSIterator iterator; | |
err = FSOpenIterator(&container, kFSIterateSubtree, &iterator); | |
assert(err == noErr); | |
FSSearchParams searchParams = {}; | |
FSCatalogInfo searchInfo1; | |
FSCatalogInfo searchInfo2; | |
// timeout as used by a Time Manager task, or 0 for no timeout | |
searchParams.searchTime = 0; | |
// fields to look at in searchInfo1 and searchInfo2 structs | |
searchParams.searchBits = fsSBPartialName + fsSBFlAttrib; | |
searchParams.searchInfo1 = &searchInfo1; // the catalog info to match | |
searchParams.searchInfo2 = &searchInfo2; // the catalog info mask | |
searchParams.searchNameLength = [query length]; | |
searchParams.searchName = calloc([query length], sizeof(unichar)); | |
if (search_dir == 0) | |
searchInfo1.nodeFlags = 0; // only match files | |
else | |
searchInfo1.nodeFlags = kFSNodeIsDirectoryMask; // only match directories | |
searchInfo2.nodeFlags = kFSNodeIsDirectoryMask; // check only this nodeFlagbit | |
[query getCharacters:(unichar *)searchParams.searchName]; | |
// call FSCatalogSearch until the iterator is exhausted | |
if (print0 == 0) // print0 is set to 0 (false) | |
{ | |
ItemCount maximumObjects = 1; | |
while (err != errFSNoMoreItems) | |
{ | |
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; | |
ItemCount count; | |
FSRef refs[maximumObjects]; // the size of the buffer is doubled during each iteration | |
err = FSCatalogSearch(iterator, &searchParams, maximumObjects, &count, NULL, kFSCatInfoNodeFlags, NULL, refs, NULL, NULL); | |
assert(err == noErr || err == errFSNoMoreItems); | |
int i; | |
for (i=0; i<count; i++) | |
{ | |
FSRef ref = refs[i]; | |
CFURLRef url = CFURLCreateFromFSRef(kCFAllocatorDefault, &ref); | |
printf("%s\n", [[(id)url path] UTF8String]); | |
} // for | |
if (maximumObjects < 128) | |
maximumObjects *= 2; | |
[pool release]; | |
} // while | |
} else { // print0 is set to 1 (true) | |
ItemCount maximumObjects = 1; | |
while (err != errFSNoMoreItems) | |
{ | |
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; | |
ItemCount count; | |
FSRef refs[maximumObjects]; // the size of the buffer is doubled during each iteration | |
err = FSCatalogSearch(iterator, &searchParams, maximumObjects, &count, NULL, kFSCatInfoNodeFlags, NULL, refs, NULL, NULL); | |
assert(err == noErr || err == errFSNoMoreItems); | |
int i; | |
for (i=0; i<count; i++) | |
{ | |
FSRef ref = refs[i]; | |
CFURLRef url = CFURLCreateFromFSRef(kCFAllocatorDefault, &ref); | |
printf("%s", [[(id)url path] UTF8String]); // print: filepath | |
putchar(0); // print \000 to stdout | |
} // for | |
if (maximumObjects < 128) | |
maximumObjects *= 2; | |
[pool release]; | |
} // while | |
} // if print0 | |
free((void *)searchParams.searchName); | |
searchParams.searchName = 0; // avoid dangling pointer | |
FSCloseIterator(iterator); | |
return; | |
} // void find_files | |
void find_all_modified(int print0, int print7, unsigned long int current_time_in_seconds, unsigned long int time_of_date_in_seconds, \ | |
unsigned long int minus_in_seconds, unsigned long int plus_in_seconds, unsigned long int seconds, \ | |
NSString * query, NSString * volumeRoot, int verbose) | |
{ | |
NSTimeInterval epochsecs; | |
NSDate *date = nil; | |
NSString *dateStr = nil; | |
const char * upperlim = 0; | |
const char * lowerlim = 0; | |
const char * file = 0; | |
unsigned long int lower_limit_in_seconds; | |
unsigned long int upper_limit_in_seconds; | |
unsigned long int lstatsecs; | |
if ( time_of_date_in_seconds == 0 ) | |
time_of_date_in_seconds = current_time_in_seconds; | |
if ( (minus_in_seconds == 0) && (plus_in_seconds == 0) && (seconds > 0) ) | |
minus_in_seconds = seconds; | |
if ( minus_in_seconds >= time_of_date_in_seconds ) | |
minus_in_seconds = time_of_date_in_seconds; | |
if ( minus_in_seconds > 0 ) | |
lower_limit_in_seconds = time_of_date_in_seconds - minus_in_seconds; | |
else | |
lower_limit_in_seconds = 0; | |
if ( plus_in_seconds > 0 ) | |
upper_limit_in_seconds = time_of_date_in_seconds + plus_in_seconds; | |
else | |
upper_limit_in_seconds = current_time_in_seconds; | |
epochsecs = upper_limit_in_seconds; | |
date = [NSDate dateWithTimeIntervalSince1970: epochsecs]; | |
dateStr = [date description]; | |
upperlim = [dateStr UTF8String]; | |
epochsecs = lower_limit_in_seconds; | |
date = [NSDate dateWithTimeIntervalSince1970: epochsecs]; | |
dateStr = [date description]; | |
lowerlim = [dateStr UTF8String]; | |
if ( verbose == 1 ) | |
{ | |
printf("\nSearch date: %s\n", [[[NSDate date] description] UTF8String]); | |
printf("\nSearch for files & folders in HFS+ volume: %s\n", [volumeRoot UTF8String]); | |
printf("\nSearch for names of files & folders containing substring: %s\n", [query UTF8String]); | |
// print dates human readable | |
printf("\nFind files & folders with modification dates between: %s - %s\n", lowerlim, upperlim); | |
// print dates in UNIX time (i. e. number of seconds elapsed since 1970-01-01 00:00:00 GMT) | |
printf("\nFind files & folders with modification dates between Unix timestamps: %lu - %lu\n\n", lower_limit_in_seconds, upper_limit_in_seconds); | |
} | |
OSErr err; | |
FSRef container; | |
err = FSPathMakeRef((const UInt8 *)[volumeRoot UTF8String], &container, NULL); | |
if (err == fnfErr) | |
{ | |
fprintf(stderr, "findfile: No such volume '%s'\n", [volumeRoot UTF8String]); | |
return; | |
} | |
assert(err == noErr); | |
FSIterator iterator; | |
err = FSOpenIterator(&container, kFSIterateSubtree, &iterator); | |
assert(err == noErr); | |
FSSearchParams searchParams = {}; | |
searchParams.searchBits = fsSBPartialName; | |
searchParams.searchNameLength = [query length]; | |
searchParams.searchName = calloc([query length], sizeof(unichar)); | |
[query getCharacters:(unichar *)searchParams.searchName]; | |
// call FSCatalogSearch until the iterator is exhausted | |
if (print0 == 0) // print0 is set to 0 (false) | |
{ | |
ItemCount maximumObjects = 1; | |
while (err != errFSNoMoreItems) | |
{ | |
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; | |
ItemCount count; | |
FSRef refs[maximumObjects]; // the size of the buffer is doubled during each iteration | |
err = FSCatalogSearch(iterator, &searchParams, maximumObjects, &count, NULL, kFSCatInfoNone, NULL, refs, NULL, NULL); | |
assert(err == noErr || err == errFSNoMoreItems); | |
int i; | |
for (i=0; i<count; i++) | |
{ | |
FSRef ref = refs[i]; | |
CFURLRef url = CFURLCreateFromFSRef(kCFAllocatorDefault, &ref); | |
// get the full path as C string | |
file = [[(id)url path] UTF8String]; | |
struct stat statinfo; | |
if (0 == lstat(file, &statinfo)) | |
{ | |
lstatsecs = statinfo.st_mtime; | |
// print file system items between given Unix timestamps: lower_limit_in_seconds & upper_limit_in_seconds | |
if ( (lstatsecs >= lower_limit_in_seconds) && (lstatsecs <= upper_limit_in_seconds) ) | |
printf("%s\n", file); | |
} else { | |
fprintf(stderr, "findfile: cannot display the modification date of file:\n%s\n", file); | |
} // if lstat | |
} // for | |
if (maximumObjects < 128) | |
maximumObjects *= 2; | |
[pool release]; | |
} // while | |
} else { // print0 is set to 1 (true) | |
ItemCount maximumObjects = 1; | |
while (err != errFSNoMoreItems) | |
{ | |
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; | |
ItemCount count; | |
FSRef refs[maximumObjects]; // the size of the buffer is doubled during each iteration | |
err = FSCatalogSearch(iterator, &searchParams, maximumObjects, &count, NULL, kFSCatInfoNone, NULL, refs, NULL, NULL); | |
assert(err == noErr || err == errFSNoMoreItems); | |
int i; | |
for (i=0; i<count; i++) | |
{ | |
FSRef ref = refs[i]; | |
CFURLRef url = CFURLCreateFromFSRef(kCFAllocatorDefault, &ref); | |
// get the full path as C string | |
file = [[(id)url path] UTF8String]; | |
struct stat statinfo; | |
if (0 == lstat(file, &statinfo)) | |
{ | |
lstatsecs = statinfo.st_mtime; | |
// print file system items between given Unix timestamps | |
if ( (lstatsecs >= lower_limit_in_seconds) && (lstatsecs <= upper_limit_in_seconds) ) | |
{ | |
if (print7 == 1) | |
printf("%s\777%lu", file, lstatsecs); // print: filepath\777nseconds | |
else | |
printf("%s", file); // print: filepath | |
putchar(0); // print \000 to stdout | |
} | |
} else { | |
fprintf(stderr, "findfile: cannot display the modification date of file:\n%s\n", file); | |
} // if lstat | |
} // for | |
if (maximumObjects < 128) | |
maximumObjects *= 2; | |
[pool release]; | |
} // while | |
} // if print0 | |
free((void *)searchParams.searchName); | |
searchParams.searchName = 0; // avoid dangling pointer | |
FSCloseIterator(iterator); | |
return; | |
} // void find_all | |
void find_files_modified(int print0, int print7, unsigned long int current_time_in_seconds, unsigned long int time_of_date_in_seconds, \ | |
unsigned long int minus_in_seconds, unsigned long int plus_in_seconds, unsigned long int seconds, \ | |
int search_dir, NSString * query, NSString * volumeRoot, int verbose) | |
{ | |
NSTimeInterval epochsecs; | |
NSDate * date = nil; | |
NSString * dateStr = nil; | |
const char * upperlim = 0; | |
const char * lowerlim = 0; | |
const char * file = 0; | |
unsigned long int lower_limit_in_seconds; | |
unsigned long int upper_limit_in_seconds; | |
unsigned long int lstatsecs; | |
if ( time_of_date_in_seconds == 0 ) | |
time_of_date_in_seconds = current_time_in_seconds; | |
if ( (minus_in_seconds == 0) && (plus_in_seconds == 0) && (seconds > 0) ) | |
minus_in_seconds = seconds; | |
if ( minus_in_seconds >= time_of_date_in_seconds ) | |
minus_in_seconds = time_of_date_in_seconds; | |
if ( minus_in_seconds > 0 ) | |
lower_limit_in_seconds = time_of_date_in_seconds - minus_in_seconds; | |
else | |
lower_limit_in_seconds = 0; | |
if ( plus_in_seconds > 0 ) | |
upper_limit_in_seconds = time_of_date_in_seconds + plus_in_seconds; | |
else | |
upper_limit_in_seconds = current_time_in_seconds; | |
epochsecs = upper_limit_in_seconds; | |
date = [NSDate dateWithTimeIntervalSince1970: epochsecs]; | |
dateStr = [date description]; | |
upperlim = [dateStr UTF8String]; | |
epochsecs = lower_limit_in_seconds; | |
date = [NSDate dateWithTimeIntervalSince1970: epochsecs]; | |
dateStr = [date description]; | |
lowerlim = [dateStr UTF8String]; | |
if ( verbose == 1 ) | |
{ | |
printf("\nSearch date: %s\n", [[[NSDate date] description] UTF8String]); | |
if (search_dir == 0) | |
{ | |
printf("\nSearch for files in HFS+ volume: %s\n", [volumeRoot UTF8String]); | |
printf("\nSearch for file names containing substring: %s\n", [query UTF8String]); | |
printf("\nFind files with modification dates between: %s - %s\n", lowerlim, upperlim); | |
printf("\nFind files with modification dates between Unix timestamps: %lu - %lu\n\n", lower_limit_in_seconds, upper_limit_in_seconds); | |
}else{ | |
printf("\nSearch for folders in HFS+ volume: %s\n", [volumeRoot UTF8String]); | |
printf("\nSearch for folder names containing substring: %s\n", [query UTF8String]); | |
printf("\nFind modification dates of folders between: %s - %s\n", lowerlim, upperlim); | |
printf("\nFind modification dates of folders between Unix timestamps: %lu - %lu\n\n", lower_limit_in_seconds, upper_limit_in_seconds); | |
} | |
} | |
OSErr err; | |
FSRef container; | |
err = FSPathMakeRef((const UInt8 *)[volumeRoot UTF8String], &container, NULL); | |
if (err == fnfErr) | |
{ | |
fprintf(stderr, "findfile: No such volume '%s'\n", [volumeRoot UTF8String]); | |
return; | |
} | |
assert(err == noErr); | |
FSIterator iterator; | |
err = FSOpenIterator(&container, kFSIterateSubtree, &iterator); | |
assert(err == noErr); | |
FSSearchParams searchParams = {}; | |
FSCatalogInfo searchInfo1; | |
FSCatalogInfo searchInfo2; | |
// timeout as used by a Time Manager task, or 0 for no timeout | |
searchParams.searchTime = 0; | |
// fields to look at in searchInfo1 and searchInfo2 structs | |
searchParams.searchBits = fsSBPartialName + fsSBFlAttrib; | |
searchParams.searchInfo1 = &searchInfo1; // the catalog info to match | |
searchParams.searchInfo2 = &searchInfo2; // the catalog info mask | |
searchParams.searchNameLength = [query length]; | |
searchParams.searchName = calloc([query length], sizeof(unichar)); | |
if (search_dir == 0) | |
searchInfo1.nodeFlags = 0; // only match files | |
else | |
searchInfo1.nodeFlags = kFSNodeIsDirectoryMask; // only match directories | |
searchInfo2.nodeFlags = kFSNodeIsDirectoryMask; // check only this nodeFlagbit | |
[query getCharacters:(unichar *)searchParams.searchName]; | |
// call FSCatalogSearch until the iterator is exhausted | |
if (print0 == 0) // print0 is set to 0 (false) | |
{ | |
ItemCount maximumObjects = 1; | |
while (err != errFSNoMoreItems) | |
{ | |
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; | |
ItemCount count; | |
FSRef refs[maximumObjects]; // the size of the buffer is doubled during each iteration | |
err = FSCatalogSearch(iterator, &searchParams, maximumObjects, &count, NULL, kFSCatInfoNodeFlags, NULL, refs, NULL, NULL); | |
assert(err == noErr || err == errFSNoMoreItems); | |
int i; | |
for (i=0; i<count; i++) | |
{ | |
FSRef ref = refs[i]; | |
CFURLRef url = CFURLCreateFromFSRef(kCFAllocatorDefault, &ref); | |
// get the full path as C string | |
file = [[(id)url path] UTF8String]; | |
struct stat statinfo; | |
if (0 == lstat(file, &statinfo)) | |
{ | |
lstatsecs = statinfo.st_mtime; | |
// print file system items between given Unix timestamps: lower_limit_in_seconds & upper_limit_in_seconds | |
if ( (lstatsecs >= lower_limit_in_seconds) && (lstatsecs <= upper_limit_in_seconds) ) | |
printf("%s\n", file); | |
} else { | |
fprintf(stderr, "findfile: cannot display the modification date of file:\n%s\n", file); | |
} | |
} // for | |
if (maximumObjects < 128) | |
maximumObjects *= 2; | |
[pool release]; | |
} // while | |
} else { // print0 is set to 1 (true) | |
ItemCount maximumObjects = 1; | |
while (err != errFSNoMoreItems) | |
{ | |
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; | |
ItemCount count; | |
FSRef refs[maximumObjects]; // the size of the buffer is doubled during each iteration | |
err = FSCatalogSearch(iterator, &searchParams, maximumObjects, &count, NULL, kFSCatInfoNodeFlags, NULL, refs, NULL, NULL); | |
assert(err == noErr || err == errFSNoMoreItems); | |
int i; | |
for (i=0; i<count; i++) | |
{ | |
FSRef ref = refs[i]; | |
CFURLRef url = CFURLCreateFromFSRef(kCFAllocatorDefault, &ref); | |
// get the full path as C string | |
file = [[(id)url path] UTF8String]; | |
struct stat statinfo; | |
if (0 == lstat(file, &statinfo)) | |
{ | |
lstatsecs = statinfo.st_mtime; | |
// print file system items between given Unix timestamps | |
if ( (lstatsecs >= lower_limit_in_seconds) && (lstatsecs <= upper_limit_in_seconds) ) | |
{ | |
if (print7 == 1) | |
printf("%s\777%lu", file, lstatsecs); // print: filepath\777nseconds | |
else | |
printf("%s", file); // print: filepath | |
putchar(0); // print \000 to stdout | |
} | |
} else { | |
fprintf(stderr, "findfile: cannot display the modification date of file:\n%s\n", file); | |
} // if lstat | |
} // for | |
if (maximumObjects < 128) | |
maximumObjects *= 2; | |
[pool release]; | |
} // while | |
} // if print0 | |
free((void *)searchParams.searchName); | |
searchParams.searchName = 0; // avoid dangling pointer | |
FSCloseIterator(iterator); | |
return; | |
} // void find_files_modified | |
int main (int argc, const char * argv[]) { | |
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; | |
NSString * volumeRoot = [NSString stringWithString: @"/"]; | |
int ch; | |
// added | |
NSString * secondstr = [NSString stringWithString: @"0"]; | |
NSString * time_of_date_in_secondstr = [NSString stringWithString: @"0"]; | |
NSString * minus_in_secondstr = [NSString stringWithString: @"0"]; | |
NSString * plus_in_secondstr = [NSString stringWithString: @"0"]; | |
NSString * query = [NSString stringWithString: @""]; | |
int no_modified_search = 0; | |
int search_all = 0; | |
int search_dir = 0; | |
int search_file = 0; | |
int print0 = 0; | |
int print7 = 0; | |
int verbose = 0; | |
const char * secstr = 0; // initialize pointer to null pointer: cf. Null Pointers, http://www.lysator.liu.se/c/c-faq/c-1.html and http://c-faq.com/null/index.html | |
const char * todisecstr = 0; | |
const char * misecstr = 0; | |
const char * pisecstr = 0; | |
unsigned long int current_time_in_seconds; | |
unsigned long int seconds; | |
unsigned long int time_of_date_in_seconds; | |
unsigned long int minus_in_seconds; | |
unsigned long int plus_in_seconds; | |
unsigned long int *iptr = 0; | |
// get current UTC time in seconds | |
// cf. man 3 time | |
time_t sec; | |
sec = time(0); | |
current_time_in_seconds = sec; // assign sec to an unsigned long int | |
//printf ("Number of seconds since January 1, 1970: %lu\n", current_time_in_seconds); | |
while ((ch = getopt(argc, (char **)argv, "m:p:r:s:t:adfhnv07")) != -1) { | |
switch (ch) | |
{ | |
case '0': | |
print0 = 1; | |
break; | |
case '7': | |
print7 = 1; | |
break; | |
case 'a': | |
search_all = 1; | |
break; | |
case 'd': | |
search_dir = 1; | |
break; | |
case 'f': | |
search_file = 1; | |
break; | |
case 'h': | |
usage(); | |
return 0; | |
case 'm': | |
minus_in_secondstr = [NSString stringWithUTF8String: optarg]; | |
break; | |
case 'n': | |
no_modified_search = 1; | |
break; | |
case 'p': | |
plus_in_secondstr = [NSString stringWithUTF8String: optarg]; | |
break; | |
case 'r': | |
volumeRoot = [NSString stringWithUTF8String: optarg]; | |
break; | |
case 's': | |
secondstr = [NSString stringWithUTF8String: optarg]; | |
break; | |
case 't': | |
time_of_date_in_secondstr = [NSString stringWithUTF8String: optarg]; | |
break; | |
case 'v': | |
verbose = 1; | |
break; | |
case '?': | |
default: | |
usage(); | |
return 1; | |
} | |
} | |
argc -= optind; | |
argv += optind; | |
if (argc == 1) | |
query = [NSString stringWithUTF8String:argv[0]]; | |
if (argc > 1) | |
{ | |
usage(); | |
goto catch_error; | |
} | |
// -f switch overrides -d switch | |
if (search_file == 1) { search_dir = 0; } | |
// convert seconds string into an unsigned long integer | |
secstr = [secondstr UTF8String]; | |
//seconds = strtoul(secstr, 0, 10); | |
//printf("unsigned long integer seconds: %lu\n", seconds); | |
iptr = &seconds; | |
if ( 0 != isULInt(secstr, iptr) ) // convert the input string into an integer and make sure the integer is valid & not too big | |
return 1; | |
if ( seconds > current_time_in_seconds ) | |
{ | |
fprintf(stderr, "findfile: number of seconds too high: %lu\n", seconds); | |
fprintf(stderr, "findfile: number of seconds since January 1, 1970: %lu \n", current_time_in_seconds); | |
return 1; | |
} | |
// convert time_of_date_in_secondstr into an unsigned long integer | |
todisecstr = [time_of_date_in_secondstr UTF8String]; | |
iptr = &time_of_date_in_seconds; | |
if ( 0 != isULInt(todisecstr, iptr) ) | |
return 1; | |
if ( time_of_date_in_seconds > current_time_in_seconds ) | |
{ | |
fprintf(stderr, "findfile: number of seconds too high for time_of_date_in_seconds: %lu\n", time_of_date_in_seconds); | |
fprintf(stderr, "findfile: number of seconds since January 1, 1970: %lu \n", current_time_in_seconds); | |
return 1; | |
} | |
// convert minus_in_secondstr into an unsigned long integer | |
misecstr = [minus_in_secondstr UTF8String]; | |
iptr = &minus_in_seconds; | |
if ( 0 != isULInt(misecstr, iptr) ) | |
return 1; | |
if ( minus_in_seconds > current_time_in_seconds ) | |
{ | |
fprintf(stderr, "findfile: number of seconds too high for minus_in_seconds: %lu\n", minus_in_seconds); | |
fprintf(stderr, "findfile: number of seconds since January 1, 1970: %lu \n", current_time_in_seconds); | |
return 1; | |
} | |
// convert plus_in_secondstr into an unsigned long integer | |
pisecstr = [plus_in_secondstr UTF8String]; | |
iptr = &plus_in_seconds; | |
if ( 0 != isULInt(pisecstr, iptr) ) | |
return 1; | |
if ( plus_in_seconds > current_time_in_seconds ) | |
{ | |
fprintf(stderr, "findfile: number of seconds too high for plus_in_seconds: %lu\n", plus_in_seconds); | |
fprintf(stderr, "findfile: number of seconds since January 1, 1970: %lu \n", current_time_in_seconds); | |
return 1; | |
} | |
if ( (print7 == 1) && (print0 == 0) ) | |
{ | |
fprintf(stderr, "\n\"-7\" requires \"-0\": \"-07\"\n\nSee: hfsfind -h\n\n"); | |
return 1; | |
} | |
if ( (print7 == 1) && (no_modified_search == 1) ) | |
{ | |
fprintf(stderr, "\n\"-n\" disables modification dates!\nUse \"-07\" without the \"-n\" option!\n\nSee: hfsfind -h\n\n"); | |
return 1; | |
} | |
// illegal combination of options: -n and time variable > 0 | |
if ( (no_modified_search == 1) && ( (seconds > 0) || (minus_in_seconds > 0) || (plus_in_seconds > 0) || (time_of_date_in_seconds > 0) ) ) | |
{ | |
fprintf(stderr, "\nIllegal combination of options: -n and time variable > 0\n\nSee: hfsfind -h\n\n"); | |
return 1; | |
} | |
// switch to no_modified_search if all time variables are set to zero | |
if ( (no_modified_search == 0) && (seconds == 0) && (minus_in_seconds == 0) && (plus_in_seconds == 0) && (time_of_date_in_seconds == 0) ) | |
no_modified_search = 1; | |
if ( (no_modified_search == 1) && (search_all == 1) ) | |
find_all(print0, query, volumeRoot, verbose); | |
else if ( no_modified_search == 1) | |
find_files(print0, search_dir, query, volumeRoot, verbose); | |
else if (search_all == 1) | |
find_all_modified(print0, print7, current_time_in_seconds, time_of_date_in_seconds, minus_in_seconds, \ | |
plus_in_seconds, seconds, query, volumeRoot, verbose); | |
else | |
find_files_modified(print0, print7, current_time_in_seconds, time_of_date_in_seconds, minus_in_seconds, \ | |
plus_in_seconds, seconds, search_dir, query, volumeRoot, verbose); | |
catch_error: | |
[pool release]; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment