Sophie

Sophie

distrib > Fedora > 14 > x86_64 > by-pkgid > df5bdfd6640671b7717a4b9ec9401363 > files > 8

olpc-utils-1.3.7-1.fc14.x86_64.rpm

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# chkconfig: 345 03 03
# description: If the NAND doesn't have enough free space, delete datastore\
#              objects until it does.  This doesn't modify the datastore's\
#              index.
# processname: diskspacerecover

# Author:      Chris Ball <cjb@laptop.org>

import os, os.path, sys, statvfs, subprocess, shutil, fcntl

THRESHOLD = 1024 * 20  # 20MB
DATASTORE_PATH = "/home/olpc/.sugar/default/datastore"
DATASTORE_PATH_0_82 = "/home/olpc/.sugar/default/datastore/store"
ACTIVITY_PATH  = "/home/olpc/Activities"

erase_datastore_index = False

def main():
    global erase_datastore_index

    # First, check to see whether we have enough free space.
    if find_freespace() < THRESHOLD:
        print "Not enough disk space."

        # Per Trac #5637, delete orphaned leaks in .sugar/default/data.
        # This is safe on any build.
        try:
            shutil.rmtree("/home/olpc/.sugar/default/data")
        except OSError:
            pass

        if find_freespace() >= THRESHOLD:
            # The above gained enough free space.
            return

        # Okay, we'll have to delete some real data.
        fileinfo = []
        lines = []

        # Activities and entries from the 0.82 datastore can be deleted
        # straight-up
        lines = os.popen("du -s %s/*" % ACTIVITY_PATH).readlines()
        if os.path.isdir(DATASTORE_PATH_0_82):
            lines += (os.popen("du -s %s/*-*" % DATASTORE_PATH_0_82).readlines())

        for line in lines:
            size, path = line.split('\t')
            fileinfo.append((int(size), path.rstrip(), delete_simple))

        # The sugar-0.84 datastore is a bit more difficult.
        if has_datastore_0_84():
            lines = os.popen("du -s %s/[0-9a-f][0-9a-f]/*" % DATASTORE_PATH).readlines()
            for line in lines:
                size, path = line.split('\t')
                fileinfo.append((int(size), path.rstrip(), delete_ds_0_84))

        fileinfo.sort()

        # The below string is in latin-1, because Unicode isn't present
        # in the environment when this script runs.
        string = u"""
Your disk is nearly full.  The system cannot operate with a full disk.
To create free space, some of the entries in your Journal will now be
deleted.  If you wish to avoid having items deleted, power down your
XO and bring it to an expert for backup and recovery.

Error code:  DISKFULL

Press the return key to delete some Journal entries, or the 'c' key
and then return key to attempt to boot anyway.


Su disco está casi lleno.  El sistema no puede funcionar si el disco
está lleno.  Para liberar espacio, se deben borrar algunas entradas de
su Diario ahora.  Si prefiere no tener que borrar datos, apague su XO y
llévelo a un experto para que haga una copia de seguridad y
recuperación de datos.

Código del error:  DISKFULL

Pulse retorno tecla para borrar algunas entradas del Diario, o presiona
'c' y retorno para iniciar de cualquier manera.
"""

        key = raw_input(string.encode('utf-8'))

        if key is 'c':
           return

        # Now, delete files/directories one at a time.
        while find_freespace() < THRESHOLD and len(fileinfo) > 0:
            size, path, delfunc = fileinfo.pop()
            try:
                print "Deleting " + path
                delfunc(path)
            except Exception, e:
                print "Could not delete %s: %s" % (path, e)

        # If we touched the datastore, delete the index.
        # It will be automatically regenerated by sugar.
        if erase_datastore_index:
            try:
                shutil.rmtree(os.path.join(DATASTORE_PATH, "index"))
            except:
                pass
            try:
                os.remove(os.path.join(DATASTORE_PATH, "index_updated"))
            except:
                pass

def has_datastore_0_84():
    try:
        if not os.path.isfile(os.path.join(DATASTORE_PATH, "version")):
            return False

        fd = open(os.path.join(DATASTORE_PATH, "version"), "r")
        ver = fd.read().strip()
        fd.close()
        if not ver.isdigit():
            return False
        if int(ver) != 1:
            return False
        return True
    except:
        return False

def find_freespace():
    # Determine free space on /.
    stat = os.statvfs("/")
    freebytes  = stat[statvfs.F_BSIZE] * stat[statvfs.F_BAVAIL]
    freekbytes = freebytes / 1024
    return freekbytes

def delete_simple(entry):
    # Delete a single file from the datastore, or an activity directory
    if os.path.isdir(entry):
        shutil.rmtree(entry)
    else:
        os.remove(entry)

def delete_ds_0_84(path):
    # for the datastore in sugar-0.84, we delete both the file itself (and
    # surrounding metadata) and its entry from the checksums index.

    # this may have almost no effect because another entry is pointing at the
    # same file (via a hardlink), but that entry will also be in fileinfo so
    # we'll likely end up deleting all hardlinks to the same file.

    global erase_datastore_index
    erase_datastore_index = True

    entry = os.path.basename(path)
    cspath = os.path.join(path, "metadata", "checksum")

    # read checksum first
    fd = open(cspath, "r")
    checksum = fd.read().strip()
    fd.close()
    if len(checksum) == 0:
        raise Exception("No checksum?")

    # delete the file and metadata
    shutil.rmtree(path)

    # remove checksums entry
    csdir = os.path.join(DATASTORE_PATH, "checksums", checksum)
    os.remove(os.path.join(csdir, entry))
    try:
        os.rmdir(csdir)
    except OSError:
        # ignore directory-not-empty errors; other entries may be pointing
        # at the same file so we'll still have a few entries remaining in
        # the checksum dir.
        pass

main()