def scan_vo_dir(vodir):
    ' Scan a VO directory (assumed to be the whole directory tree after the top level '
    now = time.time()
    totalsize = 0
    nfiles = 0
    naccesses = 0
    accesses = collections.defaultdict(int)
    most_recent_access = 0
    bad_cinfo_files = 0
    for (root, dirs, files) in os.walk(vodir):
        fnames = set(files)
        for (f, cinfo) in ((f, (f + '.cinfo')) for f in fnames if ((f + '.cinfo') in fnames)):
            try:
                st = os.stat(os.path.join(root, f))
            except OSError as ex:
                if (ex.errno == errno.ENOENT):
                    continue
                else:
                    raise
            try:
                access_info = read_cinfo(os.path.join(root, cinfo), now)
            except OSError as ex:
                if (ex.errno == errno.ENOENT):
                    continue
                else:
                    bad_cinfo_files += 1
                    access_info = {'naccesses': 0, 'last_access': 0, 'by_hour': {}}
            except ReadCInfoError as ex:
                bad_cinfo_files += 1
                access_info = ex.access_info
            nfiles += 1
            file_size = (st.st_blocks * 512)
            totalsize += file_size
            naccesses += access_info['naccesses']
            most_recent_access = max(most_recent_access, access_info['last_access'])
            for h in access_info['by_hour']:
                accesses[('naccesses_hr_' + h)] += access_info['by_hour'][h]
                accesses[('bytes_hr_' + h)] += access_info['bytes_hr'][h]
    result = classad.ClassAd({'used_bytes': totalsize, 'nfiles': nfiles, 'naccesses': naccesses, 'bad_cinfo_files': bad_cinfo_files})
    result.update(accesses)
    if (most_recent_access > 0):
        result['most_recent_access_time'] = most_recent_access
    return result
Scan a VO directory (assumed to be the whole directory tree after the top level
def scan_vo_dir(vodir):
    '  '
    now = time.time()
    totalsize = 0
    nfiles = 0
    naccesses = 0
    accesses = collections.defaultdict(int)
    most_recent_access = 0
    bad_cinfo_files = 0
    for (root, dirs, files) in os.walk(vodir):
        fnames = set(files)
        for (f, cinfo) in ((f, (f + '.cinfo')) for f in fnames if ((f + '.cinfo') in fnames)):
            try:
                st = os.stat(os.path.join(root, f))
            except OSError as ex:
                if (ex.errno == errno.ENOENT):
                    continue
                else:
                    raise
            try:
                access_info = read_cinfo(os.path.join(root, cinfo), now)
            except OSError as ex:
                if (ex.errno == errno.ENOENT):
                    continue
                else:
                    bad_cinfo_files += 1
                    access_info = {'naccesses': 0, 'last_access': 0, 'by_hour': {}}
            except ReadCInfoError as ex:
                bad_cinfo_files += 1
                access_info = ex.access_info
            nfiles += 1
            file_size = (st.st_blocks * 512)
            totalsize += file_size
            naccesses += access_info['naccesses']
            most_recent_access = max(most_recent_access, access_info['last_access'])
            for h in access_info['by_hour']:
                accesses[('naccesses_hr_' + h)] += access_info['by_hour'][h]
                accesses[('bytes_hr_' + h)] += access_info['bytes_hr'][h]
    result = classad.ClassAd({'used_bytes': totalsize, 'nfiles': nfiles, 'naccesses': naccesses, 'bad_cinfo_files': bad_cinfo_files})
    result.update(accesses)
    if (most_recent_access > 0):
        result['most_recent_access_time'] = most_recent_access
    return result