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>
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
28 size_observable
= observable()
30 def log_error(text
, e
):
33 def _fast(path
, dir_ino
, cross_device
, error_cb
):
34 """Return the size of the file or directory at path, using or updating the
35 cache. dir_ino is the inode of the directory containing the path, it is
36 used only with hardlinks.
39 size_observable
.fire_observers()
41 if stat
.S_ISDIR(st
.st_mode
): # Directory
42 dev_ino
= st
.st_dev
, st
.st_ino
43 cached_size
= cache_get_dir_size(dev_ino
)
44 if cached_size
is None:
45 size
= st
.st_blocks
* 512
47 cookie
= chdir_browsing
.init(path
)
49 for child
in chdir_browsing
.browsedir(cookie
, cross_device
):
50 size
+= _fast(child
, dir_ino
, cross_device
, error_cb
)
52 chdir_browsing
.finalize(cookie
)
53 cache_add_dir(dev_ino
, size
)
56 elif st
.st_nlink
> 1: # Hardlink
57 if cache_add_hardlink(st
.st_dev
, st
.st_ino
, dir_ino
, path
):
58 size
= st
.st_blocks
* 512
62 size
= st
.st_blocks
* 512
65 error_cb('size.fast(%s)' % (path
), e
)
68 def slow(path
, cross_device
=True, error_cb
=log_error
):
69 """Same as _size_fast(path, dir_ino), except that dir_ino is computed."""
71 """Return the inode of the parent directory"""
72 path_st
= os
.lstat(path
)
73 if stat
.S_ISDIR(path_st
.st_mode
):
74 parent_path
= path
+ '/..'
76 parent_path
= os
.path
.dirname(path
) or '.'
77 return get_dev_ino(parent_path
)[1]
79 parent_ino
= parent_inode()
81 error_cb('size.slow(%s)' % (path
), e
)
83 return _fast(path
, parent_ino
, cross_device
, error_cb
)
85 def slow_sum(paths
, cross_device
=True, error_cb
=log_error
):
88 res
+= slow(p
, cross_device
, error_cb
)