commit qdirstat for openSUSE:Factory
Hello community, here is the log from the commit of package qdirstat for openSUSE:Factory checked in at 2017-01-17 14:36:54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/qdirstat (Old) and /work/SRC/openSUSE:Factory/.qdirstat.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Package is "qdirstat" Changes: -------- --- /work/SRC/openSUSE:Factory/qdirstat/qdirstat.changes 2016-11-28 15:04:41.000000000 +0100 +++ /work/SRC/openSUSE:Factory/.qdirstat.new/qdirstat.changes 2017-01-17 14:36:55.356684362 +0100 @@ -1,0 +2,5 @@ +Mon Jan 9 13:49:25 CET 2017 - shundhammer@suse.de + +- Update to V1.2 (Improved Btrfs subvolume support) + +------------------------------------------------------------------- Old: ---- qdirstat-1.1.tar.bz2 New: ---- qdirstat-1.2.tar.bz2 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ qdirstat.spec ++++++ --- /var/tmp/diff_new_pack.muDQEw/_old 2017-01-17 14:36:55.744629366 +0100 +++ /var/tmp/diff_new_pack.muDQEw/_new 2017-01-17 14:36:55.744629366 +0100 @@ -1,7 +1,7 @@ # # spec file for package qdirstat # -# Copyright (c) 2016 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2016-2017 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -17,7 +17,7 @@ Name: qdirstat -Version: 1.1 +Version: 1.2 Release: 0 Summary: Directory Statistics License: GPL-2.0 ++++++ qdirstat-1.1.tar.bz2 -> qdirstat-1.2.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qdirstat-1.1/.gitignore new/qdirstat-1.2/.gitignore --- old/qdirstat-1.1/.gitignore 2016-10-31 19:09:45.000000000 +0100 +++ new/qdirstat-1.2/.gitignore 2017-01-03 14:47:15.000000000 +0100 @@ -1 +1,2 @@ Makefile +.qmake.stash diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qdirstat-1.1/DevHistory.md new/qdirstat-1.2/DevHistory.md --- old/qdirstat-1.1/DevHistory.md 2016-10-31 19:09:45.000000000 +0100 +++ new/qdirstat-1.2/DevHistory.md 2017-01-03 14:47:15.000000000 +0100 @@ -11,6 +11,181 @@ ## QDirStat History +- 2016-12-06 **Warning to Btrfs users** (Fixed as of 2012-12-09) + + If you use QDirStat to scan a Btrfs partition, + [any subvolumes of that partition are not scanned](https://github.com/shundhammer/qdirstat/issues/39): + Btrfs subvolumes are treated just like ordinary + mount points (which, to all intents and purposes, they are). So you might + wonder why the _df_ command shows your 40 GB root filesystem as 97% full, yet + QDirStat shows only about 7 GB. The rest might be hidden in subvolumes. + + QDirStat stops reading at mount points - which only makes sense because + normally you want to know what eats up the disk space on that one partition + that is filling up, not on any others like /home that are mounted + there. Unfortunately, a Btrfs subvolume is also just another mount point, and + QDirStat will stop reading there, too - at /var/log, at /var/spool, at + /var/lib/libvirt etc.; a typical Btrfs root filesystem has about a dozen + subvolumes, and all files in them are currently disregarded by QDirStat. You + can of course click on "Continue reading at mount point" individually in + QDirStat's directory tree for each one of them, but that's tedious. + + I am working on a solution. One approach would be to check if the current + filesystem is Btrfs and list its subvolumes, but the Btrfs developers in + their infinite wisdom decided that `btrfs subvolume list <path>` is a + privileged operation, so QDirStat would have to use `sudo` with it and prompt + for the root password (at which point I as a user would terminate the program + and not use it any more). **This is broken by design.** A simple info command + like that should not require root privileges. + + +- 2016-10-31 (Halloween) **New stable release: V1.1-Pumpkin** + + It's about time for another official release to get the accumulated fixes and + small changes out into the world. Since today is Halloween, this release + shall be named _Pumpkin_ (as in the unforgettable Charlie Brown's _Great + Pumpkin_). + + The last stable release, V1.0, was in mid-May (2016-05-16). Since then, there + were 5 bug fixes and one small feature (the config file split up into + independent parts so admins can provide presets to their users without + overwriting the complete configuration), all described in greater detail + below. + + +- 2016-10-23 + + - Fixed [GitHub issue #32](https://github.com/shundhammer/qdirstat/issues/32): + %p does not escape single quotes properly + + If you have a file name like `Don't do this.txt` (with a quote character in + the name), the shell used when executing a cleanup action with this would + complain about unmatched single quotes. + + QDirStat had always escaped such single quotes, but not the way common + shells (Bash, Zsh) expect it: They don't want a backslash in front of that + embedded single quote. Rather, you need to terminate the string with a + single quote, escape the embedded quote with a backslash (or put it into + double quotes), and then re-open the old string with another single quote. + + Thus, `'Don't do this'` becomes `'Don'\''t do this'`. + + This is certainly not what most people expect. I just wonder how much other + software is out there that does it the intuitive (yet wrong) way: Just + escape the single quote with a backslash (`'Don\'t do this'`). + + Of course, such file names should be avoided entirely, but you can't help + some slightly broken MP3 ripper program doing it, so it needs to be handled + correctly. + + - Fixed [GitHub issue #31](https://github.com/shundhammer/qdirstat/issues/31): + Segfault with cleanup action while reading directories + + Now disabling cleanups that have a refresh policy other than "No Refresh" + while directory reading is in progress; otherwise the re-read when the + cleanup action has finished clashes with the directory read already in + progress. + + This is not an optimal solution, but a very pragmatic one; the optimal + solution might queue updates and execute them after the main read is done. + + - Fixed [GitHub issue #33](https://github.com/shundhammer/qdirstat/issues/33): + Added command line option `--slow-update` (or `-s`) for slow remote X connections. + + +- 2016-08-12 + + - Fixed [GitHub issue #23](https://github.com/shundhammer/qdirstat/issues/23): + + The internal cache writer would sometimes generate incorrect cache files + because of buggy URL escaping resulting in an empty file name and thus + invalid cache file syntax. This affected file names with colons (which is + weird, but legal). + + One of these days I'm going to throw out all that QUrl stuff and replace the + few things that I need with something that actually works consistently and + not just under optimum conditions. + + +- 2016-08-10 + + - Fixed [GitHub issue #22](https://github.com/shundhammer/qdirstat/issues/22): + + Cache files containing the root file system would not display correctly or + segfault under certain conditions. This is now fixed. + + - Added "Refresh All" action to the main window tool bar. I had consciously + avoided that because it's just too tempting to re-read the complete + directory tree rather than think about what actually might have changed and + then refresh just that, but it has become so common to use that action in + web browsers that I found myself missing that more and more. And re-reading + is not that expensive on today's mainstream PCs. + + +- 2016-07-02 + + - Fixed [GitHub issue #21](https://github.com/shundhammer/qdirstat/issues/21): + + When started from a desktop menu, i.e. without any command line parameters, + QDirStat would not prompt for a directory to read, but read the current + directory (typically the user's home directory) right away. + + - More graceful handling for nonexisting paths specified on the commmand + line: It now no longer just throws an exception right after starting the + program (which looks like a crash to the unwary user), but posts an error + popup instead and then asks for a directory to read. + + +- 2016-06-29 + + - V1.01 (Development version) + + - Split up config file into four separate ones below ~/.config/QDirStat: + + - QDirStat.conf + - QDirStat-cleanup.conf + - QDirStat-exclude.conf + - QDirStat-mime.conf + + This should make it much easier for site administrators to provide their + own site-wide cleanup actions, exclude rules, or MIME categories. I did + this with this in mind: + + http://moo.nac.uci.edu/~hjm/kdirstat/kdirstat-for-clusters.html + + Here, they describe how users should overwrite their KDirStat config file + with one provided by the site admin so all users have those carefully + crafted cleanup actions. But that also means that all other settings get + lost each time there is a change in any of those commands, and users have + to update that config file again. + + With the latest change, it is now possible to only replace the cleanup + action config (QDirStat-cleanup.conf) and leave everything else untouched. + + Notice that this is far from a perfect solution; all cleanup actions the + user added himself still get lost. But doing this perfectly might pretty + quickly become an overengineered solution that would be hard to understand + for everybody. + + As for migration from previous single-file configurations, QDirStat does + that automatically: It reads the single file and moves the respective parts + where they belong. No need to bother with any migration scrips or anything + like that. + + +- 2016-05-16 **First stable release: V1.0** + + After 3 months of Beta phase and 3 Beta releases, here is finally the + official first stable release of QDirStat: Version 1.0. + + In terms of source code, there were very little changes from the last Beta + (0.98-Beta3 from 2016-04-08) and no real code change (only the version number + increased) from the last check-in from 2016-04-11. This version can really be + considered stable in the truest sense of the word. It was not rushed out the + door, and there were no hectic last minute changes. It is well tested, and + the community had ample opportunity to report any problems. + + - 2016-04-11 - _buxit_ reported diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qdirstat-1.1/README.md new/qdirstat-1.2/README.md --- old/qdirstat-1.1/README.md 2016-10-31 19:09:45.000000000 +0100 +++ new/qdirstat-1.2/README.md 2017-01-03 14:47:15.000000000 +0100 @@ -9,7 +9,7 @@ License: GPL V2 -Updated: 2016-10-31 +Updated: 2017-01-03 ## Overview @@ -76,152 +76,93 @@ ## Current Development Status -**Latest stable release: V1.1** +**Latest stable release: V1.2** -- 2016-10-31 (Halloween) **New stable release: V1.1-Pumpkin** +- 2017-01-03 **New stable release: V1.2** - It's about time for another official release to get the accumulated fixes and - small changes out into the world. Since today is Halloween, this release - shall be named _Pumpkin_ (as in the unforgettable Charlie Brown's _Great - Pumpkin_). + _Upgrading to this release is highly recommended for Btrfs users:_ - The last stable release, V1.0, was in mid-May (2016-05-16). Since then, there - were 5 bug fixes and one small feature (the config file split up into - independent parts so admins can provide presets to their users without - overwriting the complete configuration), all described in greater detail - below. + If you used QDirStat to scan a Btrfs partition, any subvolumes of that + partition were not scanned (see + [GitHub issue #39](https://github.com/shundhammer/qdirstat/issues/39)). -- 2016-10-23 + Btrfs subvolumes were treated just like ordinary mount points (which, to all + intents and purposes, they are). So you might have wondered why the _df_ + command shows your 40 GB root filesystem as 97% full, yet QDirStat shows only + about 7 GB. The rest might be hidden in subvolumes. - - Fixed [GitHub issue #32](https://github.com/shundhammer/qdirstat/issues/32): - %p does not escape single quotes properly + QDirStat stops reading at mount points - which only makes sense because + normally you want to know what eats up the disk space on that one partition + that is filling up, not on any others like /home that are mounted + there. Unfortunately, a Btrfs subvolume is also just another mount point, and + QDirStat would stop reading there, too - at /var/log, at /var/spool, at + /var/lib/libvirt etc.; a typical Btrfs root filesystem has about a dozen + subvolumes, and all files in them were disregarded by QDirStat. - If you have a file name like `Don't do this.txt` (with a quote character in - the name), the shell used when executing a cleanup action with this would - complain about unmatched single quotes. + This is now fixed: Despite Btrfs doing its best to make this difficult (using + one single privileged system call for all its functionality, including simple + info calls), QDirStat now detects if a mount point is a Btrfs subvolume and + continues reading if it is. QDirStat uses /proc/mounts (or, if this is not + available, /etc/mtab) to find this out. - QDirStat had always escaped such single quotes, but not the way common - shells (Bash, Zsh) expect it: They don't want a backslash in front of that - embedded single quote. Rather, you need to terminate the string with a - single quote, escape the embedded quote with a backslash (or put it into - double quotes), and then re-open the old string with another single quote. + This is fixed in the _qdirstat-cache-writer_ script, too. - Thus, `'Don't do this'` becomes `'Don'\''t do this'`. - This is certainly not what most people expect. I just wonder how much other - software is out there that does it the intuitive (yet wrong) way: Just - escape the single quote with a backslash (`'Don\'t do this'`). +- 2016-12-11 Bernhard Walle contributed some patches for MacOS X support. + Thanks, Bernhard! - Of course, such file names should be avoided entirely, but you can't help - some slightly broken MP3 ripper program doing it, so it needs to be handled - correctly. +- 2016-12-09 Fixed Perl (_qdirstat-cache-writer_) part of + [GitHub issue #39](https://github.com/shundhammer/qdirstat/issues/39): + QDirStat doesn't scan Btrfs subvolumes - - Fixed [GitHub issue #31](https://github.com/shundhammer/qdirstat/issues/31): - Segfault with cleanup action while reading directories + The _qdirstat-cache-writer_ script now also checks the device names of a + mount point and its parent directory, not only their major/minor device + numbers; so now it will not stop at Btrfs subvolumes while scanning. - Now disabling cleanups that have a refresh policy other than "No Refresh" - while directory reading is in progress; otherwise the re-read when the - cleanup action has finished clashes with the directory read already in - progress. + That script uses a more simplistic approach than QDirStat itself: It invokes + the _df_ command with that path and parses its output. If the path contains + very weird special characters, this may fail, in which case that directory + (which at that point is already known to have a different device major/minor + number than its parent) is considered a filesystem boundary, and that branch + is not scanned. - This is not an optimal solution, but a very pragmatic one; the optimal - solution might queue updates and execute them after the main read is done. - - Fixed [GitHub issue #33](https://github.com/shundhammer/qdirstat/issues/33): - Added command line option `--slow-update` (or `-s`) for slow remote X connections. +- 2016-12-08 Fixed C++ (QDirStat binary) part of + [GitHub issue #39](https://github.com/shundhammer/qdirstat/issues/39): + QDirStat doesn't scan Btrfs subvolumes + This was a bit of a challenge since the relevant Btrfs commands to obtain any + useful information about subvolumes all require root privileges, and I really + wouldn't want to scare users off by prompting for a _sudo_ password. QDirStat + now fetches the information from /proc/mounts (or /etc/mtab if /proc/mounts + is unavailable) and does some heuristics (which are not completely fool + proof) to check if a potential mount point is still on the same device. That + means that it will no longer treat a Btrfs subvolume as an ordinary mount + point where it stops reading by default, but it just continues. On the other + hand, another Btrfs mounted into the current file system is of course treated + as a normal mount point. See also the corresponding + [GitHub issue](https://github.com/shundhammer/qdirstat/issues/39) + for details. -- 2016-08-12 + The Perl _qdirstat-cache-writer_ still has the old behaviour, i.e. it still + stops at a subvolume mount point. This will be addressed next. - - Fixed [GitHub issue #23](https://github.com/shundhammer/qdirstat/issues/23): - The internal cache writer would sometimes generate incorrect cache files - because of buggy URL escaping resulting in an empty file name and thus - invalid cache file syntax. This affected file names with colons (which is - weird, but legal). +- 2016-12-07 Fixed [GitHub issue #40](https://github.com/shundhammer/qdirstat/issues/40): + Crash without useful error message when no display available - One of these days I'm going to throw out all that QUrl stuff and replace the - few things that I need with something that actually works consistently and - not just under optimum conditions. + When ssh'ing without -X to a remote machine and starting QDirStat there, it + would just dump core and not issue any meaningful message. The fatal error + message was only in the log file: + `<ERROR> :0 (): QXcbConnection: Could not connect to display` -- 2016-08-10 + Now this message is also repeated on stderr, and in this particular case + ("Could not connect to display"), it does not dump core any more, but just + exits with error code 1. - - Fixed [GitHub issue #22](https://github.com/shundhammer/qdirstat/issues/22): - Cache files containing the root file system would not display correctly or - segfault under certain conditions. This is now fixed. - - - Added "Refresh All" action to the main window tool bar. I had consciously - avoided that because it's just too tempting to re-read the complete - directory tree rather than think about what actually might have changed and - then refresh just that, but it has become so common to use that action in - web browsers that I found myself missing that more and more. And re-reading - is not that expensive on today's mainstream PCs. - - -- 2016-07-02 - - - Fixed [GitHub issue #21](https://github.com/shundhammer/qdirstat/issues/21): - - When started from a desktop menu, i.e. without any command line parameters, - QDirStat would not prompt for a directory to read, but read the current - directory (typically the user's home directory) right away. - - - More graceful handling for nonexisting paths specified on the commmand - line: It now no longer just throws an exception right after starting the - program (which looks like a crash to the unwary user), but posts an error - popup instead and then asks for a directory to read. - - -- 2016-06-29 - - - V1.01 (Development version) - - - Split up config file into four separate ones below ~/.config/QDirStat: - - - QDirStat.conf - - QDirStat-cleanup.conf - - QDirStat-exclude.conf - - QDirStat-mime.conf - - This should make it much easier for site administrators to provide their - own site-wide cleanup actions, exclude rules, or MIME categories. I did - this with this in mind: - - http://moo.nac.uci.edu/~hjm/kdirstat/kdirstat-for-clusters.html - - Here, they describe how users should overwrite their KDirStat config file - with one provided by the site admin so all users have those carefully - crafted cleanup actions. But that also means that all other settings get - lost each time there is a change in any of those commands, and users have - to update that config file again. - - With the latest change, it is now possible to only replace the cleanup - action config (QDirStat-cleanup.conf) and leave everything else untouched. - - Notice that this is far from a perfect solution; all cleanup actions the - user added himself still get lost. But doing this perfectly might pretty - quickly become an overengineered solution that would be hard to understand - for everybody. - - As for migration from previous single-file configurations, QDirStat does - that automatically: It reads the single file and moves the respective parts - where they belong. No need to bother with any migration scrips or anything - like that. - - -- 2016-05-16 **First stable release: V1.0** - - After 3 months of Beta phase and 3 Beta releases, here is finally the - official first stable release of QDirStat: Version 1.0. - - In terms of source code, there were very little changes from the last Beta - (0.98-Beta3 from 2016-04-08) and no real code change (only the version number - increased) from the last check-in from 2016-04-11. This version can really be - considered stable in the truest sense of the word. It was not rushed out the - door, and there were no hectic last minute changes. It is well tested, and - the community had ample opportunity to report any problems. +- 2016-10-31 (Halloween) New stable release: V1.1-Pumpkin _See file DevHistory.md for older entries:_ @@ -389,6 +330,13 @@ - Configuration dialog for exclude rules -- see screenshots. +- Subvolume detection for Btrfs. Btrfs subvolumes are just ordinary mount + points, so normally QDirStat would stop scanning there, leaving a large part + of a Btrfs partition unaccounted for. But for each mount point found while + scanning a directory tree, QDirStat checks /proc/mounts or /etc/mtab if it + has the same device name as its parent directory, and if yes, considers it a + subvolume and continues scanning. + - Actions to go one directory level higher or to the toplevel: Context menu and menu "Go To" -> "Up One Level" or "Toplevel". This is useful if you clicked on a file in the treemap that is deep down in some subdirectory, and you want @@ -574,10 +522,11 @@ (Compared with the old KDirStat) -- KPacman: That was that PacMan animation wile reading directory reading. This is - gone now. KPacMan looked out of place pretty soon after it got to KDirStat. I - know that it does have its fans, but unless a graphics designer joins the - project who can do that right, this will not come back. +- KPacman: That was that PacMan animation wile reading directory reading. This + is gone now. KPacMan looked out of place pretty soon after it got to KDirStat + due to Qt styles doing fancy rendering of widget backgrounds with gradients + etc. I know that it does have its fans, but it's unrealistic to get this + back without breaking the menu bar rendering. - KioDirReadJob: Network-transparent directory reading for network protocols like FTP, HTTP, Fish (ssh-based). This depended on KDE's KIO slaves, so this @@ -664,12 +613,13 @@ QDirStat packages for: - openSUSE Tumbleweed +- openSUSE Leap 42.2 - openSUSE Leap 42.1 - openSUSE 13.2 - SUSE Linux Enterprise (SLE) 12 SP1 - SUSE Linux Enterprise (SLE) 12 -Download page for the [**latest stable release**: QDirStat 1.0] +Download page for the [**latest stable release**: QDirStat 1.1] (https://software.opensuse.org/download/package?project=home:shundhammer:qdir...) Download page for the [**current development version** (git master)] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qdirstat-1.1/scripts/qdirstat-cache-writer new/qdirstat-1.2/scripts/qdirstat-cache-writer --- old/qdirstat-1.1/scripts/qdirstat-cache-writer 2016-10-31 19:09:45.000000000 +0100 +++ new/qdirstat-1.2/scripts/qdirstat-cache-writer 2017-01-03 14:47:15.000000000 +0100 @@ -68,7 +68,8 @@ my $default_cache_file_name = ".qdirstat.cache.gz"; -my $toplevel_device = undef; +my $toplevel_dev_no = undef; +my $toplevel_dev_name = undef; my $unsafe_chars = "\x00-\x20%"; @@ -297,7 +298,7 @@ return; } - my ( $dev, + my ( $dev_no, $ino, $mode, $links, @@ -312,28 +313,71 @@ $blocks ) = @lstat_result; - if ( ! defined( $toplevel_device ) ) + $dir =~ s://+:/:g; # Replace multiple // with one + my $escaped_dir = uri_escape( $dir, $unsafe_chars ); + + # Write cache file entry for this directory (even if it's a mount point) + + print CACHE "D $escaped_dir"; + print CACHE "\t$size"; + printf CACHE "\t0x%x\n", $mtime; + + if ( ! defined( $toplevel_dev_no ) ) { - $toplevel_device = $dev; + $toplevel_dev_no = $dev_no; + $toplevel_dev_name = device_name( $dir ); + print CACHE "# Device: $toplevel_dev_name\n\n"; } - if ( $dev == $toplevel_device || $scan_mounted ) + if ( $dev_no == $toplevel_dev_no || $scan_mounted ) { - $dir = uri_escape( $dir, $unsafe_chars ); - $dir =~ s://+:/:g; # Replace multiple // with one + return 1; + } - print CACHE "D $dir"; - print CACHE "\t$size"; - printf CACHE "\t0x%x\n", $mtime; + my $dev_name = device_name( $dir ); + my $fs_boundary = $dev_name ne $toplevel_dev_name; + my $msg; - return 1; + if ( $fs_boundary ) + { + $msg = "File system boundary at mount point $dir on device $dev_name"; } else { - my $msg = "Not crossing mount point $dir (use -m to override)"; - print CACHE "# $msg\n"; - logf( $msg ); + $msg = "Mount point $dir is still on the same device $dev_name"; } + + print CACHE "# $msg\n\n"; + logf( $msg ); + + return ! $fs_boundary; +} + + +#----------------------------------------------------------------------------- + + +# Get the device name where a directory is on from the 'df' command. +# +# Parameters: +# $dir directory +# +# Return value: +# device name ("/dev/sda3", "/dev/system/root") + +sub device_name() +{ + my ( $dir ) = @_; + + my @df_output = `df "$dir" 2>/dev/null`; + return "<unknown>" if scalar @df_output < 1; + + shift @df_output; # Remove header line + my ( $line ) = @df_output; + my ( $device_name ) = split( '\s+', $line ); + deb( "Directory $dir is on device $device_name" ); + + return $device_name; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qdirstat-1.1/src/Cleanup.cpp new/qdirstat-1.2/src/Cleanup.cpp --- old/qdirstat-1.1/src/Cleanup.cpp 2016-10-31 19:09:45.000000000 +0100 +++ new/qdirstat-1.2/src/Cleanup.cpp 2017-01-03 14:47:15.000000000 +0100 @@ -479,8 +479,13 @@ if ( apps.isEmpty() ) { +#ifdef Q_OS_MAC + apps[ "%terminal" ] = "open -a Terminal.app ."; + apps[ "%filemanager" ] = "open"; +#else apps[ "%terminal" ] = "xterm"; apps[ "%filemanager" ] = "xdg-open"; +#endif } return apps; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qdirstat-1.1/src/DirInfo.cpp new/qdirstat-1.2/src/DirInfo.cpp --- old/qdirstat-1.1/src/DirInfo.cpp 2016-10-31 19:09:45.000000000 +0100 +++ new/qdirstat-1.2/src/DirInfo.cpp 2017-01-03 14:47:15.000000000 +0100 @@ -676,3 +676,15 @@ } } } + + +const DirInfo * DirInfo::findNearestMountPoint() const +{ + const DirInfo * dir = this; + + while ( dir && ! dir->isMountPoint() ) + dir = dir->parent(); + + return dir; +} + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qdirstat-1.1/src/DirInfo.h new/qdirstat-1.2/src/DirInfo.h --- old/qdirstat-1.1/src/DirInfo.h 2016-10-31 19:09:45.000000000 +0100 +++ new/qdirstat-1.2/src/DirInfo.h 2017-01-03 14:47:15.000000000 +0100 @@ -144,6 +144,12 @@ **/ virtual void setMountPoint( bool isMountPoint = true ) Q_DECL_OVERRIDE; + /** + * Find the nearest parent that is a mount point or 0 if there is + * none. This may return this DirInfo itself. + **/ + const DirInfo * findNearestMountPoint() const; + /** * Returns true if this subtree is finished reading. * diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qdirstat-1.1/src/DirReadJob.cpp new/qdirstat-1.2/src/DirReadJob.cpp --- old/qdirstat-1.1/src/DirReadJob.cpp 2016-10-31 19:09:45.000000000 +0100 +++ new/qdirstat-1.2/src/DirReadJob.cpp 2017-01-03 14:47:15.000000000 +0100 @@ -19,6 +19,7 @@ #include "DirReadJob.h" #include "DirTreeCache.h" #include "ExcludeRules.h" +#include "MountPoints.h" #include "Exception.h" @@ -89,6 +90,54 @@ } +bool DirReadJob::crossingFileSystems( DirInfo * parent, DirInfo * child ) +{ + if ( parent->device() == child->device() ) + return false; + + QString childDevice = device( child ); + QString parentDevice = device( parent->findNearestMountPoint() );; + + if ( parentDevice.isEmpty() ) + parentDevice = _tree->device(); + + bool crossing = true; + + if ( ! parentDevice.isEmpty() && ! childDevice.isEmpty() ) + crossing = parentDevice != childDevice; + + if ( crossing ) + { + logInfo() << "File system boundary at mount point " << child + << " on device " << ( childDevice.isEmpty() ? "<unknown>" : childDevice ) + << endl; + } + else + { + logInfo() << "Mount point " << child + << " is still on the same device " << childDevice << endl; + } + + return crossing; +} + + +QString DirReadJob::device( const DirInfo * dir ) const +{ + QString device; + + if ( dir ) + { + const MountPoint * mountPoint = MountPoints::findByPath( dir->url() ); + + if ( mountPoint ) + device = mountPoint->device(); + } + + return device; +} + + @@ -145,7 +194,7 @@ } else // No exclude rule matched { - if ( _dir->device() == subDir->device() ) // normal case + if ( ! crossingFileSystems(_dir, subDir ) ) // normal case { LocalDirReadJob * job = new LocalDirReadJob( _tree, subDir ); CHECK_NEW( job ); @@ -153,7 +202,6 @@ } else // The subdirectory we just found is a mount point. { - logDebug() << "Found mount point " << subDir << endl; subDir->setMountPoint(); if ( _tree->crossFileSystems() ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qdirstat-1.1/src/DirReadJob.h new/qdirstat-1.2/src/DirReadJob.h --- old/qdirstat-1.1/src/DirReadJob.h 2016-10-31 19:09:45.000000000 +0100 +++ new/qdirstat-1.2/src/DirReadJob.h 2017-01-03 14:47:15.000000000 +0100 @@ -133,6 +133,18 @@ **/ void finished(); + /** + * Check if going from 'parent' to 'child' would cross a file system + * boundary. This take Btrfs subvolumes into account. + **/ + bool crossingFileSystems( DirInfo * parent, DirInfo * child ); + + /** + * Return the device name where 'dir' is on if it's a mount point. + * This uses MountPoints which reads /proc/mounts. + **/ + QString device( const DirInfo * dir ) const; + DirTree * _tree; DirInfo * _dir; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qdirstat-1.1/src/DirTree.cpp new/qdirstat-1.2/src/DirTree.cpp --- old/qdirstat-1.1/src/DirTree.cpp 2016-10-31 19:09:45.000000000 +0100 +++ new/qdirstat-1.2/src/DirTree.cpp 2017-01-03 14:47:15.000000000 +0100 @@ -14,6 +14,7 @@ #include "FileInfoSet.h" #include "Exception.h" #include "DirTreeCache.h" +#include "MountPoints.h" using namespace QDirStat; @@ -82,6 +83,7 @@ } _isBusy = false; + _device.clear(); } @@ -91,6 +93,9 @@ QString url = fileInfo.absoluteFilePath(); // logDebug() << "rawUrl: \"" << rawUrl << "\"" << endl; logInfo() << " url: \"" << url << "\"" << endl; + const MountPoint * mountPoint = MountPoints::findNearestMountPoint( url ); + _device = mountPoint ? mountPoint->device() : ""; + logInfo() << "device: " << _device << endl; _isBusy = true; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qdirstat-1.1/src/DirTree.h new/qdirstat-1.2/src/DirTree.h --- old/qdirstat-1.1/src/DirTree.h 2016-10-31 19:09:45.000000000 +0100 +++ new/qdirstat-1.2/src/DirTree.h 2017-01-03 14:47:15.000000000 +0100 @@ -132,6 +132,11 @@ **/ bool isTopLevel( FileInfo *item ) const; + /** + * Return the device of this tree's root item ("/dev/sda3" etc.). + **/ + QString device() const { return _device; } + /** * Clear all items of this tree. **/ @@ -351,6 +356,7 @@ DirReadJobQueue _jobQueue; bool _crossFileSystems; bool _isBusy; + QString _device; }; // class DirTree diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qdirstat-1.1/src/Logger.cpp new/qdirstat-1.2/src/Logger.cpp --- old/qdirstat-1.1/src/Logger.cpp 2016-10-31 19:09:45.000000000 +0100 +++ new/qdirstat-1.2/src/Logger.cpp 2017-01-03 14:47:15.000000000 +0100 @@ -258,7 +258,14 @@ << msg << endl; if ( msgType == QtFatalMsg ) - abort(); + { + fprintf( stderr, "FATAL: %s\n", qPrintable( msg ) ); + + if ( msg.contains( "Could not connect to display" ) ) + exit( 1 ); + else + abort(); + } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qdirstat-1.1/src/MainWindow.cpp new/qdirstat-1.2/src/MainWindow.cpp --- old/qdirstat-1.1/src/MainWindow.cpp 2016-10-31 19:09:45.000000000 +0100 +++ new/qdirstat-1.2/src/MainWindow.cpp 2017-01-03 14:47:15.000000000 +0100 @@ -92,6 +92,11 @@ _ui->treemapView->setMimeCategorizer( _mimeCategorizer ); +#ifdef Q_OS_MACX + // this makes the application to look like more "native" on macOS + setUnifiedTitleAndToolBarOnMac(true); + _ui->toolBar->setMovable(false); +#endif connect( _selectionModel, SIGNAL( currentBranchChanged( QModelIndex ) ), _ui->dirTreeView, SLOT ( closeAllExcept ( QModelIndex ) ) ); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qdirstat-1.1/src/MountPoints.cpp new/qdirstat-1.2/src/MountPoints.cpp --- old/qdirstat-1.1/src/MountPoints.cpp 1970-01-01 01:00:00.000000000 +0100 +++ new/qdirstat-1.2/src/MountPoints.cpp 2017-01-03 14:47:15.000000000 +0100 @@ -0,0 +1,244 @@ +/* + * File name: MountPoints.cpp + * Summary: Support classes for QDirStat + * License: GPL V2 - See file LICENSE for details. + * + * Author: Stefan Hundhammer <Stefan.Hundhammer@gmx.de> + */ + + +#include <QFile> +#include <QRegExp> +#include <QFileInfo> + +#include "MountPoints.h" +#include "Logger.h" +#include "Exception.h" + + +using namespace QDirStat; + + +MountPoint::MountPoint( const QString & device, + const QString & path, + const QString & filesystemType, + const QString & mountOptions ) : + _device( device ), + _path( path ), + _filesystemType( filesystemType ) +{ + _mountOptions = mountOptions.split( "," ); +} + + +QString MountPoint::mountOptionsStr() const +{ + return _mountOptions.join( "," ); +} + + +bool MountPoint::isBtrfs() const +{ + return _filesystemType.toLower() == "btrfs"; +} + + + + +MountPoints * MountPoints::_instance = 0; + + +MountPoints * MountPoints::instance() +{ + if ( ! _instance ) + { + _instance = new MountPoints(); + CHECK_NEW( _instance ); + } + + return _instance; +} + + +MountPoints::MountPoints() +{ + init(); +} + + +MountPoints::~MountPoints() +{ + init(); +} + + +void MountPoints::init() +{ + qDeleteAll( _mountPointMap ); + _mountPointMap.clear(); + _isPopulated = false; + _checkedForBtrfs = false; +} + + +void MountPoints::clear() +{ + if ( _instance ) + _instance->init(); +} + + +bool MountPoints::isEmpty() +{ + instance()->ensurePopulated(); + + return instance()->_mountPointMap.isEmpty(); +} + + +const MountPoint * MountPoints::findByPath( const QString & path ) +{ + instance()->ensurePopulated(); + + return instance()->_mountPointMap.value( path, 0 ); +} + + +const MountPoint * MountPoints::findNearestMountPoint( const QString & startPath ) +{ + QFileInfo fileInfo( startPath ); + QString path = fileInfo.canonicalFilePath(); // absolute path without symlinks or .. + + if ( path != startPath ) + logDebug() << startPath << " canonicalized is " << path << endl; + + const MountPoint * mountPoint = findByPath( path ); + + if ( ! mountPoint ) + { + QStringList pathComponents = startPath.split( "/", QString::SkipEmptyParts ); + + while ( ! mountPoint && !pathComponents.isEmpty() ) + { + // Try one level upwards + pathComponents.removeLast(); + path = QString( "/" ) + pathComponents.join( "/" ); + + mountPoint = instance()->_mountPointMap.value( path, 0 ); + } + } + + // logDebug() << "Nearest mount point for " << startPath << " is " << mountPoint << endl; + + return mountPoint; +} + + +bool MountPoints::hasBtrfs() +{ + instance()->ensurePopulated(); + + if ( ! _instance->_checkedForBtrfs ) + { + _instance->_hasBtrfs = _instance->checkForBtrfs(); + _instance->_checkedForBtrfs = true; + } + + return _instance->_hasBtrfs; +} + + +void MountPoints::ensurePopulated() +{ + if ( _isPopulated ) + return; + + read( "/proc/mounts" ) || read( "/etc/mtab" ); + + if ( ! _isPopulated ) + logError() << "Could not read either /proc/mounts or /etc/mtab" << endl; + + _isPopulated = true; +} + + +bool MountPoints::read( const QString & filename ) +{ + QFile file( filename ); + + if ( ! file.open( QIODevice::ReadOnly | QIODevice::Text ) ) + { + logWarning() << "Can't open " << filename << endl; + return false; + } + + QTextStream in( &file ); + int lineNo = 0; + int count = 0; + QString line = in.readLine(); + + while ( ! line.isNull() ) // in.atEnd() always returns true for /proc/* + { + ++lineNo; + QStringList fields = line.split( QRegExp( "\\s+" ), QString::SkipEmptyParts ); + + if ( fields.isEmpty() ) // allow empty lines + continue; + + if ( fields.size() < 4 ) + { + logError() << "Bad line " << filename << ":" << lineNo << ": " << line << endl; + continue; + } + + // File format (/proc/mounts or /etc/mtab): + // + // /dev/sda6 / ext4 rw,relatime,errors=remount-ro,data=ordered 0 0 + // /dev/sda7 /work ext4 rw,relatime,data=ordered 0 0 + // nas:/share/work /nas/work nfs rw,local_lock=none 0 0 + + QString device = fields[0]; + QString path = fields[1]; + QString fsType = fields[2]; + QString mountOpts = fields[3]; + // ignoring fsck and dump order (0 0) + + MountPoint * mountPoint = new MountPoint( device, path, fsType, mountOpts ); + CHECK_NEW( mountPoint ); + + _mountPointMap[ path ] = mountPoint; + ++count; + + line = in.readLine(); + } + + if ( count < 1 ) + logWarning() << "Not a single mount point in " << filename << endl; + else + _isPopulated = true; + + return _isPopulated; +} + + +bool MountPoints::checkForBtrfs() +{ + ensurePopulated(); + + foreach ( const MountPoint * mountPoint, _mountPointMap ) + { + if ( mountPoint && mountPoint->isBtrfs() ) + return true; + } + + return false; +} + + +void MountPoints::dump() +{ + foreach ( const MountPoint * mountPoint, instance()->_mountPointMap ) + { + logDebug() << mountPoint << endl; + } +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qdirstat-1.1/src/MountPoints.h new/qdirstat-1.2/src/MountPoints.h --- old/qdirstat-1.1/src/MountPoints.h 1970-01-01 01:00:00.000000000 +0100 +++ new/qdirstat-1.2/src/MountPoints.h 2017-01-03 14:47:15.000000000 +0100 @@ -0,0 +1,203 @@ +/* + * File name: MountPoints.h + * Summary: Support classes for QDirStat + * License: GPL V2 - See file LICENSE for details. + * + * Author: Stefan Hundhammer <Stefan.Hundhammer@gmx.de> + */ + +#ifndef MountPoints_h +#define MountPoints_h + + +#include <QString> +#include <QStringList> +#include <QMap> +#include <QTextStream> + + +namespace QDirStat +{ + /** + * Helper class to represent one mount point of a Linux/Unix filesystem. + **/ + class MountPoint + { + public: + /** + * Constructor. + **/ + MountPoint( const QString & device, + const QString & path, + const QString & filesystemType, + const QString & mountOptions ); + + /** + * Return the device that is mounted, someting like "/dev/sda3", + * "/dev/mapper/crypto", "nas:/share/work". + **/ + QString device() const { return _device; } + + /** + * Return the path where the device is mounted to. + **/ + QString path() const { return _path; } + + /** + * Return the filesystem type as string ("ext4", "btrfs", "none". + **/ + QString filesystemType() const { return _filesystemType; } + + /** + * Return the individual mount options as a list of strings + * ["rw", "nosuid", "nodev", "relatime", "rsize=32768"]. + **/ + QStringList mountOptions() const { return _mountOptions; } + + /** + * Return the mount options as one comma-separated string. + **/ + QString mountOptionsStr() const; + + /** + * Return 'true' if the filesystem type of this mount point is "btrfs". + **/ + bool isBtrfs() const; + + protected: + QString _device; + QString _path; + QString _filesystemType; + QStringList _mountOptions; + + }; // class MountPoint + + + /** + * Singleton class to access the current mount points. + **/ + class MountPoints + { + public: + /** + * Return the singleton object for this class. The first use will + * create the singleton. Notice that most of the static methods access + * the singleton, too, so the first call to most of those static + * methods will already create the singleton. + **/ + static MountPoints * instance(); + + /** + * Clear the content of the singleton. This is useful whenever the + * mount points in the system might have changed, i.e. when a + * filesystem might have been mounted or unmounted. + * + * This does not create the singleton if it doesn't exist yet. + **/ + static void clear(); + + /** + * Return 'true' if there are no mount points at all. + **/ + static bool isEmpty(); + + /** + * Return the mount point for 'path' if there is one or 0 if there is + * not. Ownership of the returned object is not transferred to the + * caller, i.e. the caller should not delete it. The pointer remains + * valid until the next call to clear(). + **/ + static const MountPoint * findByPath( const QString & path ); + + /** + * Find the nearest mount point upwards in the directory hierarchy + * starting from 'path'. 'path' itself might be that mount point. + * Ownership of the returned object is not transferred to the caller. + * + * This might return 0 if none of the files containing mount + * information (/proc/mounts, /etc/mtab) could be read. + **/ + static const MountPoint * findNearestMountPoint( const QString & path ); + + /** + * Return 'true' if any mount point has filesystem type "btrfs". + **/ + static bool hasBtrfs(); + + /** + * Ensure the mount points are populated with the content of + * /proc/mounts, falling back to /etc/mtab if /proc/mounts cannot be + * read. + **/ + void ensurePopulated(); + + /** + * Dump all current mount points to the log. This does not call + * ensurePopulated() first. + **/ + static void dump(); + + + protected: + /** + * Constructor. Not for public use. Use instance() or the static + * methods instead. + **/ + MountPoints(); + + /** + * Destructor. + **/ + virtual ~MountPoints(); + + + /** + * Clear the content of this class. + **/ + void init(); + + /** + * Read 'filename' (in /proc/mounts or /etc/mnt syntax) and populate + * the mount points with the content. Return 'true' on success, 'false' + * on failure. + **/ + bool read( const QString & filename ); + + /** + * Check if any of the mount points has filesystem type "btrfs". + **/ + bool checkForBtrfs(); + + // + // Data members + // + + static MountPoints * _instance; + + QMap<QString, MountPoint *> _mountPointMap; + bool _isPopulated; + bool _hasBtrfs; + bool _checkedForBtrfs; + + }; // class MountPoints + + + inline QTextStream & operator<< ( QTextStream & stream, const MountPoint * mp ) + { + if ( mp ) + { + stream << "<mount point for " << mp->device() + << " at " << mp->path() + << " type " << mp->filesystemType() + << ">"; + } + else + stream << "<NULL MountPoint*>"; + + return stream; + } + +} // namespace QDirStat + + +#endif // MountPoints_h diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qdirstat-1.1/src/Version.h new/qdirstat-1.2/src/Version.h --- old/qdirstat-1.1/src/Version.h 2016-10-31 19:09:45.000000000 +0100 +++ new/qdirstat-1.2/src/Version.h 2017-01-03 14:47:15.000000000 +0100 @@ -9,6 +9,6 @@ #ifndef Version_h #define Version_h -#define QDIRSTAT_VERSION "1.1-Pumpkin" +#define QDIRSTAT_VERSION "1.2" #endif // Version_h Binary files old/qdirstat-1.1/src/icons/qdirstat.icns and new/qdirstat-1.2/src/icons/qdirstat.icns differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qdirstat-1.1/src/main.cpp new/qdirstat-1.2/src/main.cpp --- old/qdirstat-1.1/src/main.cpp 2016-10-31 19:09:45.000000000 +0100 +++ new/qdirstat-1.2/src/main.cpp 2017-01-03 14:47:15.000000000 +0100 @@ -55,7 +55,7 @@ } else { - logDebug() << "No " << longName << endl; + // logDebug() << "No " << longName << endl; return false; } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qdirstat-1.1/src/src.pro new/qdirstat-1.2/src/src.pro --- old/qdirstat-1.1/src/src.pro 2016-10-31 19:09:45.000000000 +0100 +++ new/qdirstat-1.2/src/src.pro 2017-01-03 14:47:15.000000000 +0100 @@ -55,6 +55,7 @@ MimeCategorizer.cpp \ MimeCategory.cpp \ MimeCategoryConfigPage.cpp \ + MountPoints.cpp \ OutputWindow.cpp \ PercentBar.cpp \ Process.cpp \ @@ -98,6 +99,7 @@ MimeCategorizer.h \ MimeCategory.h \ MimeCategoryConfigPage.h \ + MountPoints.h \ OutputWindow.h \ PercentBar.h \ Process.h \ @@ -131,3 +133,5 @@ icons.files = icons/qdirstat.png icons.path = /usr/share/icons/hicolor/32x32/apps + +mac:ICON = icons/qdirstat.icns
participants (1)
-
root@hilbertn.suse.de