From 04f8b8230817e7de05b7417902b03ab78a97dce5 Mon Sep 17 00:00:00 2001 From: Johan Date: Thu, 14 Oct 2021 20:07:16 +0300 Subject: [PATCH] Add total disk space to free-space RPC request (#1682) * Add total space to free-space endpoint * Update docs --- extras/rpc-spec.txt | 10 ++-- libtransmission/platform-quota.cc | 82 +++++++++++++++++++------------ libtransmission/platform-quota.h | 13 +++-- libtransmission/rpcimpl.cc | 13 ++--- libtransmission/session.cc | 4 +- libtransmission/utils.cc | 21 ++++---- libtransmission/utils.h | 8 +-- 7 files changed, 89 insertions(+), 62 deletions(-) diff --git a/extras/rpc-spec.txt b/extras/rpc-spec.txt index 7d64f6eb3..506ad6124 100644 --- a/extras/rpc-spec.txt +++ b/extras/rpc-spec.txt @@ -679,10 +679,11 @@ Response arguments: - string | value type & description - ------------+---------------------------------------------------------- - "path" | string same as the Request argument - "size-bytes"| number the size, in bytes, of the free space in that directory + string | value type & description + -------------+---------------------------------------------------------- + "path" | string same as the Request argument + "size-bytes" | number the size, in bytes, of the free space in that directory + "total_size" | number the total capacity, in bytes, of that directory 5.0. Protocol Versions @@ -854,6 +855,7 @@ | | | session-get | new arg "script-torrent-added-filename" | | | torrent-get | new arg "file-count" | | | torrent-get | new arg "primary-mime-type" + | | | free-space | new return arg "total-capacity" 5.1. Upcoming Breakage diff --git a/libtransmission/platform-quota.cc b/libtransmission/platform-quota.cc index 70362f81b..9ed006e83 100644 --- a/libtransmission/platform-quota.cc +++ b/libtransmission/platform-quota.cc @@ -268,11 +268,12 @@ extern "C" #include } -static int64_t getquota(char const* device) +struct tr_disk_space getquota(char const* device) { struct quotahandle* qh; struct quotakey qk; struct quotaval qv; + struct tr_disk_space disk_space = { -1, -1 }; int64_t limit; int64_t freespace; int64_t spaceused; @@ -281,7 +282,7 @@ static int64_t getquota(char const* device) if (qh == nullptr) { - return -1; + return disk_space; } qk.qk_idtype = QUOTA_IDTYPE_USER; @@ -291,7 +292,7 @@ static int64_t getquota(char const* device) if (quota_get(qh, &qk, &qv) == -1) { quota_close(qh); - return -1; + return disk_space; } if (qv.qv_softlimit > 0) @@ -305,19 +306,21 @@ static int64_t getquota(char const* device) else { quota_close(qh); - return -1; + return disk_space; } spaceused = qv.qv_usage; quota_close(qh); freespace = limit - spaceused; - return freespace < 0 ? 0 : freespace; + disk_space.free = freespace < 0 ? 0 : freespace; + disk_space.total = limit; + return disk_space; } #else -static int64_t getquota(char const* device) +static struct tr_disk_space getquota(char const* device) { #if defined(__DragonFly__) struct ufs_dqblk dq; @@ -326,12 +329,13 @@ static int64_t getquota(char const* device) #endif int64_t limit; int64_t freespace; + struct tr_disk_space disk_space = { -1, -1 }; int64_t spaceused; #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__APPLE__) if (quotactl(device, QCMD(Q_GETQUOTA, USRQUOTA), getuid(), (caddr_t)&dq) != 0) { - return -1; + return disk_space; } #elif defined(__sun) struct quotctl op; @@ -339,7 +343,7 @@ static int64_t getquota(char const* device) if (fd < 0) { - return -1; + return disk_space; } op.op = Q_GETQUOTA; @@ -349,14 +353,14 @@ static int64_t getquota(char const* device) if (ioctl(fd, Q_QUOTACTL, &op) != 0) { close(fd); - return -1; + return disk_space; } close(fd); #else if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device, getuid(), (caddr_t)&dq) != 0) { - return -1; + return disk_space; } #endif @@ -372,7 +376,7 @@ static int64_t getquota(char const* device) else { /* No quota enabled for this user */ - return -1; + return disk_space; } #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) @@ -390,9 +394,13 @@ static int64_t getquota(char const* device) freespace = limit - spaceused; #ifdef __APPLE__ - return freespace < 0 ? 0 : freespace; + disk_space.free = freespace < 0 ? 0 : freespace; + disk_space.total = limit < 0 ? 0 : limit; + return disk_space; #else - return freespace < 0 ? 0 : (freespace * 1024); + disk_space.free = freespace < 0 ? 0 : (freespace * 1024); + disk_space.total = limit < 0 ? 0 : (limit * 1024); + return disk_space; #endif } @@ -400,10 +408,11 @@ static int64_t getquota(char const* device) #ifdef HAVE_XQM -static int64_t getxfsquota(char* device) +static struct tr_disk_space getxfsquota(char* device) { int64_t limit; int64_t freespace; + struct tr_disk_space disk_space = { -1, -1 }; struct fs_disk_quota dq; if (quotactl(QCMD(Q_XGETQUOTA, USRQUOTA), device, getuid(), (caddr_t)&dq) == 0) @@ -420,24 +429,28 @@ static int64_t getxfsquota(char* device) else { /* No quota enabled for this user */ - return -1; + return disk_space; } freespace = limit - (dq.d_bcount >> 1); - return freespace < 0 ? 0 : (freespace * 1024); + freespace = freespace < 0 ? 0 : (freespace * 1024); + limit = limit * 1024; + disk_space.free = freespace; + disk_space.total = limit; + return disk_space; } /* something went wrong */ - return -1; + return disk_space; } #endif /* HAVE_XQM */ #endif /* _WIN32 */ -static int64_t tr_getQuotaFreeSpace([[maybe_unused]] struct tr_device_info const* info) +static struct tr_disk_space tr_getQuotaSpace([[maybe_unused]] struct tr_device_info const* info) { - int64_t ret = -1; + struct tr_disk_space ret = { -1, -1 }; #ifndef _WIN32 @@ -457,11 +470,11 @@ static int64_t tr_getQuotaFreeSpace([[maybe_unused]] struct tr_device_info const return ret; } -static int64_t tr_getDiskFreeSpace(char const* path) +static struct tr_disk_space tr_getDiskSpace(char const* path) { #ifdef _WIN32 - int64_t ret = -1; + struct tr_disk_space ret = { -1, -1 }; wchar_t* wide_path; wide_path = tr_win32_utf8_to_native(path, -1); @@ -469,10 +482,12 @@ static int64_t tr_getDiskFreeSpace(char const* path) if (wide_path != nullptr) { ULARGE_INTEGER freeBytesAvailable; + ULARGE_INTEGER totalBytesAvailable; - if (GetDiskFreeSpaceExW(wide_path, &freeBytesAvailable, nullptr, nullptr)) + if (GetDiskFreeSpaceExW(wide_path, &freeBytesAvailable, &totalBytesAvailable, nullptr)) { - ret = freeBytesAvailable.QuadPart; + ret.free = freeBytesAvailable.QuadPart; + ret.total = totalBytesAvailable.QuadPart; } tr_free(wide_path); @@ -483,13 +498,15 @@ static int64_t tr_getDiskFreeSpace(char const* path) #elif defined(HAVE_STATVFS) struct statvfs buf; - return statvfs(path, &buf) ? -1 : (int64_t)buf.f_bavail * (int64_t)buf.f_frsize; + return statvfs(path, &buf) ? + (struct tr_disk_space){ -1, -1 } : + (struct tr_disk_space){ (int64_t)buf.f_bavail * (int64_t)buf.f_frsize, (int64_t)buf.f_blocks * (int64_t)buf.f_frsize }; #else #warning FIXME: not implemented - return -1; + return { -1, -1 }; #endif } @@ -520,26 +537,27 @@ void tr_device_info_free(struct tr_device_info* info) } } -int64_t tr_device_info_get_free_space(struct tr_device_info const* info) +struct tr_disk_space tr_device_info_get_disk_space(struct tr_device_info const* info) { - int64_t free_space; + struct tr_disk_space space; if (info == nullptr || info->path == nullptr) { errno = EINVAL; - free_space = -1; + space.free = -1; + space.total = -1; } else { - free_space = tr_getQuotaFreeSpace(info); + space = tr_getQuotaSpace(info); - if (free_space < 0) + if (space.free < 0 || space.total < 0) { - free_space = tr_getDiskFreeSpace(info->path); + space = tr_getDiskSpace(info->path); } } - return free_space; + return space; } /*** diff --git a/libtransmission/platform-quota.h b/libtransmission/platform-quota.h index 83597c379..ce154e939 100644 --- a/libtransmission/platform-quota.h +++ b/libtransmission/platform-quota.h @@ -24,11 +24,18 @@ struct tr_device_info char* fstype; }; +struct tr_disk_space +{ + int64_t free; + int64_t total; +}; + struct tr_device_info* tr_device_info_create(char const* path); -/** If the disk quota is enabled and readable, this returns how much is available in the quota. - Otherwise, it returns how much is available on the disk, or -1 on error. */ -int64_t tr_device_info_get_free_space(struct tr_device_info const* info); +/** Values represents the total space on disk. + If the disk quota (free space) is enabled and readable, this returns how much is available in the quota. + Otherwise, it returns how much is available on the disk, or { -1, -1 } on error. */ +struct tr_disk_space tr_device_info_get_disk_space(struct tr_device_info const* info); void tr_device_info_free(struct tr_device_info* info); diff --git a/libtransmission/rpcimpl.cc b/libtransmission/rpcimpl.cc index 3f659d677..a305e1a95 100644 --- a/libtransmission/rpcimpl.cc +++ b/libtransmission/rpcimpl.cc @@ -26,7 +26,7 @@ #include "fdlimit.h" #include "file.h" #include "log.h" -#include "platform-quota.h" /* tr_device_info_get_free_space() */ +#include "platform-quota.h" /* tr_device_info_get_disk_space() */ #include "rpcimpl.h" #include "session.h" #include "session-id.h" @@ -2388,7 +2388,7 @@ static void addSessionField(tr_session* s, tr_variant* d, tr_quark key) break; case TR_KEY_download_dir_free_space: - tr_variantDictAddInt(d, key, tr_device_info_get_free_space(s->downloadDir)); + tr_variantDictAddInt(d, key, tr_device_info_get_disk_space(s->downloadDir).free); break; case TR_KEY_download_queue_enabled: @@ -2627,7 +2627,7 @@ static char const* freeSpace( int tmperr; char const* path = nullptr; char const* err = nullptr; - int64_t free_space = -1; + struct tr_disk_space dir_space = { -1, -1 }; if (!tr_variantDictFindStr(args_in, TR_KEY_path, &path, nullptr)) { @@ -2642,9 +2642,9 @@ static char const* freeSpace( /* get the free space */ tmperr = errno; errno = 0; - free_space = tr_sessionGetDirFreeSpace(session, path); + dir_space = tr_getDirSpace(path); - if (free_space < 0) + if (dir_space.free < 0 || dir_space.total < 0) { err = tr_strerror(errno); } @@ -2657,7 +2657,8 @@ static char const* freeSpace( tr_variantDictAddStr(args_out, TR_KEY_path, path); } - tr_variantDictAddInt(args_out, TR_KEY_size_bytes, free_space); + tr_variantDictAddInt(args_out, TR_KEY_size_bytes, dir_space.free); + tr_variantDictAddInt(args_out, TR_KEY_total_size, dir_space.total); return err; } diff --git a/libtransmission/session.cc b/libtransmission/session.cc index 4cb1eb395..2a1f26293 100644 --- a/libtransmission/session.cc +++ b/libtransmission/session.cc @@ -1232,11 +1232,11 @@ int64_t tr_sessionGetDirFreeSpace(tr_session* session, char const* dir) if (tr_strcmp0(dir, tr_sessionGetDownloadDir(session)) == 0) { - free_space = tr_device_info_get_free_space(session->downloadDir); + free_space = tr_device_info_get_disk_space(session->downloadDir).free; } else { - free_space = tr_getDirFreeSpace(dir); + free_space = tr_getDirSpace(dir).free; } return free_space; diff --git a/libtransmission/utils.cc b/libtransmission/utils.cc index 02a490ebb..3f98ab0c6 100644 --- a/libtransmission/utils.cc +++ b/libtransmission/utils.cc @@ -63,7 +63,7 @@ #include "mime-types.h" #include "net.h" #include "platform.h" /* tr_lockLock() */ -#include "platform-quota.h" /* tr_device_info_create(), tr_device_info_get_free_space(), tr_device_info_free() */ +#include "platform-quota.h" /* tr_device_info_create(), tr_device_info_get_disk_space(), tr_device_info_free() */ #include "tr-assert.h" #include "utils.h" #include "variant.h" @@ -390,24 +390,21 @@ char* tr_buildPath(char const* first_element, ...) return buf; } -int64_t tr_getDirFreeSpace(char const* dir) +struct tr_disk_space tr_getDirSpace(char const* dir) { - int64_t free_space; + struct tr_disk_space disk_space = { -1, -1 }; if (tr_str_is_empty(dir)) { errno = EINVAL; - free_space = -1; - } - else - { - struct tr_device_info* info; - info = tr_device_info_create(dir); - free_space = tr_device_info_get_free_space(info); - tr_device_info_free(info); + return disk_space; } - return free_space; + struct tr_device_info* info; + info = tr_device_info_create(dir); + disk_space = tr_device_info_get_disk_space(info); + tr_device_info_free(info); + return disk_space; } /**** diff --git a/libtransmission/utils.h b/libtransmission/utils.h index 2dc78339e..912185dd8 100644 --- a/libtransmission/utils.h +++ b/libtransmission/utils.h @@ -27,6 +27,8 @@ struct timeval; struct tr_error; +struct tr_disk_space; + /** * @addtogroup utils Utilities * @{ @@ -79,10 +81,10 @@ uint8_t* tr_loadFile(char const* filename, size_t* size, struct tr_error** error char* tr_buildPath(char const* first_element, ...) TR_GNUC_NULL_TERMINATED TR_GNUC_MALLOC; /** - * @brief Get available disk space (in bytes) for the specified folder. - * @return zero or positive integer on success, -1 in case of error. + * @brief Get disk capacity and free disk space (in bytes) for the specified folder. + * @return struct with free and total as zero or positive integer on success, -1 in case of error. */ -int64_t tr_getDirFreeSpace(char const* path); +struct tr_disk_space tr_getDirSpace(char const* path); /** * @brief Convenience wrapper around timer_add() to have a timer wake up in a number of seconds and microseconds