Blame tools/gfind_missing_files/gfid_to_path.py

Packit Service 35f350
#!/usr/bin/python3
Packit Service e080da
Packit Service e080da
# Copyright (c) 2015 Red Hat, Inc. <http://www.redhat.com/>
Packit Service e080da
# This file is part of GlusterFS.
Packit Service e080da
#
Packit Service e080da
# This file is licensed to you under your choice of the GNU Lesser
Packit Service e080da
# General Public License, version 3 or any later version (LGPLv3 or
Packit Service e080da
# later), or the GNU General Public License, version 2 (GPLv2), in all
Packit Service e080da
# cases as published by the Free Software Foundation.
Packit Service e080da
Packit Service e080da
import sys
Packit Service e080da
import os
Packit Service e080da
import xattr
Packit Service e080da
import uuid
Packit Service e080da
import re
Packit Service e080da
import errno
Packit Service e080da
Packit Service e080da
CHANGELOG_SEARCH_MAX_TRY = 31
Packit Service e080da
DEC_CTIME_START = 5
Packit Service e080da
ROOT_GFID = "00000000-0000-0000-0000-000000000001"
Packit Service e080da
MAX_NUM_CHANGELOGS_TRY = 2
Packit Service e080da
Packit Service e080da
Packit Service e080da
def output_not_found(gfid):
Packit Service e080da
    # Write GFID to stderr
Packit Service e080da
    sys.stderr.write("%s\n" % gfid)
Packit Service e080da
Packit Service e080da
Packit Service e080da
def output_success(path):
Packit Service e080da
    # Write converted Path to Stdout
Packit Service e080da
    sys.stdout.write("%s\n" % path)
Packit Service e080da
Packit Service e080da
Packit Service e080da
def full_dir_path(gfid):
Packit Service e080da
    out_path = ""
Packit Service e080da
    while True:
Packit Service e080da
        path = os.path.join(".glusterfs", gfid[0:2], gfid[2:4], gfid)
Packit Service e080da
        path_readlink = os.readlink(path)
Packit Service e080da
        pgfid = os.path.dirname(path_readlink)
Packit Service e080da
        out_path = os.path.join(os.path.basename(path_readlink), out_path)
Packit Service e080da
        if pgfid == "../../00/00/%s" % ROOT_GFID:
Packit Service e080da
            out_path = os.path.join("./", out_path)
Packit Service e080da
            break
Packit Service e080da
        gfid = os.path.basename(pgfid)
Packit Service e080da
    return out_path
Packit Service e080da
Packit Service e080da
Packit Service e080da
def find_path_from_changelog(fd, gfid):
Packit Service e080da
    """
Packit Service e080da
    In given Changelog File, finds using following pattern
Packit Service e080da
    <T><GFID>\x00<TYPE>\x00<MODE>\x00<UID>\x00<GID>\x00<PARGFID>/<BASENAME>
Packit Service e080da
    Pattern search finds PARGFID and BASENAME, Convert PARGFID to Path
Packit Service e080da
    Using readlink and add basename to form Full path.
Packit Service e080da
    """
Packit Service e080da
    content = fd.read()
Packit Service e080da
Packit Service e080da
    pattern = "E%s" % gfid
Packit Service e080da
    pattern += "\x00(3|23)\x00\d+\x00\d+\x00\d+\x00([^\x00]+)/([^\x00]+)"
Packit Service e080da
    pat = re.compile(pattern)
Packit Service e080da
    match = pat.search(content)
Packit Service e080da
Packit Service e080da
    if match:
Packit Service e080da
        pgfid = match.group(2)
Packit Service e080da
        basename = match.group(3)
Packit Service e080da
        if pgfid == ROOT_GFID:
Packit Service e080da
            return os.path.join("./", basename)
Packit Service e080da
        else:
Packit Service e080da
            full_path_parent = full_dir_path(pgfid)
Packit Service e080da
            if full_path_parent:
Packit Service e080da
                return os.path.join(full_path_parent, basename)
Packit Service e080da
Packit Service e080da
    return None
