Skip to content

Instantly share code, notes, and snippets.

@atr000
Created February 5, 2010 02:06
Show Gist options
  • Save atr000/295410 to your computer and use it in GitHub Desktop.
Save atr000/295410 to your computer and use it in GitHub Desktop.
//
// 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