Submit Hint Search The Forums LinksStatsPollsHeadlinesRSS
14,000 hints and counting!


Click here to return to the 'Enh Req: View exactly which files Time Machine backed up' hint
The following comments are owned by whoever posted them. This site is not responsible for what they say.
Enh Req: View exactly which files Time Machine backed up
Authored by: scottbayes on Jul 17, '08 09:03:22PM

This is functionality I've been looking for for quite a while now. Thank you!

One small request, since I'm not Perl-literate: please add a -n or some such option to format the output in a more machine-friendly format, as:

3126 3157 /Macintosh HD/Library/Preferences/SystemConfiguration/com.apple.network.identification.plist

(with nice wide fields like %15d or something, and maybe with TAB as field separator) instead of:

3.1KB-> 3.1KB /Macintosh HD/Library/Preferences/SystemConfiguration/com.apple.network.identification.plist

Would make it easier to pipe to sort(1) or cut(1) or load as csv into Excel, etc. I'd usually like to see my top N big updates.

I think the current format should remain the default, my suggestion is for geeks.



[ Reply to This | # ]
Enh Req: View exactly which files Time Machine backed up
Authored by: jdsmith on Jul 23, '08 09:19:25AM
Here's an update with -n and which reports the number of changed contents for summarized directories (with -d).

#!/usr/bin/perl
#
# timedog
#
#   J.D. Smith (jdtsmith A@T gmail _dot_ com)
#
# Display the files which time machine backed up in its most recent
# backup (or any of your choosing).  Uses the fact that Time Machine
# creates hard links for unchanged files and directories.  Reports old
# and new sizes of the changed files, along with the total file count
# and backup size.
#
# Usage:  timedog [-d depth] [-l] [-n] [latest]
#
#   N.B. You must first mount the time machine volume, and change to
#   the directory containing your time machine backup directories, the
#   ones named like 2008-07-14-112245/.  This can be found in the
#   directory /Volumes/TM/Backups.backupdb/hostname or similar.
#
#     latest: The backup directory for which you'd like to see the
#             changed contents.  Defaults to the most recent (the one
#             linked to by Latest)
#
#         -l: Omit symbolic links from the summary.  For whatever
#             reason, Time Machine creates a new version of a symbolic
#             link each and every time it backs up.
#
#         -n  Use simple fixed width formatting, and omit summaries.
#
#   -d depth: By default, all files are printed, which can get
#             lengthy.  With this option, summarize changes in
#             directories only down to the given depth.  The number of
#             files and subdirectories which changed will be reported
#             as [n].
#
# Example:
#   % cd /Volumes/TM/Backups.backupdb/myhost
#   % timedog -d 5 -l
#
###############################################################################
# 
# LICENSE
#
#  Copyright (C) 2008 J.D. Smith
#
#  This file is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published
#  by the Free Software Foundation; either version 2, or (at your
#  option) any later version.
#
#  This File is distributed in the hope that it will be useful, but
#  WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
#  General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this file; see the file COPYING.  If not, write to the
#  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
#  Boston, MA 02110-1301, USA.
#
###############################################################################


use File::Find;
use Fcntl ':mode';
use Getopt::Std;

getopt('d');

sub bytes {
  my $bytes=shift;
  $format=shift || ".1";
  @suff=("B","KB","MB","GB","TB");
  for ($suff=shift @suff; $#suff>=0 and $bytes>=1000.; $suff=shift @suff) {
    $bytes/=1024.;
  }
  return int($bytes) . $suff if int($bytes)==$bytes;
  return sprintf("%${format}f",$bytes) . $suff;
}

sub summarize {
  ($size,$size_old,$old_exists,$name,$cnt)=@_;
  if ($opt_n) {
    printf "%12d %12d %s\n",$old_exists?$size_old:0,$size,$name;
  } else {
    if ($opt_d) { 
      printf "%9s->%9s %6s %s\n",$old_exists?bytes($size_old):"....  ",
	bytes($size),$cnt?"[$cnt]":"",$name;
    } else {
      printf "%9s->%9s %s\n",$old_exists?bytes($size_old):"....  ",
	bytes($size),$name;
    }
  }
}


opendir DIR,"." or die "Can't open directory.";
@files=sort grep {m|[0-9]{4}-[0-9]{2}-[0-9]{2}-[0-9]+$|} readdir(DIR);
die "None or only one Time Machine backups found." if @files == 1;

if (@ARGV) {
  $latest=$ARGV[0];
  $latest=~s|/$||;
  foreach (@files) {
    last if $_ eq $latest;
    $last=$_;
  }
  die "Invalid backup directory" if !defined($last) || $last eq $latest;
} else {
  ($last,$latest)=@files[$#files-1..$#files];
}

print "==> Comparing TM backup $latest to $last\n" unless $opt_n;

my ($old_exists,$rold_exists,$rsize,$rsize_old);
$total_size=0;
$total_cnt=0;

find({wanted =>
      sub{
	($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size) =
	  lstat($_);
	($old=$_)=~s/^$latest/$last/;
	if (-e $old) {
	  ($dev, $ino_old,$mode_old,
	   $nlink,$uid,$gid,$rdev,$size_old) = lstat($old);
	  if ($ino == $ino_old) { # Prune matching
	    $File::Find::prune=1 if -d;
	    return
	  }
	  $old_exists=1;
	} else {$old_exists=0;}


	$total_size+=$size;

	$link=S_ISLNK($mode);
	return if $opt_l && $link;

	# Don't include links in the count
	$total_cnt++;
	($name=$_)=~s/^$latest//;

	if ($opt_d) {
	  $depth=$name=~tr|/||;
	  $rsize+=$size;
	  $rsize_old+=$size_old if $old_exists;
	  $rcnt++;
	  return if S_ISDIR($mode) || $depth > $opt_d; # Post will handle
	}
	$name.="/" if S_ISDIR($mode);
	$name.="@" if $link;
	summarize($size,$size_old,$old_exists,$name);
      },
      preprocess =>
      (!$opt_d)?0:
      sub{
	$depth=$File::Find::dir=~tr|/||;
	if ($depth<=$opt_d) {
	  # Starting a new printable directory; zero out sizes
	  $rsize=$rsize_old=$rcnt=0;
	  $rold_exists=-e $File::Find::dir;
	}
	@_;
      },
      postprocess =>
      (!$opt_d)?0:
      sub{
	$depth=$File::Find::dir=~tr|/||;
	return if $depth > $opt_d;
	# This directory is at or below the depth, summarize it
	($name=$File::Find::dir)=~s/^$latest//;
	summarize($rsize,$rsize_old,$rold_exists,$name.'/',$rcnt)
	  if $rsize || $rsize_old;
	$rsize=$rsize_old=$rcnt=0;
      },
      no_chdir => 1}, $latest);

print "==> Total Backup: $total_cnt changed files/directories, ",
  bytes($total_size,".2"),"\n" unless $opt_n;


[ Reply to This | # ]