diff options
author | elfmz <fenix1905@tut.by> | 2022-10-27 21:41:43 +0300 |
---|---|---|
committer | elfmz <fenix1905@tut.by> | 2022-10-27 22:50:25 +0300 |
commit | 6cae1adec50281fa695649f01f682189a1ec9234 (patch) | |
tree | e90b38adb9b31216b442f67635d278b531c7cdc3 | |
parent | ecefbdfc83366ac6d119e8356901ecfeb70afa7c (diff) |
use MountInfo for Location menu (touch #1375)
-rwxr-xr-x | far2l/bootstrap/mounts.sh | 171 | ||||
-rw-r--r-- | far2l/src/Mounts.cpp | 86 | ||||
-rw-r--r-- | far2l/src/farwinapi.cpp | 2 | ||||
-rw-r--r-- | far2l/src/findfile.cpp | 2 | ||||
-rw-r--r-- | far2l/src/mix/MountInfo.cpp | 99 | ||||
-rw-r--r-- | far2l/src/mix/MountInfo.h | 22 | ||||
-rw-r--r-- | far2l/src/mix/dirmix.cpp | 4 | ||||
-rw-r--r-- | far2l/src/mix/strmix.cpp | 9 | ||||
-rw-r--r-- | utils/src/Threaded.cpp | 22 |
9 files changed, 164 insertions, 253 deletions
diff --git a/far2l/bootstrap/mounts.sh b/far2l/bootstrap/mounts.sh deleted file mode 100755 index 561f5d95..00000000 --- a/far2l/bootstrap/mounts.sh +++ /dev/null @@ -1,171 +0,0 @@ -#!/bin/sh - -########################################################## -#This script used during FAR's Alt+F1/Alt+F2 menu building -#--------------------------------------------------------- -# Mode of operation controlled by $1 and can be one of: 'enum' 'umount' -# Other arguments and output depend on mode operation: -# $1 == 'enum' - enumerates all locations -# Outputs multiple lines with format: -# Path1<TAB>Info1 -# Path2<TAB>Info2 -# FAR extracts path, replaces TABs with vertical lines and -# adds resulting strings to menu -#--------------------------------------------------------- -# $1 == 'umount' - unmounts given location -# $2 - path to unmount -# $3 - optional 'force' flag -########################################################## - -# Optional per-user script -if [ -x ~/.config/far2l/mounts.sh ]; then -. ~/.config/far2l/mounts.sh -fi - -########################################################## -# This optional file may contain per-user extra values added to df output, -# its content must be looking like: -#path1<TAB>info1 -#path2<TAB>info2 -#-<TAB>separator_label -#path3<TAB>info3 -FAVORITES=~/.config/far2l/favorites - -########################################################## -if [ "$1" = 'umount' ]; then - if [ "$3" = 'force' ]; then - sudo umount -f "$2" - else - umount "$2" - fi - -########################################################## -else - sysname="$(uname)" - timeout_coreutils="false" - column_bsdmainutils="false" - awk_busybox="false" - if [ "$sysname" = "Linux" ]; then - timeout_coreutils="$(sh -c 'timeout --version > /dev/null 2>&1 && printf true || printf false')" - column_bsdmainutils="$(sh -c 'column -h > /dev/null 2>&1 && printf true || printf false')" - awk_busybox="$([ .$(awk 2>&1 | head -n 1 | cut -d' ' -f1) = .BusyBox ] > /dev/null 2>&1 && printf true || printf false)" - fi - if [ "$sysname" = "Linux" ] || [ "$sysname" = "FreeBSD" ]; then - DF_ARGS='-T' - DF_AVAIL=5 - DF_TOTAL=3 - DF_NAME=2 - DF_DIVBY=1 - DF_USE=6 - MNT_FS=1 - MNT_PATH=3 - FT_IDX=1 - FT_FS=3 - FT_TYPE=4 - FT_PATH=5 - TIMEOUT=1 - MNT_TYPE=0 - MNT_FILTER='cat' - FT_HEADER='Filesystem Type 1K-blocks Used Avail Use%% Mountpoint' - FMT_COLUMN='cat' - if [ "$sysname" = "Linux" ]; then - MNT_TYPE=5 - MNT_FILTER='grep -v -e " /proc\(/[\/a-z_]\+\)* " -e " /sys\(/[a-z_,]\+\)* " -e " /dev/\(pts\|hugepages\|mqueue\) " -e " /run/user/\([0-1]\+\)/doc " -e "/home/\([a-z0-9\._]\+\)/.cache/doc" -e " /tmp/\.\([a-z0-9\._]\+\)_\([a-zA-Z0-9\._]\+\) "' - FT_HEADER='Filesystem Type 1K-blocks Used Available Use%% Mounted_on' - if [ "$timeout_coreutils" = "true" ]; then - FMT_COLUMN='column -t' - fi - fi - if [ "$sysname" = "FreeBSD" ]; then - MNT_FILTER='grep -v -e " \(/[a-z]\+\)*/dev/foo "' - FT_HEADER='Filesystem Type 1K-blocks Used Avail Capacity Mounted_on' - fi - - # 1} printf $FT_HEADER and mount output - # 2) grep - use $MNT_FILTER - # 3) awk - output almost like df - # 4) sed - prepare for uniq to eliminate duplicated block device names - # 5) awk - uniq by $FT_IDX and use timeout controlled df output in subshell - # 6) column - format final output - if [ "$sysname" = "Linux" ] && [ "$timeout_coreutils" = "true" ]; then - DF='( printf "'$FT_HEADER'" ; printf "\n" ; mount \ - | '$MNT_FILTER' \ - | awk '"'"'{ printf "%03.0f:",NR ; printf $'$MNT_FS' " $ " ; print $'$MNT_FS' " " $'$MNT_TYPE' " " $'$MNT_PATH' }'"'"' \ - | sed -e "s_^\([0-9]\+\):\(\/dev\/[^\ ]\+\)_000:~\\2_" \ - | awk '"'"' { if ( prev != $'$FT_IDX' ) { var = "" ; "( timeout --signal=TERM '$TIMEOUT' df '$DF_ARGS' " $'$FT_PATH' " 2> /dev/null ) | head -n 2 | tail -n 1" | getline var ; if ( var != "" ) { print var } else { print $'$FT_FS' " " $'$FT_TYPE' " [size] [used] [avail] [use] " $'$FT_PATH' } } ; prev = $'$FT_IDX' } '"'"' ) \ - | '$FMT_COLUMN'' - else - DF='( printf "'$FT_HEADER'" ; printf "\n" ; mount \ - | '$MNT_FILTER' \ - | awk '"'"' { printf "%03.0f:",NR ; printf $'$MNT_FS' " $ " ; print $'$MNT_FS' " [type] " $'$MNT_PATH' } '"'"' \ - | sed -e "s_^\([0-9]\+\):\(\/dev\/[^\ ]\+\)_000:~\\2_" \ - | awk '"'"' { if ( prev != $'$FT_IDX' ) { var = "" ; "( ( sleep '$TIMEOUT' ; kill $$ 2> /dev/null ) & exec df '$DF_ARGS' " $'$FT_PATH' " 2> /dev/null ) | head -n 2 | tail -n 1" | getline var ; if ( var != "" ) { print var } else { print $'$FT_FS' " " $'$FT_TYPE' " [size] [used] [avail] [use] " $'$FT_PATH' } } ; prev = $'$FT_IDX' } '"'"' ) \ - | '$FMT_COLUMN'' - fi - else - DF_ARGS='-t' - DF_AVAIL=4 - DF_TOTAL=2 - DF_NAME=1 - DF_DIVBY=2 - DF_USE=5 - DF='df '$DF_ARGS'' - fi - - #FIXME: paths that contain repeated continuos spaces - sh -c "$DF" 2>/dev/null | awk "-F " '{ - path = $NF; - for (n = NF - 1; n > '$DF_AVAIL' && substr(path, 1, 1) != "/"; n--) { - path = $n" "path; - } - - if ( substr(path, 1, 1) == "/" && substr(path, 1, 5) != "/run/" && substr(path, 1, 5) != "/sys/" \ - && substr(path, 1, 5) != "/dev/" && substr(path, 1, 6) != "/snap/" \ - && substr(path, 1, 8) != "/System/" && substr(path, 1, 9) != "/private/" \ - && path != "/dev" ) { - - avail = ($'$DF_AVAIL'+0.0) / '$DF_DIVBY'; - total = ($'$DF_TOTAL'+0.0) / '$DF_DIVBY'; - - total_units="K"; - if (total >= 1024*1024*1024) { total_units="T" ; total/= 1024*1024*1024;} - else if (total >= 1024*1024) { total_units="G" ; total/= 1024*1024;} - else if (total >= 1024) { total_units="M" ; total/= 1024;} - - avail_units="K"; - if (avail >= 1024*1024*1024) { avail_units="T" ; avail/= 1024*1024*1024;} - else if (avail >= 1024*1024) { avail_units="G" ; avail/= 1024*1024;} - else if (avail >= 1024) { avail_units="M" ; avail/= 1024;} - - avail_ident = avail < 99.9 ? ( avail < 9.9 ? "" : "_" ) : ""; - total_ident = total < 99.9 ? ( total < 9.9 ? "" : " " ) : ""; - - avail_fraction = avail < 10 ? 1 : 0; - total_fraction = total < 10 ? 1 : 0; - - separator_symbol = "/" - - if ("'$awk_busybox'" == "true") { - - avail2 = substr((avail_ident avail ".0"), 1, 3); - total2 = substr((total_ident total ".0"), 1, 3); - - print_format = "%s\t%s%s%s%s%s\t%s\n"; - printf print_format, path, avail2, avail_units, separator_symbol, total2, total_units, $'$DF_NAME'; - - } else { - - print_format = "%s\t%s%.*f%s%s%s%.*f%s\t%8s\n"; - printf print_format, path, avail_ident, avail_fraction, avail, avail_units, separator_symbol, total_ident, total_fraction, total, total_units, $'$DF_NAME'; - } - } - }' - - if [ -s "$FAVORITES" ]; then - awk "-F " '{ - if ($0 != "" && substr($0, 1, 1) != "#") { - print $0; - } - }' "$FAVORITES" - fi -fi diff --git a/far2l/src/Mounts.cpp b/far2l/src/Mounts.cpp index 4eb615bb..2804f915 100644 --- a/far2l/src/Mounts.cpp +++ b/far2l/src/Mounts.cpp @@ -1,7 +1,7 @@ #include "headers.hpp" #include <crc64.h> - +#include <fstream> #include "Mounts.hpp" #include "lang.hpp" #include "keys.hpp" @@ -16,6 +16,7 @@ #include "manager.hpp" #include "ConfigRW.hpp" #include "HotkeyLetterDialog.hpp" +#include "MountInfo.h" namespace Mounts { @@ -63,51 +64,68 @@ namespace Mounts Enum::Enum(FARString &another_curdir) { - std::string cmd = GetMyScriptQuoted("mounts.sh"); - cmd+= " enum"; + MountInfo mi(true); bool has_rootfs = false; + for (const auto &mp : mi.Enum()) { + emplace_back(); + auto &e = back(); + e.path = mp.path; + e.info = mp.filesystem; + if (mp.bad) { + e.usage = Opt.NoGraphics ? L"X_X" : L"❌_❌"; + + } else { + FileSizeToStr(e.usage, mp.avail, -1, COLUMN_ECONOMIC | COLUMN_FLOATSIZE | COLUMN_SHOWBYTESINDEX); //COLUMN_AUTOSIZE | COLUMN_SHOWBYTESINDEX + while (e.usage.GetLength() < 4) { + e.usage.Insert(0, L' '); + } + FARString tmp; + FileSizeToStr(tmp, mp.total, -1, COLUMN_ECONOMIC | COLUMN_FLOATSIZE | COLUMN_SHOWBYTESINDEX); //COLUMN_AUTOSIZE | COLUMN_SHOWBYTESINDEX + while (e.usage.GetLength() < 4) { + tmp.Insert(0, L' '); + } + e.usage+= L"/"; + e.usage+= tmp; + } - FILE *f = popen(cmd.c_str(), "r"); - if (f) { - char buf[0x2100] = { }; - std::wstring s, tmp; - while (fgets(buf, sizeof(buf) - 1, f)!=NULL) { - for (;;) { - size_t l = strlen(buf); - if (!l) break; - if (buf[l-1]!='\r' && buf[l-1]!='\n') break; - buf[l-1] = 0; + if (e.path == L"/") { + has_rootfs = true; + } else { + e.unmountable = true; + } + e.id = GenerateIdFromPath(e.path); + } + + std::ifstream favis(InMyConfig("favorites")); + if (favis.is_open()) { + std::string line; + while (std::getline(favis, line)) { + StrTrim(line, " \t\r\n"); + if (line.empty() || line.front() == '#') { + continue; } - if (buf[0]) { + std::vector<std::string> parts; + StrExplode(parts, line, "\t"); + if (!parts.empty()) { emplace_back(); auto &e = back(); - e.path.Copy(&buf[0]); - size_t t; - if (e.path.Pos(t, L'\t')) { - e.info = e.path.SubStr(t + 1); - e.path.Truncate(t); - if (e.info.Pos(t, L'\t')) { - e.usage = e.info.SubStr(0, t); - e.info = e.info.SubStr(t + 1); + e.path = parts.front(); + if (parts.size() > 1) { + e.info = parts.back(); + if (parts.size() > 2) { + e.usage = parts[1]; } } + e.id = GenerateIdFromPath(e.path); if (e.path == L"/") { has_rootfs = true; - } else { + + } else if (*e.path.CPtr() == L'/') { e.unmountable = true; } - RemoveExternalSpaces(e.usage); - RemoveExternalSpaces(e.info); - e.id = GenerateIdFromPath(e.path); } } - int r = pclose(f); - if (r != 0) { - fprintf(stderr, "Exit code %u executing '%s'\n", r, cmd.c_str()); - } - } else { - fprintf(stderr, "Error %u executing '%s'\n", errno, cmd.c_str()); } if (!has_rootfs) { @@ -133,8 +151,8 @@ namespace Mounts bool Unmount(const FARString &path, bool force) { - std::string cmd = GetMyScriptQuoted("mounts.sh"); - cmd+= " umount \""; + std::string cmd = GetMyScriptQuoted("unmount.sh"); + cmd+= " \""; cmd+= EscapeCmdStr(Wide2MB(path)); cmd+= "\""; if (force) { diff --git a/far2l/src/farwinapi.cpp b/far2l/src/farwinapi.cpp index 0afad4d4..64e9d254 100644 --- a/far2l/src/farwinapi.cpp +++ b/far2l/src/farwinapi.cpp @@ -514,7 +514,7 @@ BOOL apiGetVolumeInformation( } if (pFileSystemName) { - *pFileSystemName = MountInfo(false).GetFileSystem(path); + *pFileSystemName = MountInfo().GetFileSystem(path); } return TRUE; diff --git a/far2l/src/findfile.cpp b/far2l/src/findfile.cpp index d27f3939..f4655733 100644 --- a/far2l/src/findfile.cpp +++ b/far2l/src/findfile.cpp @@ -2803,7 +2803,7 @@ public: { SudoClientRegion scr; DWORD msec = GetProcessUptimeMSec(); - pMountInfo.reset(new MountInfo(false)); + pMountInfo.reset(new MountInfo); if (PluginMode) { DoPreparePluginList(hDlg); diff --git a/far2l/src/mix/MountInfo.cpp b/far2l/src/mix/MountInfo.cpp index a655ccfb..669cd6b5 100644 --- a/far2l/src/mix/MountInfo.cpp +++ b/far2l/src/mix/MountInfo.cpp @@ -20,6 +20,7 @@ #include <fstream> #include <chrono> #include <mutex> +#include <atomic> #include <condition_variable> #include "MountInfo.h" #include <ScopeHelpers.h> @@ -105,14 +106,6 @@ static struct FSMagic { ///////////////////////////////////////////////////////////////////////////////////////////// -struct Mountpoint -{ - std::string path; - std::string filesystem; - bool multi_thread_friendly; - unsigned long long total, used; -}; - struct Mountpoints : std::vector<Mountpoint> { struct Pending @@ -123,30 +116,35 @@ struct Mountpoints : std::vector<Mountpoint> } pending; }; -class ThreadedStatFS : Threaded +static std::atomic<unsigned int> s_mount_info_threads{0}; + +class ThreadedStatVFS : Threaded { std::shared_ptr<Mountpoints> _mps; size_t _mpi; void *ThreadProc() { - struct statfs fs{}; - int r = statfs((*_mps)[_mpi].path.c_str(), &fs); + struct statvfs s = {}; + int r = statvfs((*_mps)[_mpi].path.c_str(), &s); if (r == 0) { - (*_mps)[_mpi].total = fs.f_bsize * fs.f_blocks; - (*_mps)[_mpi].used = (fs.f_bsize - fs.f_bfree) * fs.f_blocks; + (*_mps)[_mpi].total = ((unsigned long long)s.f_blocks) * s.f_frsize; + (*_mps)[_mpi].avail = ((unsigned long long)s.f_bavail) * s.f_frsize; + (*_mps)[_mpi].bad = false; } return nullptr; } public: - ThreadedStatFS(std::shared_ptr<Mountpoints> &mps, size_t mpi) + ThreadedStatVFS(std::shared_ptr<Mountpoints> &mps, size_t mpi) : _mps(mps), _mpi(mpi) { + ++s_mount_info_threads; } - virtual ~ThreadedStatFS() + virtual ~ThreadedStatVFS() { + --s_mount_info_threads; std::unique_lock<std::mutex> lock(_mps->pending.mtx); _mps->pending.cnt--; if (_mps->pending.cnt == 0) { @@ -158,13 +156,30 @@ public: void Start() { if (!StartThread(true)) { - fprintf(stderr, "ThreadedStatFS: can't start thread\n"); + fprintf(stderr, "ThreadedStatVFS: can't start thread\n"); delete this; } } }; -MountInfo::MountInfo(bool query_space) + +static bool SkipForLocationMenu(const char *path) +{ + if (StrStartsFrom(path, "/System/") + || strcmp(path, "/proc") == 0 || StrStartsFrom(path, "/proc/") + || strcmp(path, "/sys") == 0 || StrStartsFrom(path, "/sys/") + || strcmp(path, "/dev") == 0 || StrStartsFrom(path, "/dev/") + || strcmp(path, "/run") == 0 || StrStartsFrom(path, "/run/") + || strcmp(path, "/tmp") == 0 || StrStartsFrom(path, "/tmp/") + || strcmp(path, "/snap") == 0 || StrStartsFrom(path, "/snap/") + || strcmp(path, "/private") == 0 || StrStartsFrom(path, "/private/") + ) { + return true; + } + return false; +} + +MountInfo::MountInfo(bool for_location_menu) { // force-enable multi-threaded disk access: echo e > ~/.config/far2l/mtfs // force-disable multi-threaded disk access: echo d > ~/.config/far2l/mtfs @@ -178,6 +193,8 @@ MountInfo::MountInfo(bool query_space) _mountpoints = std::make_shared<Mountpoints>(); #ifdef __linux__ + // manual parsing mounts file instead of using setmntent cuz later doesnt return + // mounted device path that is needed to determine if its 'rotational' std::ifstream is("/proc/mounts"); if (is.is_open()) { std::string line, sys_path; @@ -185,7 +202,8 @@ MountInfo::MountInfo(bool query_space) while (std::getline(is, line)) { parts.clear(); StrExplode(parts, line, " \t"); - if (parts.size() > 1 && StrStartsFrom(parts[1], "/")) { + if (parts.size() > 1 && StrStartsFrom(parts[1], "/") + && (!for_location_menu || !SkipForLocationMenu(parts[1].c_str()))) { bool multi_thread_friendly; if (StrStartsFrom(parts[0], "/dev/")) { sys_path = "/sys/block/"; @@ -214,6 +232,7 @@ MountInfo::MountInfo(bool query_space) parts[1], parts[2], multi_thread_friendly, + false, 0, 0 }); @@ -226,17 +245,20 @@ MountInfo::MountInfo(bool query_space) int r = getfsstat(nullptr, 0, MNT_NOWAIT); if (r > 0) { std::vector<struct statfs> buf(r * 2 + 2); - r = getfsstat(buf.data(), buf.size(), MNT_NOWAIT); + r = getfsstat(buf.data(), buf.size() * sizeof(*buf.data()), MNT_NOWAIT); if (r > 0) { buf.resize(r); for (const auto &fs : buf) { - _mountpoints->emplace_back(Mountpoint{ - fs.f_mntonname, - fs.f_fstypename, - true, - fs.f_bsize * fs.f_blocks, - (fs.f_bsize - fs.f_bfree) * fs.f_blocks - }); + if (!for_location_menu || !SkipForLocationMenu(fs.f_mntonname)) { + _mountpoints->emplace_back(Mountpoint{ + fs.f_mntonname, + fs.f_fstypename, + true, + false, + ((unsigned long long)fs.f_blocks) * fs.f_bsize, // unreliable due to MNT_NOWAIT + ((unsigned long long)fs.f_bavail) * fs.f_bsize // ThreadedStatVFS will set true nums + }); + } } } } @@ -245,17 +267,23 @@ MountInfo::MountInfo(bool query_space) if (_mountpoints->empty()) { fprintf(stderr, "%s: no mountpoints found\n", __FUNCTION__); - } else if (query_space) { + } else if (for_location_menu) { + if (s_mount_info_threads != 0) { + fprintf(stderr, "%s: still %u old threads hanging around\n", + __FUNCTION__, (unsigned int)s_mount_info_threads); + } for (size_t i = 0; i < _mountpoints->size(); ++i) { try { - (new ThreadedStatFS(_mountpoints, i))->Start(); + (*_mountpoints)[i].bad = true; + (new ThreadedStatVFS(_mountpoints, i))->Start(); std::unique_lock<std::mutex> lock(_mountpoints->pending.mtx); _mountpoints->pending.cnt++; + } catch (std::exception &e) { fprintf(stderr, "%s: %s\n", __FUNCTION__, e.what()); } } - for (DWORD ms = 0; ms < 1000;) { + for (DWORD ms = 0; ;) { std::chrono::milliseconds ms_before = std::chrono::duration_cast< std::chrono::milliseconds > (std::chrono::steady_clock::now().time_since_epoch()); { @@ -265,17 +293,25 @@ MountInfo::MountInfo(bool query_space) break; } } - ms+= (std::chrono::duration_cast< std::chrono::milliseconds > + ms+= (std::chrono::duration_cast< std::chrono::milliseconds > (std::chrono::steady_clock::now().time_since_epoch()) - ms_before).count(); + if (ms >= 1000) { + fprintf(stderr, "%s: timed out\n", __FUNCTION__); + break; + } } } for (const auto &it : *_mountpoints) { fprintf(stderr, "%s: mtf=%d spc=[%llu/%llu] fs='%s' at '%s'\n", __FUNCTION__, - it.multi_thread_friendly, it.used, it.total, it.filesystem.c_str(), it.path.c_str()); + it.multi_thread_friendly, it.avail, it.total, it.filesystem.c_str(), it.path.c_str()); } } +const std::vector<Mountpoint> &MountInfo::Enum() const +{ + return *_mountpoints; +} std::string MountInfo::GetFileSystem(const std::string &path) const { @@ -327,3 +363,4 @@ bool MountInfo::IsMultiThreadFriendly(const std::string &path) const } return out; } + diff --git a/far2l/src/mix/MountInfo.h b/far2l/src/mix/MountInfo.h index 65781245..ce4bbddd 100644 --- a/far2l/src/mix/MountInfo.h +++ b/far2l/src/mix/MountInfo.h @@ -3,11 +3,25 @@ #include <vector> #include <memory> +struct Mountpoint +{ + std::string path; + std::string filesystem; + bool multi_thread_friendly; + + // following fields valid only if for_location_menu set to true + volatile bool bad; + volatile unsigned long long total; + volatile unsigned long long avail; +}; + struct Mountpoints; -/* This class detects if path points to device that is best to be +/* This class enumerates mountpoints and also provides extra information + * like disk sizes (if for_location_menu enabled) and also it detects + * if specified path points to device that is best to be * accessed in multi-thread parallel manner, like SSD drives. - * Currently works only under Linux, others defaulted to <true>. + * Later currently works only under Linux, others defaulted to <true>. */ class MountInfo { @@ -15,7 +29,9 @@ class MountInfo char _mtfs = 0; public: - MountInfo(bool query_space); + MountInfo(bool for_location_menu = false); + + const std::vector<Mountpoint> &Enum() const; std::string GetFileSystem(const std::string &path) const; diff --git a/far2l/src/mix/dirmix.cpp b/far2l/src/mix/dirmix.cpp index 9439a818..08063376 100644 --- a/far2l/src/mix/dirmix.cpp +++ b/far2l/src/mix/dirmix.cpp @@ -248,7 +248,9 @@ void CreatePath(FARString &strPath) std::string GetHelperPathName(const char *name) { std::string out = g_strFarPath.GetMB(); - out+= GOOD_SLASH; + if (!out.empty() && out.back() != GOOD_SLASH) { + out+= GOOD_SLASH; + } out+= name; struct stat s; diff --git a/far2l/src/mix/strmix.cpp b/far2l/src/mix/strmix.cpp index 1e422050..317f68f2 100644 --- a/far2l/src/mix/strmix.cpp +++ b/far2l/src/mix/strmix.cpp @@ -743,8 +743,8 @@ FARString & WINAPI FileSizeToStr(FARString &strDestStr, uint64_t Size, int Width Sz++; } - strStr.Format(L"%d.%02d", (DWORD)Sz,Decimal); - FormatNumber(strStr,strStr,2); + strStr.Format(L"%d.%02d", (DWORD)Sz, Decimal); + FormatNumber(strStr, strStr, (Economic && Sz > 9) ? 1 : 2); } if (IndexB>0 || ShowBytesIndex) @@ -752,7 +752,7 @@ FARString & WINAPI FileSizeToStr(FARString &strDestStr, uint64_t Size, int Width Width-=(Economic?1:2); if (Width<0) - Width=0; + Width=strStr.GetLength(); if (Economic) strDestStr.Format(L"%*.*ls%1.1ls",Width,Width,strStr.CPtr(),UnitStr[IndexB][IndexDiv]); @@ -763,6 +763,7 @@ FARString & WINAPI FileSizeToStr(FARString &strDestStr, uint64_t Size, int Width strDestStr.Format(L"%*.*ls",Width,Width,strStr.CPtr()); return strDestStr; + } if (Commas) @@ -777,7 +778,7 @@ FARString & WINAPI FileSizeToStr(FARString &strDestStr, uint64_t Size, int Width Width-=(Economic?1:2); if (Width<0) - Width=0; + Width=strStr.GetLength(); if (Economic) strDestStr.Format(L"%*.*ls%1.1ls",Width,Width,strStr.CPtr(),UnitStr[0][IndexDiv]); diff --git a/utils/src/Threaded.cpp b/utils/src/Threaded.cpp index 7e404f1d..b23f725c 100644 --- a/utils/src/Threaded.cpp +++ b/utils/src/Threaded.cpp @@ -10,7 +10,7 @@ Threaded::~Threaded() { std::lock_guard<std::mutex> lock(_trd_mtx); - if (!_trd_exited || !_trd_joined) { + if (!_self_destruct && (!_trd_exited || !_trd_joined)) { fprintf(stderr, "~Threaded: still busy\n"); abort(); } @@ -21,16 +21,15 @@ void *Threaded::sThreadProc(void *p) Threaded *it = (Threaded *)p; void *result = it->ThreadProc(); - { + if (it->_self_destruct) { + delete it; + + } else { std::lock_guard<std::mutex> lock(it->_trd_mtx); it->_trd_exited = true; it->_trd_cond.notify_all(); } - if (it->_self_destruct) { - delete it; - } - return result; } @@ -48,12 +47,21 @@ bool Threaded::StartThread(bool self_destruct) _trd_joined = _trd_exited = false; _self_destruct = self_destruct; - if (pthread_create(&_trd, NULL, &sThreadProc, this) != 0) { + pthread_t trd; + if (pthread_create(&trd, NULL, &sThreadProc, this) != 0) { _trd_joined = _trd_exited = true; + _self_destruct = false; _trd = 0; return false; } + if (self_destruct) { + pthread_detach(trd); + + } else { + _trd = trd; + } + return true; } |