This file is indexed.

/usr/bin/lensfun-update-data is in liblensfun-bin 0.3.2-4.

This file is owned by root:root, with mode 0o755.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""This program fetches the latest version of the Lensfun database from the
Internet and places it on the local system.  This way, the user can update the
database conveniently.  Unfortunately, we have to take into account that the
Git database may have a too new format for the locally installed Lensfun.
Then, it may fetch backports of the database from other URLs.

This program must be called with root privileges.  It stores the new database
in `/var/lib/lensfun-updates`.

The repository of databases resides at a base URL.  Below that URL, there is
the file versions.json.  It contains a list with three elements.  The first is
the database timestamp, the second is a list of available version numbers, and
the third is a list of strings which represents further alternative base URLs
to look at.  So, the file may contain the following::

    [1386797501, [1, 2, 3], ["http://wilson.bronger.org/"]]

All URLs must end with a slash.  For every version number, there must be a file
called version_<versionnumber>.tar.bz2.  So in our case, there must be the
files

::

    version_1.tar.bz2
    version_2.tar.bz2
    version_3.tar.bz2

in the same directory as versions.json.  These tar balls contain the Lensfun
database with the given timestamp and version.

The timestamps are the number of seconds since the Epoch as an int.


Diagnostics:

Status code 0 -- successfully installed updates
            1 -- no newer upstream database found for last installed Lensfun
            3 -- no location was responsive; maybe network problems

"""

import urllib.request, shutil, sys, os, time, calendar, tarfile, json, glob
import lensfun


database_version = lensfun.get_database_version()

lensfun_updates_dir = "/var/lib/lensfun-updates"
if os.name == "posix" and os.geteuid() != 0:
    lensfun_updates_dir = os.path.join(os.path.expanduser("~"),
                                       ".local", "share", "lensfun", "updates")
    print("Info: root privileges needed for updating the system database.")
    print("Info: updating user DB in '%s'" % lensfun_updates_dir)


def seconds_since_epoch():
    return calendar.timegm(time.gmtime())


def detect_local_timestamp(version):
    if version == database_version:
        return lensfun.get_core_database()[0]

    def detect_single_timestamp(path):
        try:
            return int(open(os.path.join(path, "version_{}".format(version), "timestamp.txt")).read())
        except (FileNotFoundError, ValueError):
            return 0

    directory_candidates = {"/usr/share/lensfun", "/usr/local/share/lensfun",
                            "/var/lib/lensfun-updates", os.path.expanduser("~/.local/share/lensfun/updates")}
    return max(map(detect_single_timestamp, directory_candidates))


class Location:

    def __init__(self, base_url, version, timestamp):
        self.base_url, self.version, self.timestamp = base_url, version, timestamp

    def __lt__(self, other):
        return self.timestamp < other.timestamp

    def extract(self, directory):
        tar = tarfile.open(fileobj=urllib.request.urlopen(self.base_url + "version_{}.tar.bz2".format(self.version)),
                           mode="r|*")
        tar.extractall(directory)
        tar.close()


def detect_local_database_versions():
    versions = {database_version}
    for directory in glob.glob("/usr/share/lensfun/version_*") + glob.glob("/usr/local/share/lensfun/version_*"):
        if os.path.isdir(directory):
            try:
                versions.add(int(directory.partition("version_")[2]))
            except ValueError:
                pass
    return versions
local_database_versions = detect_local_database_versions()


locations = {version: set() for version in local_database_versions}
local_timestamps = {version: detect_local_timestamp(version) for version in local_database_versions}
seen_urls = set()
at_least_one_responsive_location = False

def read_location(base_url):
    global at_least_one_responsive_location
    if base_url not in seen_urls and len(seen_urls) < 50:
        seen_urls.add(base_url)
        print("Reading {} …".format(base_url + "versions.json"))
        try:
            response = urllib.request.urlopen(base_url + "versions.json")
        except (urllib.error.HTTPError, ValueError):
            print("  Error: URL could not be opened.")
        else:
            try:
                timestamp, versions, alternatives = json.loads(response.read().decode("utf-8"))
            except ValueError:
                print("  Error: Invalid data received.")
            else:
                at_least_one_responsive_location = True
                versions = set(versions) & set(locations)
                for version in versions:
                    if timestamp > local_timestamps[version]:
                        locations[version].add(Location(base_url, version, timestamp))
                for base_url in alternatives:
                    read_location(base_url)

read_location("http://lensfun.sourceforge.net/db/")
read_location("http://wilson.bronger.org/lensfun-db/")

if not at_least_one_responsive_location:
    print("Fatal: No location was responsive.  Network down?")
    sys.exit(3)
elif not locations[database_version]:
    print("Info: No newer database was found for last installed Lensfun.")
    sys.exit(1)


for version, location_list in locations.items():
    try:
        best_location = max(location_list)
    except ValueError:
        continue
    updates_dir = os.path.join(lensfun_updates_dir, "version_{}".format(version))
    shutil.rmtree(updates_dir, ignore_errors=True)
    os.makedirs(updates_dir)
    best_location.extract(updates_dir)
    open(os.path.join(updates_dir, "timestamp.txt"), "w").write(str(best_location.timestamp))
    print("Successfully updated the database in " + updates_dir + ".")