Add total disk space to free-space RPC request (#1682)

* Add total space to free-space endpoint

* Update docs
This commit is contained in:
Johan 2021-10-14 20:07:16 +03:00 committed by GitHub
parent ab82e155be
commit 04f8b82308
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 89 additions and 62 deletions

View File

@ -679,10 +679,11 @@
Response arguments: Response arguments:
string | value type & description string | value type & description
------------+---------------------------------------------------------- -------------+----------------------------------------------------------
"path" | string same as the Request argument "path" | string same as the Request argument
"size-bytes"| number the size, in bytes, of the free space in that directory "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 5.0. Protocol Versions
@ -854,6 +855,7 @@
| | | session-get | new arg "script-torrent-added-filename" | | | session-get | new arg "script-torrent-added-filename"
| | | torrent-get | new arg "file-count" | | | torrent-get | new arg "file-count"
| | | torrent-get | new arg "primary-mime-type" | | | torrent-get | new arg "primary-mime-type"
| | | free-space | new return arg "total-capacity"
5.1. Upcoming Breakage 5.1. Upcoming Breakage

View File

@ -268,11 +268,12 @@ extern "C"
#include <quota.h> #include <quota.h>
} }
static int64_t getquota(char const* device) struct tr_disk_space getquota(char const* device)
{ {
struct quotahandle* qh; struct quotahandle* qh;
struct quotakey qk; struct quotakey qk;
struct quotaval qv; struct quotaval qv;
struct tr_disk_space disk_space = { -1, -1 };
int64_t limit; int64_t limit;
int64_t freespace; int64_t freespace;
int64_t spaceused; int64_t spaceused;
@ -281,7 +282,7 @@ static int64_t getquota(char const* device)
if (qh == nullptr) if (qh == nullptr)
{ {
return -1; return disk_space;
} }
qk.qk_idtype = QUOTA_IDTYPE_USER; qk.qk_idtype = QUOTA_IDTYPE_USER;
@ -291,7 +292,7 @@ static int64_t getquota(char const* device)
if (quota_get(qh, &qk, &qv) == -1) if (quota_get(qh, &qk, &qv) == -1)
{ {
quota_close(qh); quota_close(qh);
return -1; return disk_space;
} }
if (qv.qv_softlimit > 0) if (qv.qv_softlimit > 0)
@ -305,19 +306,21 @@ static int64_t getquota(char const* device)
else else
{ {
quota_close(qh); quota_close(qh);
return -1; return disk_space;
} }
spaceused = qv.qv_usage; spaceused = qv.qv_usage;
quota_close(qh); quota_close(qh);
freespace = limit - spaceused; freespace = limit - spaceused;
return freespace < 0 ? 0 : freespace; disk_space.free = freespace < 0 ? 0 : freespace;
disk_space.total = limit;
return disk_space;
} }
#else #else
static int64_t getquota(char const* device) static struct tr_disk_space getquota(char const* device)
{ {
#if defined(__DragonFly__) #if defined(__DragonFly__)
struct ufs_dqblk dq; struct ufs_dqblk dq;
@ -326,12 +329,13 @@ static int64_t getquota(char const* device)
#endif #endif
int64_t limit; int64_t limit;
int64_t freespace; int64_t freespace;
struct tr_disk_space disk_space = { -1, -1 };
int64_t spaceused; int64_t spaceused;
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__APPLE__) #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__APPLE__)
if (quotactl(device, QCMD(Q_GETQUOTA, USRQUOTA), getuid(), (caddr_t)&dq) != 0) if (quotactl(device, QCMD(Q_GETQUOTA, USRQUOTA), getuid(), (caddr_t)&dq) != 0)
{ {
return -1; return disk_space;
} }
#elif defined(__sun) #elif defined(__sun)
struct quotctl op; struct quotctl op;
@ -339,7 +343,7 @@ static int64_t getquota(char const* device)
if (fd < 0) if (fd < 0)
{ {
return -1; return disk_space;
} }
op.op = Q_GETQUOTA; op.op = Q_GETQUOTA;
@ -349,14 +353,14 @@ static int64_t getquota(char const* device)
if (ioctl(fd, Q_QUOTACTL, &op) != 0) if (ioctl(fd, Q_QUOTACTL, &op) != 0)
{ {
close(fd); close(fd);
return -1; return disk_space;
} }
close(fd); close(fd);
#else #else
if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device, getuid(), (caddr_t)&dq) != 0) if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device, getuid(), (caddr_t)&dq) != 0)
{ {
return -1; return disk_space;
} }
#endif #endif
@ -372,7 +376,7 @@ static int64_t getquota(char const* device)
else else
{ {
/* No quota enabled for this user */ /* No quota enabled for this user */
return -1; return disk_space;
} }
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
@ -390,9 +394,13 @@ static int64_t getquota(char const* device)
freespace = limit - spaceused; freespace = limit - spaceused;
#ifdef __APPLE__ #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 #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 #endif
} }
@ -400,10 +408,11 @@ static int64_t getquota(char const* device)
#ifdef HAVE_XQM #ifdef HAVE_XQM
static int64_t getxfsquota(char* device) static struct tr_disk_space getxfsquota(char* device)
{ {
int64_t limit; int64_t limit;
int64_t freespace; int64_t freespace;
struct tr_disk_space disk_space = { -1, -1 };
struct fs_disk_quota dq; struct fs_disk_quota dq;
if (quotactl(QCMD(Q_XGETQUOTA, USRQUOTA), device, getuid(), (caddr_t)&dq) == 0) if (quotactl(QCMD(Q_XGETQUOTA, USRQUOTA), device, getuid(), (caddr_t)&dq) == 0)
@ -420,24 +429,28 @@ static int64_t getxfsquota(char* device)
else else
{ {
/* No quota enabled for this user */ /* No quota enabled for this user */
return -1; return disk_space;
} }
freespace = limit - (dq.d_bcount >> 1); 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 */ /* something went wrong */
return -1; return disk_space;
} }
#endif /* HAVE_XQM */ #endif /* HAVE_XQM */
#endif /* _WIN32 */ #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 #ifndef _WIN32
@ -457,11 +470,11 @@ static int64_t tr_getQuotaFreeSpace([[maybe_unused]] struct tr_device_info const
return ret; return ret;
} }
static int64_t tr_getDiskFreeSpace(char const* path) static struct tr_disk_space tr_getDiskSpace(char const* path)
{ {
#ifdef _WIN32 #ifdef _WIN32
int64_t ret = -1; struct tr_disk_space ret = { -1, -1 };
wchar_t* wide_path; wchar_t* wide_path;
wide_path = tr_win32_utf8_to_native(path, -1); 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) if (wide_path != nullptr)
{ {
ULARGE_INTEGER freeBytesAvailable; 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); tr_free(wide_path);
@ -483,13 +498,15 @@ static int64_t tr_getDiskFreeSpace(char const* path)
#elif defined(HAVE_STATVFS) #elif defined(HAVE_STATVFS)
struct statvfs buf; 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 #else
#warning FIXME: not implemented #warning FIXME: not implemented
return -1; return { -1, -1 };
#endif #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) if (info == nullptr || info->path == nullptr)
{ {
errno = EINVAL; errno = EINVAL;
free_space = -1; space.free = -1;
space.total = -1;
} }
else 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;
} }
/*** /***

View File

@ -24,11 +24,18 @@ struct tr_device_info
char* fstype; char* fstype;
}; };
struct tr_disk_space
{
int64_t free;
int64_t total;
};
struct tr_device_info* tr_device_info_create(char const* path); 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. /** Values represents the total space on disk.
Otherwise, it returns how much is available on the disk, or -1 on error. */ If the disk quota (free space) is enabled and readable, this returns how much is available in the quota.
int64_t tr_device_info_get_free_space(struct tr_device_info const* info); 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); void tr_device_info_free(struct tr_device_info* info);

