Find largest files on Mac OS X
# man mdfind # find files greater than 50 MB, 100 MB, ... mdfind 'kMDItemFSSize > 52428800' mdfind "kMDItemFSSize > $[50*1024*1024]" mdfind "kMDItemFSSize > $[100*1024*1024]" # man find # Note: "find -x ..." (BSD find) or "find -xdev ..." (GNU find) # Don't descend directories on other filesystems. # Useful for searching a single hard drive partition and omitting other HDD partitions, /proc, /dev, # CDROM's, network mounts, etc. (network drives and CD's can be really slow to search) # see: http://www.softpanorama.org/Tools/find.shtml df -ah mount -v diskutil list diskutil info / diskutil info disk0 # compare "Device: ..." /usr/bin/stat -x / /usr/bin/stat -x /dev /usr/bin/stat -x ~ /usr/bin/stat -x /Volumes/* /usr/bin/stat -x /Volumes/* | sed -E "s/(Device)/$(printf '\e[1m\\1\e[m')/" /usr/bin/stat -x /Volumes/* | sed -E "s/(Device: [[:digit:]]+,?[[:digit:]]* )/$(printf '\e[1m\\1\e[m')/" /usr/bin/stat -x /Volumes/* | sed -E "s/(Device: [[:digit:],]+ )/$(printf '\e[1m\\1\e[m')/" /usr/bin/stat -x / ~ /dev /Volumes /Volumes/* | sed -E "s/(File: .+$|Device: [[:digit:],]+ )/$(printf '\e[1m\\1\e[m')/" | nl /usr/bin/stat -x / ~ /dev /Volumes /Volumes/* | sed -E -e "s/(File: .+)/$(printf '\e[1m\\1\e[m')/" -e "s/(Device: [[:digit:],]+ )/$(printf '\e[1;31m\\1\e[m')/" | nl /usr/bin/stat -x /dev/* | sed -E "s/(File: .+$|Device: [[:digit:],]+ )/$(printf '\e[1m\\1\e[m')/" | nl /usr/bin/stat -x /dev/* | sed -E -e "s/(File: .+)/$(printf '\e[1m\\1\e[m')/" -e "s/(Device: [[:digit:],]+ )/$(printf '\e[1;31m\\1\e[m')/" | nl /usr/bin/find /dev | nl /usr/bin/find /dev -not -type d | nl /usr/bin/find -x /dev -not -type d | nl /usr/bin/find -x /dev -not -type d -ls | nl # find the 10 largest files on your system (> 50 MB) /usr/bin/sudo -H -i # only skip /dev /usr/bin/find / -not \( -type d -path '/dev' -prune \) -type f -size +$[50*1024*1024]c -ls 2>/dev/null | /usr/bin/sort -rn -k 7,7 | /usr/bin/head | /usr/bin/nl # do not descend into directories mounted from other filesystems (including network-mounted filesystems) /usr/bin/find -x / -type f -size +$[50*1024*1024]c -ls 2>/dev/null | /usr/bin/sort -rn -k 7,7 | /usr/bin/head | /usr/bin/nl exit # list local mounted volumes (file systems) including hard drive disk partitions, CDs, iPods, etc /bin/df -l | /usr/bin/sed -E -e 1d -e 's/^([^ ]+[ ]+)[^\/]+//' | /usr/bin/sort -u # list local hard drive disk partitions only (/dev/disk0*) /bin/df -l | /usr/bin/sed -E -e 1d -e '/^\/dev\/disk0/!d' -e 's/^([^ ]+[ ]+)[^\/]+//' | /usr/bin/sort -u # only scan local hard drive disk partitions (one by one) /usr/bin/sudo -H -i declare IFS=$'\n' for volume in $(/bin/df -l | /usr/bin/sed -E -e 1d -e '/^\/dev\/disk0/!d' -e 's/^([^ ]+[ ]+)[^\/]+//' | /usr/bin/sort -u); do echo echo "... scanning volume: ${volume}" /usr/bin/find -x "${volume}" -type f -size +$[50*1024*1024]c -ls 2>/dev/null | /usr/bin/sort -rn -k 7,7 | /usr/bin/head | /usr/bin/nl done declare IFS=$' \t\n' exit # store file paths of files > 50 MB in array (only skip /dev) /usr/bin/sudo -H -i man ruby | less -p 777 IFS=$'\777' #array=( $(/usr/bin/find / -not \( -type d -path '/dev' -prune \) -type f -size +$[50*1024*1024]c -exec printf "%s\777" '{}' \; 2>/dev/null) ) array=( $(/usr/bin/find / -not \( -type d -path '/dev' -prune \) -type f -size +$[50*1024*1024]c -exec printf "%s\777" '{}' + 2>/dev/null) ) IFS=$' \t\n' echo ${#array[@]} printf "%s\n" "${array[@]}" | nl echo "${array[0]}" exit # store all file paths of files > 50 MB on local hard drive in array (only scan local hard drive partitions) /usr/bin/sudo -H -i declare -a array tmparray declare IFS=$'\n' for volume in $(/bin/df -l | /usr/bin/sed -E -e 1d -e '/^\/dev\/disk0/!d' -e 's/^([^ ]+[ ]+)[^\/]+//' | /usr/bin/sort -u); do echo echo "... scanning volume: ${volume}" IFS=$'\777' #tmparray=( $(/usr/bin/find -x "${volume}" -type f -size +$[50*1024*1024]c -exec printf "%s\777" '{}' \; 2>/dev/null) ) #tmparray=( $(/opt/local/bin/gfind "${volume}" -xdev -type f -size +$[50*1024*1024]c -exec printf "%s\777" '{}' + 2>/dev/null) ) tmparray=( $(/usr/bin/find -x "${volume}" -type f -size +$[50*1024*1024]c -exec printf "%s\777" '{}' + 2>/dev/null) ) array=( "${array[@]}" "${tmparray[@]}" ) unset -v tmparray declare -a tmparray IFS=$'\n' done # this will truncate file paths containing spaces printf "%s\000" "${array[@]}" | xargs -0 /usr/bin/stat -f $'%z\t\t%N' | sort -rn | awk '{print $1/(1024*1024.0),$2;}' # this will truncate file paths containing newlines \n printf "%s\000" "${array[@]}" | xargs -0 /usr/bin/stat -f $'%z\t\t%N' | sort -rn -k 1,1 -t $'\t' | \ awk -F $'\t' '{printf "MB: %-20s", $1/(1024*1024.0); for (i=2;i<NF+1;i++) {printf "%s",$i}; print ""}' # encode newlines \n as NEWLINE # cf. Sorting arrays in Bash, http://codesnippets.joyent.com/posts/show/1592 printf "%s\000\n" "${array[@]}" | sed -e :a -e '$!N; s/\n/NEWLINE/g; ta' | ruby -n -e 'p $_.to_s' printf "%s\000\n" "${array[@]}" | sed -e :a -e '$!N; s/\n/NEWLINE/g; ta' | tr '\000' '\n' | ruby -n -e 'p $_.to_s' printf "%s\000\n" "${array[@]}" | sed -e :a -e '$!N; s/\n/NEWLINE/g; ta' | tr '\000' '\n' | sed -e 's/^NEWLINE//' | ruby -n -e 'p $_.to_s' printf "%s\000\n" "${array[@]}" | sed -e :a -e '$!N; s/\n/NEWLINE/g; ta' | tr '\000' '\n' | sed -e 's/^NEWLINE//' -e s/NEWLINE/$'\\\n'/ | ruby -n -e 'p $_.to_s' # In the first two commands (printf, stat) use \000 and \777 to mark the end of each file path, then ... : # - encode embedded newlines \n as NEWLINE (sed) # - convert \777 into \n again (tr) # - delete the last line (sed) # - sort the resulting lines according to the first column of bytes (sort) # - use awk to add line numbers and convert bytes into megabytes (awk) # - and finally restore embedded newline characters in file paths (sed) printf "%s\000" "${array[@]}" | xargs -0 /usr/bin/stat -n -f $'%z\t\t%N\777' | /usr/bin/sed -e :a -e '$!N; s/\n/NEWLINE/g; ta' | tr $'\777' $'\n' | sed '$d' | \ sort -rn -k 1,1 -t $'\t' | awk -F "\t" '{printf "%s\t%-20s", NR, $1/(1024*1024.0); for (i=2;i<NF+1;i++) {printf "%s",$i}; print ""}' | sed -e $'s/NEWLINE/\\\n/' # same as previous command sequence except that the awk command (cf. ORS) marks the end of each file path with \777 again printf "%s\000" "${array[@]}" | xargs -0 /usr/bin/stat -n -f $'%z\t\t%N\777' | /usr/bin/sed -e :a -e '$!N; s/\n/NEWLINE/g; ta' | tr $'\777' $'\n' | sed '$d' | \ sort -rn -k 1,1 -t $'\t' | awk -F "\t" -v ORS="\777" '{printf "%-20s", $1/(1024*1024.0); for (i=2;i<NF+1;i++) {printf "%s",$i}; print ""}' | sed -e $'s/NEWLINE/\\\n/' # use the previous command sequence to read the sorted list of file paths into an array again IFS=$'\777' result=( $( printf "%s\000" "${array[@]}" | xargs -0 /usr/bin/stat -n -f $'%z\t\t%N\777' | /usr/bin/sed -e :a -e '$!N; s/\n/NEWLINE/g; ta' | tr $'\777' $'\n' | sed '$d' | \ sort -rn -k 1,1 -t $'\t' | awk -F "\t" -v ORS="\777" '{printf "%-20s", $1/(1024*1024.0); for (i=2;i<NF+1;i++) {printf "%s",$i}; print ""}' | sed -e $'s/NEWLINE/\\\n/' ) ) IFS=$'\n' # print sorted list of file sizes (in MB) with file paths for ((i=0; i < ${#result[@]}; i++)); do printf "%-5s %s\n" "$[i+1]" "${result[${i}]}"; done exit # sudo shell #---------------------------------------------------------------------------------------------------- # ... testing weird file paths mkfile 10m ${HOME}/Desktop/'te:st\file:' # convert file sizes to megabyte with awk (> 1 MB) /usr/bin/find -x ~/Desktop -type f -size +$[1*1024*1024]c -print0 2>/dev/null | xargs -0 stat -f "%z: %N" | \ sort -rn | awk -F: '{printf "%-20s", $1/(1024*1024.0); for (i=2;i<NF+1;i++) {printf "%s%s",$i,(i==NF) ? "\n" : ":"}}' # find the 10 largest directories in the current directory /usr/bin/find -x . -mindepth 1 -maxdepth 1 -type d -print0 | xargs -0 du -hs /usr/bin/find -x . -mindepth 1 -maxdepth 1 -type d -print0 | xargs -0 du -ks | sort -rn | head # awk: print the first field and from the second field to the end (just in case there are file paths with spaces) /usr/bin/find -x . -mindepth 1 -maxdepth 1 -type d -print0 | xargs -0 du -ks | sort -rn | head | \ awk -F' ' '{printf "%-20s", $1/1024.0; for (i=2;i<NF+1;i++) {printf "%s ",$i}; print ""}' #---------------------------------------------------------------------------------------------------- # sort file sizes & file paths containing newlines \n # cf. Sorting arrays in Bash, http://codesnippets.joyent.com/posts/show/1592 mkfile 10m ${HOME}/Desktop/'te:st\file'.txt mkfile 10m ${HOME}/Desktop/'te:st\file:' mkfile 10m ${HOME}/Desktop/$'te:s\nt\\file:' declare -a file_path_array man ruby | less -p '777' IFS=$'\777' file_path_array=($(/usr/bin/find -x ~/Desktop -type f -size +$[1*1024*1024]c -print0 2>/dev/null | xargs -0 -n 500 printf "%s\777")) IFS=$' \t\n' echo "${#file_path_array[@]}" echo "${file_path_array[@]}" printf "%s\n" "${file_path_array[@]}" | ruby -n -e 'p $_.to_s' declare -a file_path_array2 for ((i=0; i < "${#file_path_array[@]}"; i++)); do mbyte=$(/usr/bin/stat -f "%z" "${file_path_array[$i]}" | awk '{print $1/(1024*1024.0);}') file_path_array2[${i}]="${mbyte}: ${file_path_array[$i]}" done echo "${#file_path_array2[@]}" echo "${file_path_array2[@]}" IFS=$'\n' declare -a file_path_array2_sorted file_path_array2_sorted=( $(printf "%s\000\n" "${file_path_array2[@]}" | sed -e :a -e '$!N; s/\n/NEWLINE/g; ta' | tr '\000' '\n' | \ sed -e 's/^NEWLINE//' | sort -rn -t . -k 1,1 -k 2,2) ) IFS=$' \t\n' for ((i=0; i < "${#file_path_array2_sorted[@]}"; i++)); do printf "%s\n" "${file_path_array2_sorted[$i]//NEWLINE/$'\n'}"; done | nl for ((i=0; i < "${#file_path_array2_sorted[@]}"; i++)); do printf "%s\n" "${file_path_array2_sorted[$i]//NEWLINE/\n}"; done | nl for ((i=0; i < "${#file_path_array2_sorted[@]}"; i++)); do printf "%s" "${file_path_array2_sorted[$i]//NEWLINE/\n}" | ruby -0777 -n -e 'p $_.to_s' done | nl #---------------------------------------------------------------------------------------------------- # alternative declare -i i=0 declare -a file_path_array while read -d $'\000' filepath; do mbyte=$(/usr/bin/stat -f "%z" "${filepath}" | awk '{print $1/(1024*1024.0);}') file_path_array[${i}]="${mbyte}: ${filepath}" let i++ done < <(/usr/bin/find -x ~/Desktop -type f -size +$[1*1024*1024]c -print0 2>/dev/null | sed -E '/\\/s/\\/\\\\/g') IFS=$'\n' declare -a file_path_array_sorted file_path_array_sorted=( $(printf "%s\000\n" "${file_path_array[@]}" | sed -e :a -e '$!N; s/\n/NEWLINE/g; ta' | tr '\000' '\n' | \ sed -e 's/^NEWLINE//' | sort -rn -t . -k 1,1 -k 2,2) ) IFS=$' \t\n' for ((i=0; i < "${#file_path_array_sorted[@]}"; i++)); do printf "%s\n" "${file_path_array_sorted[$i]//NEWLINE/$'\n'}"; done | nl for ((i=0; i < "${#file_path_array_sorted[@]}"; i++)); do printf "%s\n" "${file_path_array_sorted[$i]//NEWLINE/\n}"; done | nl for ((i=0; i < "${#file_path_array_sorted[@]}"; i++)); do printf "%s" "${file_path_array_sorted[$i]//NEWLINE/\n}" | ruby -0777 -n -e 'p $_.to_s' done | nl #---------------------------------------------------------------------------------------------------- # same for directory paths containing possible newlines \n declare -i i=0 declare -a dir_path_array while read -d $'\000' dirpath; do dir_size=$(/usr/bin/du -ks "${dirpath}" | /usr/bin/awk '/^[[:digit:]]+/{print $1/1024.0}') dir_path_array[${i}]="${dir_size} ${dirpath}" let i++ done < <(/usr/bin/find -x . -mindepth 1 -maxdepth 1 -type d -print0 2>/dev/null | sed -E '/\\/s/\\/\\\\/g') echo "${#dir_path_array[@]}" echo "${dir_path_array[@]}" printf "%s\n" "${dir_path_array[@]}" | ruby -n -e 'p $_.to_s' IFS=$'\n' declare -a dir_path_array_sorted dir_path_array_sorted=( $(printf "%s\000\n" "${dir_path_array[@]}" | sed -e :a -e '$!N; s/\n/NEWLINE/g; ta' | tr '\000' '\n' | \ sed -e 's/^NEWLINE//' | sort -rn -t . -k 1,1 -k 2,2) ) IFS=$' \t\n' for ((i=0; i < "${#dir_path_array_sorted[@]}"; i++)); do printf "%s\n" "${dir_path_array_sorted[$i]//NEWLINE/$'\n'}"; done | nl for ((i=0; i < "${#dir_path_array_sorted[@]}"; i++)); do printf "%s\n" "${dir_path_array_sorted[$i]//NEWLINE/\n}"; done | nl for ((i=0; i < "${#dir_path_array_sorted[@]}"; i++)); do printf "%s" "${dir_path_array_sorted[$i]//NEWLINE/\n}" | ruby -0777 -n -e 'p $_.to_s' done | nl #---------------------------------------------------------------------------------------------------- # get file sizes via ls command ls -alS ls -alSr ls -ahlS ls -ahlSr ls -alSrR #---------------------------------------------------------------------------------------------------- # bigfiles (see below) # scan local hard disk (/dev/disk0*) IFS=$'\n' bigfiles -v -m 10 $(/bin/df -l | /usr/bin/sed -E -e 1d -e '/^\/dev\/disk0/!d' -e 's/^([^ ]+[ ]+)[^\/]+//' | /usr/bin/sort -u) IFS=$' \t\n' IFS=$'\777' bigfiles $(localvols -7) # localvols (see below) IFS=$' \t\n'
bigfiles.c:
/* * * bigfiles -- list big files in given directories * * License: The MIT License, http://www.opensource.org/licenses/mit-license.php * Copyright (c) 2009 jv * * compile with: gcc -std=c99 -Wall -Wextra -pedantic -O3 -o bigfiles bigfiles.c * * For how to implement recursive directory scanning please see: * "fts(3) or Avoiding to Reinvent the Wheel", * http://keramida.wordpress.com/2009/07/05/fts3-or-avoiding-to-reinvent-the-wheel/ * * * man 2 stat: * * struct stat { * ... * off_t st_size; // file size, in bytes * ... * } * * * egrep -Irs --color 'typedef.*[[:space:]]off_t([[:space:];]|$)' /usr/include * egrep -Irs --color 'typedef.*[[:space:]]__darwin_off_t([[:space:];]|$)' /usr/include * egrep -Irs --color 'typedef.*[[:space:]]__int64_t([[:space:];]|$)' /usr/include * * typedef __darwin_off_t off_t; * typedef __int64_t __darwin_off_t; // [???] Used for file sizes * typedef long long __int64_t; * * * * usage example to scan local hard disk: * IFS=$'\n' * ~/Desktop/bigfiles -v -m 10 $(/bin/df -l | /usr/bin/sed -E -e 1d -e '/^\/dev\/disk0/!d' -e 's/^([^ ]+[ ]+)[^\/]+//' | /usr/bin/sort -u) * IFS=$' \t\n' * * */ #include <err.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <fts.h> #include <unistd.h> // getopt #include <limits.h> // PATH_MAX #define MAX_FILEPATH_LENGTH 2 * PATH_MAX // 2048 (in 2009) #define STRUCTS_IN_ARRAY 15000 static int ptree(char * const argv[], int argc, int megabytes, unsigned long long int print, int printfid, int verbose); static void usage() { static char const *usageinfo[] = { "bigfiles -- list big files in given directories", "Usage:", "bigfiles [-0] [-7] [-hv] [-m mbytes] [-n num] [ [dir1] [dir2] ...]", "-0: print each item to stdout in the following format: size\\777path\\777\\000", "-7: print each item to stdout in the following format: size\\777path\\777", "-h: help", "-m: megabytes (default: 50, min size: 2)", "-n: print n items (file size in MB & file path; default: 20)", "-n 0: print all items", "-v: verbose", "Note:", "- Files named '.' or '..' get scanned.", "- File search will not descend into directories that have a different device number than the file from which the descent began.", "- fts_options: FTS_COMFOLLOW | FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV | FTS_SEEDOT (see man 3 fts)" }; fprintf(stderr, "\n%s\n\n%s\n\n\t%s\n\n\t%s\n\n\t%s\n\n\t%s\n\n\t%s\n\n\t%s\n\n\t%s\n\n\t%s\n\n%s\n\n\t%s\n\n\t%s\n\n\t%s\n\n", usageinfo[0], usageinfo[1], usageinfo[2], usageinfo[3], usageinfo[4], usageinfo[5], usageinfo[6], usageinfo[7], usageinfo[8], usageinfo[9], usageinfo[10], usageinfo[11], usageinfo[12], usageinfo[13] ); } int main(int argc, char * const argv[]) { int megabytes = 50; unsigned long long int print = 20; int verbose = 0; int printfid = 10; // defaults to newline character \n; cf. man ascii (decimal set) if ( argc == 1 ) { usage(); return 0; } int ch; while ((ch = getopt(argc, (char **)argv, "m:n:07hv")) != -1) { switch (ch) { case '0': printfid = 0; break; case '7': printfid = 7; break; case 'h': usage(); return 0; case 'm': megabytes = atoi(optarg); break; case 'n': print = atoi(optarg); break; case 'v': verbose = 1; break; case '?': default: usage(); return 1; } } argc -= optind; argv += optind; if ( megabytes < 2 ) megabytes = 2; int rc; if ((rc = ptree(argv, argc, megabytes, print, printfid, verbose)) != 0) rc = 1; return rc; } void copystr (char *srcstr, char *tgtstr) { while ( *srcstr ) { *tgtstr++ = *srcstr++; } *tgtstr = '\0'; } struct file_size_path { unsigned long long int file_size; char *file_path; }; // VLA (variable length array) in C99 // For some VLA links see: Xcode now defaults to use C99 - so what's C99?, // http://www.cocoabuilder.com/archive/message/xcode/2008/5/30/21989 struct file_size_path array_file_size_path[STRUCTS_IN_ARRAY]; // qsort / mergesort struct comparison function (file_size field) int struct_cmp_by_filesize(const void *a, const void *b) { struct file_size_path *ia = (struct file_size_path *)a; struct file_size_path *ib = (struct file_size_path *)b; // return 1 or -1 if file_size members are not equal //if (ia->file_size > ib->file_size) return 1; //if (ia->file_size < ib->file_size) return -1; if (ia->file_size < ib->file_size) return 1; if (ia->file_size > ib->file_size) return -1; // return 0 if file_size members are equal return 0; } // struct array printing function void print_struct_array(struct file_size_path *array, unsigned long long int nitems, int printfid) { unsigned long long int i; for(i=0; i < nitems; i++) { switch (printfid) { case 0: printf("%llu\777%s\777", array[i].file_size, array[i].file_path); putchar(0); break; case 7: printf("%llu\777%s\777", array[i].file_size, array[i].file_path); break; case 10: printf("%-12llu %s\n", array[i].file_size, array[i].file_path); break; default: break; } } } static int ptree(char * const argv[], int argc, int megabytes, unsigned long long int print, int printfid, int verbose) { int i = 0; unsigned long long int x = 0; long long int bytes = megabytes * 1024 * 1024; unsigned long long int print_n_items = print; void copystr (char *srcstr, char *tgtstr); char filepathstr[MAX_FILEPATH_LENGTH]; unsigned long long int file_count = 0; unsigned long long int array_index = 0; unsigned long long int number_of_array_items = 0; FTS *ftsp; FTSENT *p, *chp; //int fts_options = FTS_COMFOLLOW | FTS_LOGICAL | FTS_NOCHDIR | FTS_SEEDOT; //int fts_options = FTS_COMFOLLOW | FTS_LOGICAL | FTS_NOCHDIR | FTS_XDEV | FTS_SEEDOT; int fts_options = FTS_COMFOLLOW | FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV | FTS_SEEDOT; int rval; rval = 0; if ((ftsp = fts_open(argv, fts_options, NULL)) == NULL) { warn("fts_open"); return -1; } // Initialize ftsp with as many argv[] parts as possible. chp = fts_children(ftsp, 0); //if (chp == NULL) return 0; // no files to traverse if (chp == NULL) { fprintf(stderr, "No files to traverKKKse. See -h option. Exiting ...\n"); return 1; } while ((p = fts_read(ftsp)) != NULL) { switch (p->fts_info) { /* // cf. man 3 fts case FTS_DNR: //printf("directory which cannot be read: %s\n", p->fts_path); break; case FTS_DC: //printf("directory that causes a cycle in the tree: %s\n", p->fts_path); break; case FTS_D: //printf("directory: %s\n", p->fts_path); break; case FTS_SLNONE: //printf("symbolic link with a non-existent target: %s\n", p->fts_path); break; case FTS_SL: //printf("symbolic link: %s\n", p->fts_path); break; */ case FTS_F: file_count++; if ( p->fts_statp->st_size < bytes ) break; // ignore files < bytes // convert bytes to megabytes array_file_size_path[array_index].file_size = p->fts_statp->st_size / (1024*1024); //printf("path: %s\n", p->fts_path); //printf("size: %jd\n", (intmax_t)p->fts_statp->st_size); copystr(p->fts_path, filepathstr); array_file_size_path[array_index].file_path = calloc( strlen(filepathstr) + 1, sizeof(char) ); if (array_file_size_path[array_index].file_path == NULL) exit(1); strcpy(array_file_size_path[array_index].file_path, filepathstr); array_index++; // we will increment array_index one too many here in the last while loop break; default: break; } // switch } // while fts_close(ftsp); if (array_index == 0) { printf("\nNo files found.\nSee -h option to modify search parameters.\n\n"); if (verbose == 1) { printf("\nSearching for files larger than: %i MB\n", megabytes); printf("\nPrint %llu sorted items (file size in MB & file path).\n", print_n_items); printf("\nNumber of files scanned: %llu\n", file_count); printf("\nNumber of files found: %llu\n", array_index); printf("\nDirectories scanned:\n\n"); for(i=0; i < argc; i++) { printf("%i: %s\n", i+1, argv[i]); } printf("\n\n\n"); } return 0; } number_of_array_items = array_index; array_index = number_of_array_items - 1; size_t structs_len = number_of_array_items; //size_t structs_len = sizeof(array_file_size_path) / sizeof(struct file_size_path); // sort array using qsort functions //qsort(array_file_size_path, structs_len, sizeof(struct file_size_path), struct_cmp_by_filesize); mergesort(array_file_size_path, structs_len, sizeof(struct file_size_path), struct_cmp_by_filesize); if ( (print_n_items == 0) || (print_n_items > number_of_array_items) ) print_n_items = number_of_array_items; if (verbose == 1) { printf("\nSearching for files larger than: %i MB\n", megabytes); printf("\nPrint %llu sorted items (file size in MB & file path).\n", print_n_items); printf("\nNumber of files scanned: %llu\n", file_count); printf("\nNumber of files found: %llu\n", number_of_array_items); printf("\nDirectories scanned:\n\n"); for(i=0; i < argc; i++) { printf("%i: %s\n", i+1, argv[i]); } printf("\n\n\n"); } // print sorted struct array print_struct_array(array_file_size_path, print_n_items, printfid); // free memory for( x=0; x < number_of_array_items; x++ ) { //memset(array_file_size_path[x].file_path, 0, sizeof(array_file_size_path[x].file_path)); //memset(array_file_size_path[x].file_path, 0, strlen(array_file_size_path[x].file_path) + 1); bzero(array_file_size_path[x].file_path, sizeof(array_file_size_path[x].file_path)); free (array_file_size_path[x].file_path); } return 0; } // ptree
localvols.c:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/param.h> #include <sys/ucred.h> #include <sys/mount.h> #include <errno.h> #include <unistd.h> // getopt // localvols - list local hfs & ufs volumes (file systems) on Mac OS X // License: The MIT License, http://www.opensource.org/licenses/mit-license.php // Copyright (c) 2009 jv // compile with: gcc -Wall -O3 -o localvols localvols.c static void usage() { static char const *usageinfo[] = { "localvols -- list locally mounted hfs & ufs volumes (file systems) on Mac OS X", "Usage:", "localvols [-0] [-7] [-afhu]", "-0: print volume paths to stdout in the following format: vol1\\000vol2\\000vol3\\000 (-print0)", "-7: print volume paths to stdout in the following format: vol1\\777vol2\\777vol3\\777 (-print7)", "-a: list all locally mounted hfs & ufs file systems", "-f: list all locally mounted hfs file systems only", "-h: help", "-u: list all locally mounted ufs file systems only", "Note:", "- file systems: hfs, ufs", "- default: list the local hard drive disk partitions mounted on /Volumes/*", "Examples:", "localvols", "localvols -7 | ruby -0777 -n -e 'p $_.to_s'", "IFS=$'\\777'", "lvols=( $(localvols) )", "IFS=$' \\t\\n'", "echo \"${lvols[0]}\"", "echo \"${lvols[1]}\"", "echo \"${lvols[@]}\"", "IFS=$'\\777'", "bigfiles $(localvols -7)", "IFS=$' \\t\\n'" }; fprintf(stderr, "\n%s\n\n%s\n\n\t%s\n\n\t%s\n\n\t%s\n\n\t%s\n\n\t%s\n\n\t%s\n\n\t%s\n\n\n%s\n\n\t%s\n\n\t%s\n\n\ \n%s\n\n\t%s\n\n\t%s\n\n\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n\n\t%s\n\t%s\n\t%s\n\n", usageinfo[0], usageinfo[1], usageinfo[2], usageinfo[3], usageinfo[4], usageinfo[5], usageinfo[6], usageinfo[7], usageinfo[8], usageinfo[9], usageinfo[10], usageinfo[11], usageinfo[12], usageinfo[13], usageinfo[14], usageinfo[15], usageinfo[16], usageinfo[17], usageinfo[18], usageinfo[19], usageinfo[20], usageinfo[21], usageinfo[22], usageinfo[23] ); } void printfid_function(int printfid, const char * volpath) { switch (printfid) { case 0: printf("%s", volpath); putchar(0); break; case 7: //printf("%s\777", volpath); printf("%s", volpath); putchar('\777'); break; case 10: printf("%s\n", volpath); break; default: break; } } int main(int argc, const char **argv) { struct statfs *mountlist; int ch, n, i; int all = 0; int all_hfs = 0; int all_ufs = 0; int printfid = 10; // defaults to newline character \n; cf. man ascii (decimal set) while ((ch = getopt(argc, (char **)argv, "07afhu")) != -1) { switch (ch) { case '0': printfid = 0; break; case '7': printfid = 7; break; case 'a': all = 1; break; case 'f': all_hfs = 1; break; case 'h': usage(); return 0; case 'u': all_ufs = 1; break; case '?': default: usage(); return 1; } } argc -= optind; argv += optind; if (argc > 0) { usage(); return 1; } //n = getmntinfo(&mountlist, 0); //n = getmntinfo(&mountlist, MNT_NOWAIT); n = getmntinfo(&mountlist, MNT_WAIT); // see man 3 getmntinfo and man 2 getfsstat if (n < 0) { fprintf(stderr, "getmntinfo failed: %s\n", strerror(errno)); exit(1); } if (all == 1) { for(i=0; i<n; i++) { if ( ( (mountlist[i].f_flags & MNT_LOCAL) == MNT_LOCAL ) && ( (strcmp(mountlist[i].f_fstypename, "hfs") == 0) || (strcmp(mountlist[i].f_fstypename, "ufs") == 0) ) ) { printfid_function(printfid, mountlist[i].f_mntonname); } } return 0; } if (all_hfs == 1) { for(i=0; i<n; i++) { if ( ((mountlist[i].f_flags & MNT_LOCAL) == MNT_LOCAL ) && (strcmp(mountlist[i].f_fstypename, "hfs") == 0) ) { printfid_function(printfid, mountlist[i].f_mntonname); } } return 0; } if (all_ufs == 1) { for(i=0; i<n; i++) { if ( ((mountlist[i].f_flags & MNT_LOCAL) == MNT_LOCAL ) && (strcmp(mountlist[i].f_fstypename, "ufs") == 0) ) { printfid_function(printfid, mountlist[i].f_mntonname); } } return 0; } // default // get the device node entry (/dev/disk*, 10 characters) of the root path / // see: man 8 diskutil | less -p DEVICES char root_path_device_node[11]; // can store up to 11 chars; the last index: 10 is used for the terminating '\0' char below //printf("%s\n", root_path_device_node); //printf("sizeof(root_path_device_node): %zu\n", sizeof(root_path_device_node)); for(i=0; i<n; i++) { if ( (strcmp(mountlist[i].f_mntonname, "/") == 0) ) { strncpy(root_path_device_node, mountlist[i].f_mntfromname, 10); root_path_device_node[10] = '\0'; break; } } for(i=0; i<n; i++) { if ( ( (mountlist[i].f_flags & MNT_LOCAL) == MNT_LOCAL ) && ( (strcmp(mountlist[i].f_fstypename, "hfs") == 0) || (strcmp(mountlist[i].f_fstypename, "ufs") == 0) ) && (strncmp(mountlist[i].f_mntfromname, root_path_device_node, 10) == 0) && ( (strcmp(mountlist[i].f_mntonname, "/") == 0) || (strncmp(mountlist[i].f_mntonname, "/Volumes/", 9) == 0) ) ) { printfid_function(printfid, mountlist[i].f_mntonname); } // if } // for return 0; }