#!/usr/bin/python

# fix_ownership.py  (http://puddle.ca/~/sim/scripts/fix_broken_owners.html)
# 
# Repair file ownership munged by improper use of rsync
# Simeon Veldstra    25 August 2009
# Released to the Public Domain with *NO WARRANTY*
# Use at your own risk.
#
# Usage: 
# fix_ownership.py manifest_file
# Where manifest_file contains a null delimited list of filepaths 
# preceded with the file's UID and GID as produced by the following find command:
# find /path/to/mount/ -fprintf file_manifest "%U\000%G\000/%P\000"


import os
import sys


def fix_owners(filename, verbose=False, bufsize=2048):

    fp = file(filename, 'r')
    buf = [fp.read(bufsize)]

    def get_field():
        while 1:
            i = buf[0].find('\x00')
            if i != -1:
                break
            next = fp.read(bufsize)
            if next:
                buf[0] += next
            else:
                return None
        val = buf[0][:i]
        buf[0] = buf[0][i+1:]
        return val

    while 1:
        UID = get_field()
        GID = get_field()
        filepath = get_field()
        if UID is None:
            print "Done"
            break
        try:
            UID = int(UID)
            GID = int(GID)
        except ValueError, TypeError:
            print "Corruption in data file near:"
            print UID, GID, filepath
            break
        if os.path.exists(filepath):
            try:
                finfo = os.stat(filepath)
                if UID != finfo.st_uid or GID != finfo.st_gid:
                    os.lchown(filepath, UID, GID)
                    if verbose:
                        print "Fixing ", filepath
            except OSError:
                print "OS Error on file", filepath, "        Are you root?"

    fp.close()


if __name__ == '__main__':
    if len(sys.argv) == 2:
        fix_owners(sys.argv[1], True)
    else:
        print "Usage:", sys.argv[0], "file_manifest"



