Never been to CodeSnippets before?

Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world (or not, you can keep them private!)

1 total

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;

}



1 total