Initial support for deletion schedule
[pysize.git] / pysize / core / compute_size.py
blobc44d94691c745d4ad68f7361295616c9ae028ad5
1 # This program is free software; you can redistribute it and/or modify
2 # it under the terms of the GNU General Public License as published by
3 # the Free Software Foundation; either version 2 of the License, or
4 # (at your option) any later version.
6 # This program is distributed in the hope that it will be useful,
7 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 # GNU Library General Public License for more details.
11 # You should have received a copy of the GNU General Public License
12 # along with this program; if not, write to the Free Software
13 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 # See the COPYING file for license information.
17 # Copyright (c) 2006 Guillaume Chazarain <guichaz@yahoo.fr>
19 import os
20 import stat
22 from pysize.core import chdir_browsing
23 from pysize.core.observable import observable
24 from pysize.core.pysize_global_fs_cache import get_dev_ino, cache_add_dir
25 from pysize.core.pysize_global_fs_cache import cache_add_hardlink
26 from pysize.core.pysize_global_fs_cache import cache_get_dir_size
27 from pysize.core.deletion import get_subtracted
29 size_observable = observable()
31 def log_error(text, e):
32 print text, e
34 def _fast(path, dir_ino, cross_device, error_cb):
35 """Return the size of the file or directory at path, using or updating the
36 cache. dir_ino is the inode of the directory containing the path, it is
37 used only with hardlinks.
38 """
39 try:
40 size_observable.fire_observers()
41 st = os.lstat(path)
42 if stat.S_ISDIR(st.st_mode): # Directory
43 dev_ino = st.st_dev, st.st_ino
44 cached_size = cache_get_dir_size(dev_ino)
45 if cached_size is None:
46 size = st.st_blocks * 512
47 dir_ino = st.st_ino
48 cookie = chdir_browsing.init(path)
49 try:
50 for child in chdir_browsing.browsedir(cookie, cross_device):
51 size += _fast(child, dir_ino, cross_device, error_cb)
52 finally:
53 chdir_browsing.finalize(cookie)
54 cache_add_dir(dev_ino, size)
55 else:
56 size = cached_size
57 elif st.st_nlink > 1: # Hardlink
58 if cache_add_hardlink(st.st_dev, st.st_ino, dir_ino, path):
59 size = st.st_blocks * 512
60 else:
61 size = 0
62 else: # File
63 size = st.st_blocks * 512
64 return size
65 except OSError, e:
66 error_cb('size.fast(%s)' % (path), e)
67 return 0
69 def slow(path, cross_device=True, error_cb=log_error):
70 """Same as _size_fast(path, dir_ino), except that dir_ino is computed."""
71 def parent_inode():
72 """Return the inode of the parent directory"""
73 path_st = os.lstat(path)
74 if stat.S_ISDIR(path_st.st_mode):
75 parent_path = path + '/..'
76 else:
77 parent_path = os.path.dirname(path) or '.'
78 return get_dev_ino(parent_path)[1]
79 try:
80 parent_ino = parent_inode()
81 except OSError, e:
82 error_cb('size.slow(%s)' % (path), e)
83 return 0
84 size = _fast(path, parent_ino, cross_device, error_cb)
85 size -= get_subtracted(get_dev_ino(path))
86 return size
88 def slow_sum(paths, cross_device=True, error_cb=log_error):
89 res = 0
90 for p in paths:
91 res += slow(p, cross_device, error_cb)
92 return res