View File

@ -26,7 +26,7 @@
#include "fdlimit.h" #include "fdlimit.h"
#include "file.h" #include "file.h"
#include "log.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 "rpcimpl.h"
#include "session.h" #include "session.h"
#include "session-id.h" #include "session-id.h"
@ -2388,7 +2388,7 @@ static void addSessionField(tr_session* s, tr_variant* d, tr_quark key)
break; break;
case TR_KEY_download_dir_free_space: 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; break;
case TR_KEY_download_queue_enabled: case TR_KEY_download_queue_enabled:
@ -2627,7 +2627,7 @@ static char const* freeSpace(
int tmperr; int tmperr;
char const* path = nullptr; char const* path = nullptr;
char const* err = 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)) if (!tr_variantDictFindStr(args_in, TR_KEY_path, &path, nullptr))
{ {
@ -2642,9 +2642,9 @@ static char const* freeSpace(
/* get the free space */ /* get the free space */
tmperr = errno; tmperr = errno;
errno = 0; 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); err = tr_strerror(errno);
} }
@ -2657,7 +2657,8 @@ static char const* freeSpace(
tr_variantDictAddStr(args_out, TR_KEY_path, path); 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; return err;
} }

View File

@ -1232,11 +1232,11 @@ int64_t tr_sessionGetDirFreeSpace(tr_session* session, char const* dir)
if (tr_strcmp0(dir, tr_sessionGetDownloadDir(session)) == 0) 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 else
{ {
free_space = tr_getDirFreeSpace(dir); free_space = tr_getDirSpace(dir).free;
} }
return free_space; return free_space;

View File

@ -63,7 +63,7 @@
#include "mime-types.h" #include "mime-types.h"
#include "net.h" #include "net.h"
#include "platform.h" /* tr_lockLock() */ #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 "tr-assert.h"
#include "utils.h" #include "utils.h"
#include "variant.h" #include "variant.h"
@ -390,24 +390,21 @@ char* tr_buildPath(char const* first_element, ...)
return buf; 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)) if (tr_str_is_empty(dir))
{ {
errno = EINVAL; errno = EINVAL;
free_space = -1; return disk_space;
}
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 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;
} }
/**** /****

View File

@ -27,6 +27,8 @@ struct timeval;
struct tr_error; struct tr_error;
struct tr_disk_space;
/** /**
* @addtogroup utils Utilities * @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; 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. * @brief Get disk capacity and free disk space (in bytes) for the specified folder.
* @return zero or positive integer on success, -1 in case of error. * @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 * @brief Convenience wrapper around timer_add() to have a timer wake up in a number of seconds and microseconds