xiaoxiang781216 commented on code in PR #3665: URL: https://github.com/apache/nuttx-apps/pull/3665#discussion_r3653968526
########## system/xipfs/xipfs_main.c: ########## @@ -0,0 +1,579 @@ +/**************************************************************************** + * apps/system/xipfs/xipfs_main.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/ioctl.h> +#include <sys/statfs.h> + +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <nuttx/fs/ioctl.h> +#include <nuttx/fs/xipfs.h> + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define MAP_COLS 50 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* One row of the file table, gathered before anything is printed so that a + * failure part way through does not leave half a report behind. + */ + +struct xipfs_entry_s +{ + /* A path relative to the mountpoint, not one component, so that a file in + * a subdirectory is reported the way the volume names it. + */ + + char name[XIPFS_PATH_MAX + 1]; + uint32_t start; /* Relative to the data region */ + uint32_t nblocks; + uint32_t size; + uint32_t pincount; +}; + +struct xipfs_survey_s +{ + FAR char *map; /* One char per erase block */ + FAR struct xipfs_entry_s *files; + int nfiles; + uint32_t nblocks; /* Blocks in the data region */ + uint32_t blocksize; + uint32_t used; + uint32_t freeblocks; + uint32_t largestrun; + uint32_t nruns; /* Distinct free runs */ + uint32_t pinned; +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void show_usage(FAR const char *progname, int exitcode) +{ + fprintf(stderr, "USAGE: %s [-n] [-t <ms>] [<mountpoint>]\n", progname); + fprintf(stderr, "\nCompact a xipfs volume, or report what one looks " + "like.\n"); + fprintf(stderr, "\nWhere:\n"); + fprintf(stderr, "\t-n: Dry run. Report block usage and fragmentation " + "and exit\n"); + fprintf(stderr, "\t without moving anything.\n"); + fprintf(stderr, "\t-t <ms>: Time budget for the compaction pass. " + "0, the default,\n"); + fprintf(stderr, "\t means run to completion.\n"); + fprintf(stderr, "\t<mountpoint>: Default: %s\n", + CONFIG_SYSTEM_XIPFS_MOUNTPOINT); + exit(exitcode); +} + +/**************************************************************************** + * Name: survey_free + ****************************************************************************/ + +static void survey_free(FAR struct xipfs_survey_s *s) +{ + free(s->map); + free(s->files); + s->map = NULL; + s->files = NULL; +} + +/**************************************************************************** + * Name: survey_walk + * + * Description: + * Record where every file below 'dir' physically sits, descending into + * the directories xipfs synthesises from the names. 'rel' is the path of + * 'dir' relative to the mount, which is what a file is recorded under so + * that the table names it the way the volume does. + * + ****************************************************************************/ + +static int survey_walk(FAR const char *dir, FAR const char *rel, + FAR struct xipfs_survey_s *s, FAR int *capacity) +{ + struct xipfs_extent_info_s info; + FAR struct dirent *de; + FAR DIR *dirp; + uint32_t i; + int ret; + + dirp = opendir(dir); + if (dirp == NULL) + { + fprintf(stderr, "ERROR: opendir %s failed: %d\n", dir, errno); + return -errno; + } + + while ((de = readdir(dirp)) != NULL) + { + FAR struct xipfs_entry_s *e; + char path[PATH_MAX]; + char sub[XIPFS_PATH_MAX + 1]; + int fd; + + snprintf(path, sizeof(path), "%s/%s", dir, de->d_name); + + if (rel[0] == '\0') + { + strlcpy(sub, de->d_name, sizeof(sub)); + } + else + { + snprintf(sub, sizeof(sub), "%s/%s", rel, de->d_name); + } + + if (de->d_type == DTYPE_DIRECTORY) + { + ret = survey_walk(path, sub, s, capacity); + if (ret < 0) + { + closedir(dirp); + return ret; + } + + continue; + } + + fd = open(path, O_RDONLY); + if (fd < 0) + { + continue; + } + + ret = ioctl(fd, XIPFSIOC_EXTENTINFO, (unsigned long)(uintptr_t)&info); + close(fd); + + if (ret < 0) + { + continue; + } + + if (s->nfiles == *capacity) + { + FAR void *tmp; + + *capacity *= 2; + tmp = realloc(s->files, *capacity * sizeof(struct xipfs_entry_s)); + if (tmp == NULL) + { + closedir(dirp); + return -ENOMEM; + } + + s->files = tmp; + } + + e = &s->files[s->nfiles++]; + strlcpy(e->name, sub, sizeof(e->name)); + e->start = info.start_block - info.data_start; + e->nblocks = info.nblocks; + e->size = info.size; + e->pincount = info.pincount; + + if (e->pincount > 0) + { + s->pinned += e->nblocks; + } + + for (i = 0; i < e->nblocks; i++) + { + if (e->start + i < s->nblocks) + { + s->map[e->start + i] = e->pincount > 0 ? 'P' : '#'; + } + } + } + + closedir(dirp); + return OK; +} + +/**************************************************************************** + * Name: survey_collect + * + * Description: + * Walk the mount and record where every file physically sits. The block + * counts come from statfs so that an empty volume still reports its + * geometry -- XIPFSIOC_EXTENTINFO can only be issued against a regular + * file, so with no files there is nothing to ask. + * + ****************************************************************************/ + +static int survey_collect(FAR const char *mount, + FAR struct xipfs_survey_s *s) +{ + struct statfs sbuf; + uint32_t run = 0; + uint32_t i; + int capacity = 8; + int ret; + + memset(s, 0, sizeof(*s)); + + if (statfs(mount, &sbuf) < 0) + { + fprintf(stderr, "ERROR: statfs %s failed: %d\n", mount, errno); + return -errno; + } + + s->nblocks = sbuf.f_blocks; + s->blocksize = sbuf.f_bsize; + + if (s->nblocks == 0) + { + fprintf(stderr, "ERROR: %s reports no blocks; not a xipfs mount?\n", + mount); + return -EINVAL; + } + + s->map = malloc(s->nblocks); + if (s->map == NULL) + { + return -ENOMEM; + } + + memset(s->map, '.', s->nblocks); + + s->files = malloc(capacity * sizeof(struct xipfs_entry_s)); + if (s->files == NULL) + { + survey_free(s); + return -ENOMEM; + } + + ret = survey_walk(mount, "", s, &capacity); + if (ret < 0) + { + survey_free(s); + return ret; + } + + /* Reduce the map to the numbers a caller actually decides on: how much is + * free, and how much of that is reachable by a single allocation. + */ + + for (i = 0; i < s->nblocks; i++) + { + if (s->map[i] == '.') + { + s->freeblocks++; + if (run == 0) + { + s->nruns++; + } + + if (++run > s->largestrun) + { + s->largestrun = run; + } + } + else + { + s->used++; + run = 0; + } + } + + return OK; +} + +/**************************************************************************** + * Name: survey_report + ****************************************************************************/ + +static void survey_report(FAR const char *mount, + FAR struct xipfs_survey_s *s) +{ + uint32_t frag; + uint32_t i; + int width; + int f; + + printf("%s: %lu blocks of %lu bytes (%lu KB)\n", + mount, (unsigned long)s->nblocks, (unsigned long)s->blocksize, + (unsigned long)(s->nblocks * (uint64_t)s->blocksize / 1024)); + + if (s->nfiles > 0) + { + /* A name here is a path relative to the mountpoint, so it can be + * longer than one component. Widen the column to the longest one + * rather than let it push the rest of the row out of alignment. + */ + + width = XIPFS_NAME_MAX; + for (f = 0; f < s->nfiles; f++) + { + int len = (int)strlen(s->files[f].name); Review Comment: why not check type to size_t -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
