/usr/share/pyshared/quodlibet/util/trash.py is in exfalso 3.0.2-3.
This file is owned by root:root, with mode 0o644.
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 | # -*- coding: utf-8 -*-
# Copyright 2011 Christoph Reiter
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation
import os
import stat
import sys
import errno
import urllib
import time
from os.path import join, islink, abspath, dirname
from os.path import isdir, basename, exists, splitext
from quodlibet.util import xdg_get_data_home, find_mount_point
class TrashError(EnvironmentError):
pass
def is_sticky(path):
return bool(os.stat(path).st_mode & stat.S_ISVTX)
def get_fd_trash_dir(path):
"""Returns the right trash directory for the given path."""
path = abspath(path)
mount = find_mount_point(path)
xdg_data_home = xdg_get_data_home()
xdg_mount = find_mount_point(xdg_data_home)
if mount == xdg_mount:
trash_home = join(xdg_data_home, "Trash")
return trash_home
else:
root = join(mount, ".Trash")
uid = str(os.getuid())
if isdir(root) and not islink(root) and is_sticky(root):
root = join(root, uid)
else:
root = join(mount, ".Trash-" + uid)
return root
def trash_free_desktop(path):
"""Partial implementation of
http://www.freedesktop.org/wiki/Specifications/trash-spec
No copy fallback, either it can be moved on the same FS or it failes.
Also doesn't work for files in the trash directory.
"""
path = abspath(path)
if not exists(path):
raise TrashError("Path %s does not exist." % path)
trash_dir = abspath(get_fd_trash_dir(path))
# to make things easier
if path.startswith(join(trash_dir, "")) or path == trash_dir:
raise TrashError("Can't move files to the trash from within the"
"trash directory.")
files = join(trash_dir, "files")
info = join(trash_dir, "info")
for d in (files, info):
if not isdir(d):
os.makedirs(d, 0700)
info_ext = ".trashinfo"
name = basename(path)
flags = os.O_EXCL | os.O_CREAT | os.O_WRONLY
mode = 0644
try:
info_path = join(info, name + info_ext)
info_fd = os.open(info_path, flags, mode)
except OSError, e:
if e.errno != errno.EEXIST:
raise
i = 2
while 1:
head, tail = splitext(name)
temp_name = "%s.%d%s" % (head, i, tail)
info_path = join(info, temp_name + info_ext)
try:
info_fd = os.open(info_path, flags, mode)
except OSError, e:
if e.errno != errno.EEXIST:
raise
i += 1
continue
name = temp_name
break
parent = dirname(trash_dir)
if path.startswith(join(parent, "")):
norm_path = path[len(join(parent, "")):]
else:
norm_path = path
del_date = time.strftime("%Y-%m-%dT%H:%M:%S", time.localtime())
data = "[Trash Info]\n"
data += "Path=%s\n" % urllib.pathname2url(norm_path)
data += "DeletionDate=%s\n" % del_date
os.write(info_fd, data)
os.close(info_fd)
try:
# We only move to the same file system.. so this is ok.
os.rename(path, join(files, name))
except OSError:
# In case something failes, remove the info file and raise again
os.unlink(info_path)
raise
def can_trash():
"""If the current platform supports moving files into a trash can."""
return (os.name == "posix" and sys.platform != "darwin")
def trash(path):
if os.name == "posix" and sys.platform != "darwin":
trash_free_desktop(path)
else:
raise NotImplementedError
|