* Copyright (c) 2022 Huawei Technologies Co.,Ltd.
*
* DSS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
* -------------------------------------------------------------------------
*
* dsscmd_du.c
*
*
* IDENTIFICATION
* src/cmd/dsscmd_du.c
*
* -------------------------------------------------------------------------
*/
#include "dss_api_impl.h"
#include "dss_file.h"
#include "dss_cli_conn.h"
#define DSS_ARG_IDX_0 0
#define DSS_ARG_IDX_1 1
#define DSS_ARG_IDX_2 2
#define DSS_DU_SIZE_BUF_LEN 20
double dss_convert_size(double size, const char *measure);
status_t du_get_params(const char *input, char *params, size_t params_size)
{
if (input == NULL || input[0] == 0x00) {
params[DSS_ARG_IDX_0] = 'B';
params[DSS_ARG_IDX_1] = 's';
return CM_SUCCESS;
}
for (uint32 i = 0; i < strlen(input); i++) {
char c = input[i];
if (c == 'B' || c == 'K' || c == 'M' || c == 'G' || c == 'T') {
params[DSS_ARG_IDX_0] = c;
} else if (c == 's' || c == 'a') {
params[DSS_ARG_IDX_1] = c;
} else if (c == 'S') {
params[DSS_ARG_IDX_2] = (char)true;
} else {
DSS_PRINT_ERROR("wrong params %c.\n", c);
return CM_ERROR;
}
}
return CM_SUCCESS;
}
static void du_print(double size, const char *params, const char *path)
{
char buf[DSS_DU_SIZE_BUF_LEN] = {0};
size_t buf_size = sizeof(buf);
char *fmt = "%0.0lf%c";
if (params[DSS_ARG_IDX_0] == 'T' || params[DSS_ARG_IDX_0] == 'G') {
fmt = "%0.5lf%c";
}
if (sprintf_s(buf, buf_size, fmt, dss_convert_size(size, params), params[DSS_ARG_IDX_0]) == -1) {
cm_panic(0);
}
size_t buf_len = strlen(buf);
if (memset_s(buf + buf_len, buf_size - buf_len, ' ', buf_size - buf_len) != EOK) {
cm_panic(0);
}
buf[buf_size - 1] = 0;
(void)printf("%s%s\n", buf, path);
}
static double du_traverse_node(
dss_conn_t *conn, gft_node_t *node, dss_vg_info_item_t *vg_item, const char *params, char *path_prefix)
{
char granularity = params[DSS_ARG_IDX_1];
bool separate = (bool)params[DSS_ARG_IDX_2];
double total_size = 0;
size_t origin_len = strlen(path_prefix);
path_prefix[origin_len] = '/';
path_prefix[origin_len + 1] = 0;
text_t path_text, name_text;
cm_str2text(path_prefix, &path_text);
cm_str2text(node->name, &name_text);
cm_concat_text(&path_text, DSS_MAX_PATH_BUFFER_SIZE, &name_text);
if (node->type == GFT_PATH) {
gft_node_t *sub_node = dss_get_ft_node_by_ftid(conn->session, vg_item, node->items.first, CM_TRUE, CM_FALSE);
while (sub_node) {
if (sub_node->type != GFT_PATH || (sub_node->type == GFT_PATH && !separate)) {
double size = du_traverse_node(conn, sub_node, vg_item, params, path_prefix);
total_size += size;
} else if (sub_node->type == GFT_PATH) {
du_traverse_node(conn, sub_node, vg_item, params, path_prefix);
}
sub_node = dss_get_ft_node_by_ftid(conn->session, vg_item, sub_node->next, CM_TRUE, CM_FALSE);
}
if (granularity != 's') {
du_print(total_size, params, path_prefix + 1);
}
} else {
if (granularity == 'a') {
du_print(node->size, params, path_prefix + 1);
}
total_size = node->size;
}
errno_t errcode =
memset_s(path_prefix + origin_len, DSS_MAX_PATH_BUFFER_SIZE - origin_len, 0, strlen(node->name) + 1);
securec_check_ret(errcode);
return total_size;
}
static status_t du_try_print_link(dss_conn_t *conn, char *path, const char *params)
{
if (dss_is_valid_link_path(path)) {
gft_node_t *node = NULL;
dss_check_dir_output_t output_info = {&node, NULL, NULL, CM_FALSE};
DSS_RETURN_IF_ERROR(dss_check_dir(conn->session, path, GFT_LINK, &output_info, CM_FALSE));
if (node != NULL) {
du_print(node->size, params, path + 1);
return CM_SUCCESS;
}
}
LOG_DEBUG_INF("Failed to try print path %s with the link type", path);
return CM_ERROR;
}
status_t du_traverse_path(char *path, size_t path_size, dss_conn_t *conn, const char *params, size_t params_size)
{
bool32 exist = false;
gft_item_type_t type;
gft_node_t *node = NULL;
dss_vg_info_item_t *vg_item = NULL;
dss_check_dir_output_t output_info = {&node, NULL, NULL, CM_FALSE};
char name[DSS_MAX_NAME_LEN] = {0};
size_t len = strlen(path);
status_t status = CM_ERROR;
DSS_RETURN_IF_ERROR(dss_find_vg_by_dir(path, name, &vg_item));
DSS_RETURN_IF_ERROR(dss_exist_impl(conn, path, &exist, &type));
if (!exist) {
DSS_PRINT_ERROR("The path %s is not exist.\n", path);
return CM_ERROR;
}
if (type == GFT_FILE) {
DSS_LOCK_VG_META_S_RETURN_ERROR(vg_item, conn->session);
status = dss_check_dir(conn->session, path, GFT_FILE, &output_info, CM_FALSE);
if (status == CM_SUCCESS && node != NULL) {
du_print(node->size, params, path + 1);
DSS_UNLOCK_VG_META_S(vg_item, conn->session);
DSS_PRINT_INF("Succeed to du file info.\n");
return CM_SUCCESS;
}
DSS_UNLOCK_VG_META_S(vg_item, conn->session);
} else if (type == GFT_LINK || type == GFT_LINK_TO_FILE || type == GFT_LINK_TO_PATH) {
DSS_LOCK_VG_META_S_RETURN_ERROR(vg_item, conn->session);
status = du_try_print_link(conn, path, params);
DSS_UNLOCK_VG_META_S(vg_item, conn->session);
if (status == CM_SUCCESS) {
return status;
}
}
dss_dir_t *dir = dss_open_dir_impl(conn, path, CM_TRUE);
if (dir == NULL) {
DSS_PRINT_ERROR("Failed to open dir %s.\n", path);
return CM_ERROR;
}
if (SECUREC_UNLIKELY(dss_lock_vg_s(dir->vg_item, conn->session) != CM_SUCCESS)) {
(void)dss_close_dir_impl(conn, dir);
return CM_ERROR;
}
node = dss_get_ft_node_by_ftid(conn->session, dir->vg_item, dir->pftid, CM_FALSE, CM_FALSE);
if (node == NULL) {
DSS_THROW_ERROR(ERR_DSS_INVALID_ID, "dir ftid", *(uint64 *)&dir->pftid);
DSS_PRINT_ERROR("Failed to get ft node %s.\n", path);
DSS_UNLOCK_VG_META_S(dir->vg_item, conn->session);
(void)dss_close_dir_impl(conn, dir);
return CM_ERROR;
}
len = strlen(path);
while (len > 0 && path[len - 1] == '/') {
path[len - 1] = 0;
len--;
}
path[(len - strlen(node->name)) - 1] = 0;
double total_size = du_traverse_node(conn, node, dir->vg_item, params, path);
char granularity = params[DSS_ARG_IDX_1];
path[strlen(path)] = '/';
text_t path_text, name_text;
cm_str2text(path, &path_text);
cm_str2text(node->name, &name_text);
cm_concat_text(&path_text, (uint32)path_size, &name_text);
if (granularity == 's') {
du_print(total_size, params, path);
}
DSS_UNLOCK_VG_META_S(dir->vg_item, conn->session);
(void)dss_close_dir_impl(conn, dir);
return CM_SUCCESS;
}