Packit Service e080da
Packit Service e080da
Packit Service e080da
def gfid_to_path(gfid):
Packit Service e080da
    """
Packit Service e080da
    Try readlink, if it is directory it succeeds.
Packit Service e080da
    Get ctime of the GFID file, Decrement by 5 sec
Packit Service e080da
    Search for Changelog filename, Since Changelog file generated
Packit Service e080da
    every 15 sec, Search and get immediate next Changelog after the file
Packit Service e080da
    Creation. Get the Path by searching in Changelog file.
Packit Service e080da
    Get the resultant file's GFID and Compare with the input, If these
Packit Service e080da
    GFIDs are different then Some thing is changed(May be Rename)
Packit Service e080da
    """
Packit Service e080da
    gfid = gfid.strip()
Packit Service e080da
    gpath = os.path.join(".glusterfs", gfid[0:2], gfid[2:4], gfid)
Packit Service e080da
    try:
Packit Service e080da
        output_success(full_dir_path(gfid))
Packit Service e080da
        return
Packit Service e080da
    except OSError:
Packit Service e080da
        # Not an SymLink
Packit Service e080da
        pass
Packit Service e080da
Packit Service e080da
    try:
Packit Service e080da
        ctime = int(os.stat(gpath).st_ctime)
Packit Service e080da
        ctime -= DEC_CTIME_START
Packit Service e080da
    except (OSError, IOError):
Packit Service e080da
        output_not_found(gfid)
Packit Service e080da
        return
Packit Service e080da
Packit Service e080da
    path = None
Packit Service e080da
    found_changelog = False
Packit Service e080da
    changelog_parse_try = 0
Packit Service e080da
    for i in range(CHANGELOG_SEARCH_MAX_TRY):
Packit Service e080da
        cl = os.path.join(".glusterfs/changelogs", "CHANGELOG.%s" % ctime)
Packit Service e080da
Packit Service e080da
        try:
Packit Service e080da
            with open(cl, "rb") as f:
Packit Service e080da
                changelog_parse_try += 1
Packit Service e080da
                found_changelog = True
Packit Service e080da
                path = find_path_from_changelog(f, gfid)
Packit Service e080da
                if not path and changelog_parse_try < MAX_NUM_CHANGELOGS_TRY:
Packit Service e080da
                    ctime += 1
Packit Service e080da
                    continue
Packit Service e080da
            break
Packit Service e080da
        except (IOError, OSError) as e:
Packit Service e080da
            if e.errno == errno.ENOENT:
Packit Service e080da
                ctime += 1
Packit Service e080da
            else:
Packit Service e080da
                break
Packit Service e080da
Packit Service e080da
    if not found_changelog:
Packit Service e080da
        output_not_found(gfid)
Packit Service e080da
        return
Packit Service e080da
Packit Service e080da
    if not path:
Packit Service e080da
        output_not_found(gfid)
Packit Service e080da
        return
Packit Service e080da
    gfid1 = str(uuid.UUID(bytes=xattr.get(path, "trusted.gfid")))
Packit Service e080da
    if gfid != gfid1:
Packit Service e080da
        output_not_found(gfid)
Packit Service e080da
        return
Packit Service e080da
Packit Service e080da
    output_success(path)
Packit Service e080da
Packit Service e080da
Packit Service e080da
def main():
Packit Service e080da
    num_arguments = 3
Packit Service e080da
    if not sys.stdin.isatty():
Packit Service e080da
        num_arguments = 2
Packit Service e080da
Packit Service e080da
    if len(sys.argv) != num_arguments:
Packit Service e080da
        sys.stderr.write("Invalid arguments\nUsage: "
Packit Service e080da
                         "%s <BRICK_PATH> <GFID_FILE>\n" % sys.argv[0])
Packit Service e080da
        sys.exit(1)
Packit Service e080da
Packit Service e080da
    path = sys.argv[1]
Packit Service e080da
Packit Service e080da
    if sys.stdin.isatty():
Packit Service e080da
        gfid_list = os.path.abspath(sys.argv[2])
Packit Service e080da
        os.chdir(path)
Packit Service e080da
        with open(gfid_list) as f:
Packit Service e080da
            for gfid in f:
Packit Service e080da
                gfid_to_path(gfid)
Packit Service e080da
    else:
Packit Service e080da
        os.chdir(path)
Packit Service e080da
        for gfid in sys.stdin:
Packit Service e080da
            gfid_to_path(gfid)
Packit Service e080da
Packit Service e080da
Packit Service e080da
if __name__ == "__main__":
Packit Service e080da
    main()