This file is indexed.

/usr/bin/naturalselection.py is in php-sabre-dav 1.8.12-3.

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
#!/usr/bin/python

#
# Copyright (c) 2009-2010 Evert Pot
# All rights reserved.
# http://www.rooftopsolutions.nl/
#
# This utility is distributed along with SabreDAV
# license: http://code.google.com/p/sabredav/wiki/License Modified BSD License

import os
from optparse import OptionParser
import time

def getfreespace(path):
    stat = os.statvfs(path)
    return stat.f_frsize * stat.f_bavail

def getbytesleft(path,threshold):
    return getfreespace(path)-threshold

def run(cacheDir, threshold, sleep=5, simulate=False, min_erase = 0):

    bytes = getbytesleft(cacheDir,threshold)
    if (bytes>0):
        print "Bytes to go before we hit threshold:", bytes
    else:
        print "Threshold exceeded with:", -bytes, "bytes"
        dir = os.listdir(cacheDir)
        dir2 = []
        for file in dir:
            path = cacheDir + '/' + file
            dir2.append({
                "path" : path,
                "atime": os.stat(path).st_atime,
                "size" : os.stat(path).st_size
            })

        dir2.sort(lambda x,y: int(x["atime"]-y["atime"]))

        filesunlinked = 0
        gainedspace = 0

        # Left is the amount of bytes that need to be freed up
        # The default is the 'min_erase setting'
        left = min_erase

        # If the min_erase setting is lower than the amount of bytes over
        # the threshold, we use that number instead.
        if left < -bytes :
            left = -bytes

        print "Need to delete at least:", left;

        for file in dir2:

            # Only deleting files if we're not simulating
            if not simulate: os.unlink(file["path"])
            left = int(left - file["size"])
            gainedspace = gainedspace + file["size"]
            filesunlinked = filesunlinked + 1

            if(left<0):
                break

        print "%d files deleted (%d bytes)" % (filesunlinked, gainedspace)


    time.sleep(sleep)



def main():
    parser = OptionParser(
        version="naturalselection v0.3",
        description="Cache directory manager. Deletes cache entries based on accesstime and free space thresholds.\n" +
            "This utility is distributed alongside SabreDAV.",
        usage="usage: %prog [options] cacheDirectory",
    )
    parser.add_option(
        '-s',
        dest="simulate",
        action="store_true",
        help="Don't actually make changes, but just simulate the behaviour",
    )
    parser.add_option(
        '-r','--runs',
        help="How many times to check before exiting. -1 is infinite, which is the default",
        type="int",
        dest="runs",
        default=-1
    )
    parser.add_option(
        '-n','--interval',
        help="Sleep time in seconds (default = 5)",
        type="int",
        dest="sleep",
        default=5
    )
    parser.add_option(
        '-l','--threshold',
        help="Threshold in bytes (default = 10737418240, which is 10GB)",
        type="int",
        dest="threshold",
        default=10737418240
    )
    parser.add_option(
        '-m', '--min-erase',
        help="Minimum number of bytes to erase when the threshold is reached. " +
            "Setting this option higher will reduce the amount of times the cache directory will need to be scanned. " +
            "(the default is 1073741824, which is 1GB.)",
        type="int",
        dest="min_erase",
        default=1073741824
    )

    options,args = parser.parse_args()
    if len(args)<1:
        parser.error("This utility requires at least 1 argument")
    cacheDir = args[0]

    print "Natural Selection"
    print "Cache directory:", cacheDir
    free = getfreespace(cacheDir);
    print "Current free disk space:", free

    runs = options.runs;
    while runs!=0 :
        run(
            cacheDir,
            sleep=options.sleep,
            simulate=options.simulate,
            threshold=options.threshold,
            min_erase=options.min_erase
        )
        if runs>0:
            runs = runs - 1

if __name__ == '__main__' :
    main()