2 Star 0 Fork 0

mirrors_dlbeer/ufat

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
main.c 25.28 KB
一键复制 编辑 原始数据 按行查看 历史
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183
/* uFAT -- small flexible VFAT implementation
* Copyright (C) 2012 TracMap Holdings Ltd
*
* Author: Daniel Beer <dlbeer@gmail.com>, www.dlbeer.co.nz
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <getopt.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <sys/time.h>
#include "ufat.h"
struct command;
#define OPTION_STATISTICS 0x01
#define OPTION_RANDOMIZE 0x02
#define OPTION_MKFS 0x04
struct options {
int flags;
unsigned int log2_bs;
unsigned int seed;
ufat_block_t num_blocks;
const char *in_file;
const char *out_file;
const char *filename;
const struct command *command;
char **argv;
int argc;
};
struct command {
const char *name;
int (*func)(struct ufat *uf,
const struct options *opt);
};
struct file_device {
struct ufat_device base;
FILE *f;
int is_read_only;
};
static int file_device_read(const struct ufat_device *dev, ufat_block_t start,
ufat_block_t count, void *buffer)
{
struct file_device *f = (struct file_device *)dev;
if (fseek(f->f, start << f->base.log2_block_size, SEEK_SET) < 0) {
perror("file_device_read: fseek");
return -1;
}
if (fread(buffer, 1 << f->base.log2_block_size,
count, f->f) != count) {
if (feof(f->f)) {
memset(buffer, 0xcc,
(1 << f->base.log2_block_size) * count);
} else {
perror("file_device_read: fread");
return -1;
}
}
return 0;
}
static int file_device_write(const struct ufat_device *dev, ufat_block_t start,
ufat_block_t count, const void *buffer)
{
struct file_device *f = (struct file_device *)dev;
if (f->is_read_only) {
fprintf(stderr, "file_device_write: read-only device\n");
return -1;
}
if (fseek(f->f, start << f->base.log2_block_size, SEEK_SET) < 0) {
perror("file_device_write: fseek");
return -1;
}
if (fwrite(buffer, 1 << f->base.log2_block_size,
count, f->f) != count) {
perror("file_device_write: fwrite");
return -1;
}
return 0;
}
static int file_device_open(struct file_device *dev, const char *fname,
unsigned int log2_bs, int create)
{
dev->base.log2_block_size = log2_bs;
dev->base.read = file_device_read;
dev->base.write = file_device_write;
dev->is_read_only = 0;
if (create) {
dev->f = fopen(fname, "wb+");
} else {
dev->f = fopen(fname, "rb+");
if (!dev->f && errno == EACCES) {
dev->is_read_only = 1;
dev->f = fopen(fname, "rb");
}
}
if (!dev->f) {
perror("open");
return -1;
}
return 0;
}
static void file_device_close(struct file_device *dev)
{
fclose(dev->f);
}
static FILE *open_input(const char *fname)
{
FILE *in;
if (!fname)
return stdin;
in = fopen(fname, "rb");
if (!in) {
fprintf(stderr, "Failed to open %s for reading: %s\n",
fname, strerror(errno));
return NULL;
}
return in;
}
static void close_input(const char *fname, FILE *f)
{
if (fname)
fclose(f);
}
static FILE *open_output(const char *fname)
{
FILE *out;
if (!fname)
return stdout;
out = fopen(fname, "wb");
if (!out) {
fprintf(stderr, "Failed to open %s for writing: %s\n",
fname, strerror(errno));
return NULL;
}
return out;
}
static int close_output(const char *fname, FILE *f)
{
if (fname && fclose(f) < 0) {
fprintf(stderr, "Error on closing %s: %s\n",
fname, strerror(errno));
return -1;
}
return 0;
}
static void print_date(FILE *out, ufat_date_t d)
{
fprintf(out, "%04d-%02d-%02d",
UFAT_DATE_Y(d), UFAT_DATE_M(d), UFAT_DATE_D(d));
}
static void print_time(FILE *out, ufat_time_t t)
{
fprintf(out, "%2d:%02d:%02d",
UFAT_TIME_H(t), UFAT_TIME_M(t), UFAT_TIME_S(t));
}
static void print_attributes(FILE *out, ufat_attr_t a)
{
fprintf(out, "%c%c%c%c%c",
(a & UFAT_ATTR_ARCHIVE) ? 'A' : ' ',
(a & UFAT_ATTR_SYSTEM) ? 'S' : ' ',
(a & UFAT_ATTR_HIDDEN) ? 'H' : ' ',
(a & UFAT_ATTR_READONLY) ? 'R' : ' ',
(a & UFAT_ATTR_DIRECTORY) ? 'D' : ' ');
}
static int list_dir(FILE *out, struct ufat_directory *dir)
{
for (;;) {
struct ufat_dirent inf;
char lfn[UFAT_LFN_MAX_UTF8];
int err;
err = ufat_dir_read(dir, &inf, lfn, sizeof(lfn));
if (err < 0) {
fprintf(stderr, "list_dir: ufat_dir_read: %s\n",
ufat_strerror(err));
return err;
}
if (err)
break;
print_date(out, inf.modify_date);
fprintf(out, " ");
print_time(out, inf.modify_time);
fprintf(out, " ");
print_attributes(out, inf.attributes & ~UFAT_ATTR_DIRECTORY);
if (inf.attributes & UFAT_ATTR_DIRECTORY)
fprintf(out, " %9s", "<DIR>");
else
fprintf(out, " %9u", inf.file_size);
fprintf(out, " %s\n", lfn);
}
return 0;
}
static int find_path(struct ufat *uf,
struct ufat_directory *dir, const char *path,
struct ufat_dirent *inf, const char **path_out)
{
int err;
ufat_open_root(uf, dir);
err = ufat_dir_find_path(dir, path, inf, path_out);
if (err < 0)
fprintf(stderr, "ufat_dir_find_path: %s\n",
ufat_strerror(err));
return err;
}
static int require_file(struct ufat *uf, const char *path,
struct ufat_dirent *ent)
{
struct ufat_directory dir;
int err = find_path(uf, &dir, path, ent, NULL);
if (err < 0)
return err;
if (err) {
fprintf(stderr, "No such file or directory: %s\n", path);
return -1;
}
return 0;
}
static int cmd_dir(struct ufat *uf, const struct options *opt)
{
struct ufat_directory dir;
FILE *out;
if (opt->argc) {
struct ufat_dirent ent;
int err;
if (require_file(uf, opt->argv[0], &ent) < 0)
return -1;
err = ufat_open_subdir(uf, &dir, &ent);
if (err < 0) {
fprintf(stderr, "ufat_open_subdir: %s\n",
ufat_strerror(err));
return -1;
}
} else {
ufat_open_root(uf, &dir);
}
out = open_output(opt->out_file);
if (!out)
return -1;
if (list_dir(out, &dir) < 0) {
close_output(opt->out_file, out);
return -1;
}
return close_output(opt->out_file, out);
}
static int cmd_fstat(struct ufat *uf, const struct options *opt)
{
FILE *out;
struct ufat_dirent ent;
char can_name[UFAT_LFN_MAX_UTF8];
int err;
if (!opt->argc) {
fprintf(stderr, "You must specify a file path\n");
return -1;
}
if (require_file(uf, opt->argv[0], &ent) < 0)
return -1;
out = open_output(opt->out_file);
if (!out)
return -1;
err = ufat_get_filename(uf, &ent, can_name, sizeof(can_name));
if (err < 0)
fprintf(stderr, "ufat_get_filename: %s\n",
ufat_strerror(err));
else
fprintf(out, "Filename: %s\n", can_name);
fprintf(out, "Entry block/offset: %llu/%d\n",
ent.dirent_block, ent.dirent_pos);
if (ent.lfn_block != UFAT_BLOCK_NONE)
fprintf(out, "LFN start block/offset: %llu/%d\n",
ent.lfn_block, ent.lfn_pos);
fprintf(out, "Short name: %s", ent.short_name);
if (ent.short_ext[0])
fprintf(out, ".%s\n", ent.short_ext);
else
fprintf(out, "\n");
fprintf(out, "Attributes: 0x%02x (", ent.attributes);
print_attributes(out, ent.attributes);
fprintf(out, ")\n");
fprintf(out, "Creation date/time: ");
print_date(out, ent.create_date);
fprintf(out, " ");
print_time(out, ent.create_time);
fprintf(out, "\n");
fprintf(out, "Modification date/time: ");
print_date(out, ent.modify_date);
fprintf(out, " ");
print_time(out, ent.modify_time);
fprintf(out, "\n");
fprintf(out, "Last access date: ");
print_date(out, ent.access_date);
fprintf(out, "\n");
fprintf(out, "First cluster: %u\n", ent.first_cluster);
fprintf(out, "Size: %u\n", ent.file_size);
return close_output(opt->out_file, out);
}
static int cmd_read(struct ufat *uf, const struct options *opt)
{
FILE *out;
struct ufat_dirent ent;
struct ufat_file file;
int err;
if (!opt->argc) {
fprintf(stderr, "You must specify a file path\n");
return -1;
}
if (require_file(uf, opt->argv[0], &ent) < 0)
return -1;
err = ufat_open_file(uf, &file, &ent);
if (err < 0) {
fprintf(stderr, "ufat_open_file: %s\n", ufat_strerror(err));
return -1;
}
out = open_output(opt->out_file);
if (!out)
return -1;
for (;;) {
char buf[16384];
int req_size = sizeof(buf);
int len;
if (opt->flags & OPTION_RANDOMIZE)
req_size = random() % sizeof(buf) + 1;
len = ufat_file_read(&file, buf, req_size);
if (len < 0) {
fprintf(stderr, "ufat_file_read: %s\n",
ufat_strerror(len));
close_output(opt->out_file, out);
return -1;
}
if (!len)
break;
if (fwrite(buf, 1, len, out) != (size_t)len) {
perror("fwrite");
close_output(opt->out_file, out);
return -1;
}
}
return close_output(opt->out_file, out);
}
static int cmd_write(struct ufat *uf, const struct options *opt)
{
FILE *in;
const char *basename;
struct ufat_directory dir;
struct ufat_dirent ent;
struct ufat_file file;
int err;
if (!opt->argc) {
fprintf(stderr, "You must specify a file path\n");
return -1;
}
err = find_path(uf, &dir, opt->argv[0], &ent, &basename);
if (err < 0)
return -1;
in = open_input(opt->in_file);
if (!in)
return -1;
if (err) {
time_t now = time(NULL);
struct tm *local = localtime(&now);
ent.attributes = 0;
ent.create_date = UFAT_DATE(local->tm_year + 1900,
local->tm_mon + 1,
local->tm_mday);
ent.create_time = UFAT_TIME(local->tm_hour,
local->tm_min,
local->tm_sec);
ent.modify_date = ent.create_date;
ent.modify_time = ent.create_time;
ent.access_date = ent.create_date;
err = ufat_dir_mkfile(&dir, &ent, basename);
if (err < 0) {
fprintf(stderr, "Failed to create file: %s: %s\n",
basename, ufat_strerror(err));
close_input(opt->in_file, in);
return -1;
}
}
err = ufat_open_file(uf, &file, &ent);
if (err < 0) {
fprintf(stderr, "ufat_open_file: %s\n", ufat_strerror(err));
close_input(opt->in_file, in);
return -1;
}
for (;;) {
char buf[16384];
int req_size = sizeof(buf);
int len;
if (opt->flags & OPTION_RANDOMIZE)
req_size = random() % sizeof(buf) + 1;
len = fread(buf, 1, req_size, in);
if (ferror(stdin)) {
perror("fread");
close_input(opt->in_file, in);
return -1;
}
if (!len)
break;
len = ufat_file_write(&file, buf, len);
if (len < 0) {
fprintf(stderr, "ufat_file_write: %s\n",
ufat_strerror(len));
close_input(opt->in_file, in);
return -1;
}
}
err = ufat_file_truncate(&file);
if (err < 0) {
fprintf(stderr, "ufat_file_truncate: %s\n",
ufat_strerror(err));
close_input(opt->in_file, in);
return -1;
}
close_input(opt->in_file, in);
return 0;
}
static int cmd_rm(struct ufat *uf, const struct options *opt)
{
struct ufat_dirent ent;
int err;
if (!opt->argc) {
fprintf(stderr, "You must specify a file path\n");
return -1;
}
if (require_file(uf, opt->argv[0], &ent) < 0)
return -1;
err = ufat_dir_delete(uf, &ent);
if (err < 0) {
fprintf(stderr, "ufat_dir_delete: %s\n", ufat_strerror(err));
return -1;
}
return 0;
}
static int cmd_mkdir(struct ufat *uf, const struct options *opt)
{
const char *basename;
struct ufat_directory dir;
struct ufat_dirent ent;
struct tm *local;
time_t now = time(NULL);
int err;
if (!opt->argc) {
fprintf(stderr, "You must specify a file path\n");
return -1;
}
err = find_path(uf, &dir, opt->argv[0], &ent, &basename);
if (err < 0)
return -1;
if (!err) {
fprintf(stderr, "Path already exists: %s\n",
opt->argv[0]);
return -1;
}
local = localtime(&now);
ent.attributes = 0;
ent.create_date = UFAT_DATE(local->tm_year + 1900, local->tm_mon + 1,
local->tm_mday);
ent.create_time = UFAT_TIME(local->tm_hour, local->tm_min,
local->tm_sec);
ent.modify_date = ent.create_date;
ent.modify_time = ent.create_time;
ent.access_date = ent.create_date;
err = ufat_dir_create(&dir, &ent, basename);
if (err < 0) {
fprintf(stderr, "ufat_dir_create: %s\n", ufat_strerror(err));
return -1;
}
return 0;
}
static int parse_dosattr(const char *attr, ufat_attr_t *a)
{
ufat_attr_t out = 0;
while (*attr) {
switch (*attr) {
case 'A':
case 'a':
out |= UFAT_ATTR_ARCHIVE;
break;
case 'H':
case 'h':
out |= UFAT_ATTR_HIDDEN;
break;
case 'R':
case 'r':
out |= UFAT_ATTR_READONLY;
break;
case 'S':
case 's':
out |= UFAT_ATTR_SYSTEM;
break;
default:
fprintf(stderr, "Unrecognized DOS attribute: %c\n",
*attr);
return -1;
}
attr++;
}
*a = out;
return 0;
}
static int parse_date(const char *text, ufat_date_t *d)
{
int bits[3] = {0};
int b = 0;
int i;
if (!strcasecmp(text, "now")) {
time_t now = time(NULL);
struct tm *local = localtime(&now);
*d = UFAT_DATE(local->tm_year + 1900,
local->tm_mon + 1,
local->tm_mday);
return 0;
}
for (i = 0; text[i]; i++) {
const int c = text[i];
if (c == '-') {
b++;
if (b >= 3)
goto bad_format;
} else if (isdigit(c)) {
bits[b] = bits[b] * 10 + c - '0';
} else {
goto bad_format;
}
}
if (b < 2)
goto bad_format;
*d = UFAT_DATE(bits[0], bits[1], bits[2]);
return 0;
bad_format:
fprintf(stderr, "Date must be of the form YYYY-MM-DD: %s\n", text);
return -1;
}
static int parse_time(const char *text, ufat_time_t *t)
{
int bits[3] = {0};
int b = 0;
int i;
if (!strcasecmp(text, "now")) {
time_t now = time(NULL);
struct tm *local = localtime(&now);
*t = UFAT_TIME(local->tm_hour,
local->tm_min,
local->tm_sec);
return 0;
}
for (i = 0; text[i]; i++) {
const int c = text[i];
if (c == ':') {
b++;
if (b >= 3)
goto bad_format;
} else if (isdigit(c)) {
bits[b] = bits[b] * 10 + c - '0';
} else {
goto bad_format;
}
}
if (b < 2)
goto bad_format;
*t = UFAT_TIME(bits[0], bits[1], bits[2]);
return 0;
bad_format:
fprintf(stderr, "Time must be of the form HH:MM:SS: %s\n",
text);
return -1;
}
static int parse_attribute(const char *spec, struct ufat_dirent *ent)
{
char key[64];
char *value;
if (*spec == '+' || *spec == '~' || *spec == '=') {
ufat_attr_t a;
if (parse_dosattr(spec + 1, &a) < 0)
return -1;
if (*spec == '+')
ent->attributes |= a;
else if (*spec == '=')
ent->attributes = a;
else
ent->attributes &= ~a;
return 0;
}
/* Try to identify a key=value pair */
strncpy(key, spec, sizeof(key));
key[sizeof(key) - 1] = 0;
value = strchr(key, '=');
if (!value) {
fprintf(stderr, "Unknown attribute specification: %s\n",
spec);
return -1;
}
*(value++) = 0;
/* Deal with it */
if (!strcasecmp(key, "create_date"))
return parse_date(value, &ent->create_date);
if (!strcasecmp(key, "create_time"))
return parse_time(value, &ent->create_time);
if (!strcasecmp(key, "modify_date"))
return parse_date(value, &ent->modify_date);
if (!strcasecmp(key, "modify_time"))
return parse_time(value, &ent->modify_time);
if (!strcasecmp(key, "access_date"))
return parse_date(value, &ent->access_date);
fprintf(stderr, "Unknown attribute: %s\n", key);
return -1;
}
static int cmd_rename(struct ufat *uf, const struct options *opt)
{
struct ufat_directory dir;
struct ufat_dirent ent;
int err;
const char *src_path;
const char *dst_name;
if (opt->argc < 2) {
fprintf(stderr, "You must specified a source path and "
"a new name.\n");
return -1;
}
src_path = opt->argv[0];
dst_name = opt->argv[1];
err = find_path(uf, &dir, src_path, &ent, NULL);
if (err < 0)
return -1;
if (err) {
fprintf(stderr, "No such file or directory: %s\n",
ufat_strerror(err));
return -1;
}
err = ufat_move(&ent, &dir, dst_name);
if (err < 0) {
fprintf(stderr, "ufat_move: %s\n", ufat_strerror(err));
return -1;
}
return 0;
}
static int cmd_move(struct ufat *uf, const struct options *opt)
{
struct ufat_directory dir;
struct ufat_dirent src_ent;
struct ufat_dirent dst_ent;
int err;
const char *src_path;
const char *dst_path;
const char *new_name;
char old_name[UFAT_LFN_MAX_UTF8];
if (opt->argc < 2) {
fprintf(stderr, "You must specified a source path and "
"a destination path.\n");
return -1;
}
src_path = opt->argv[0];
dst_path = opt->argv[1];
err = find_path(uf, &dir, src_path, &src_ent, NULL);
if (err < 0)
return -1;
if (err) {
fprintf(stderr, "No such file or directory: %s\n",
opt->argv[0]);
return -1;
}
ufat_open_root(uf, &dir);
err = ufat_dir_find_path(&dir, dst_path, &dst_ent, &new_name);
if (err < 0) {
fprintf(stderr, "ufat_dir_find_path: %s\n",
ufat_strerror(err));
return -1;
}
if (!err) {
/* Is the destination a directory or an existing file? */
if (!(dst_ent.attributes & UFAT_ATTR_DIRECTORY)) {
fprintf(stderr, "File already exists: %s\n",
dst_path);
return -1;
}
/* It's a directory name. Use the old canonical filename. */
err = ufat_open_subdir(uf, &dir, &dst_ent);
if (err < 0) {
fprintf(stderr, "ufat_open_subdir: %s\n",
ufat_strerror(err));
return -1;
}
err = ufat_get_filename(uf, &src_ent,
old_name, sizeof(old_name));
if (err < 0) {
fprintf(stderr, "ufat_get_filename: %s\n",
ufat_strerror(err));
return -1;
}
new_name = old_name;
}
err = ufat_move(&src_ent, &dir, new_name);
if (err < 0) {
fprintf(stderr, "ufat_move: %s\n", ufat_strerror(err));
return -1;
}
return 0;
}
static int cmd_chattr(struct ufat *uf, const struct options *opt)
{
struct ufat_dirent ent;
int err;
int i;
if (!opt->argc) {
fprintf(stderr, "You must specify a file path\n");
return -1;
}
if (require_file(uf, opt->argv[0], &ent) < 0)
return -1;
for (i = 1; i < opt->argc; i++)
if (parse_attribute(opt->argv[i], &ent) < 0)
return -1;
err = ufat_update_attributes(uf, &ent);
if (err < 0) {
fprintf(stderr, "ufat_dir_update_attributes: %s\n",
ufat_strerror(err));
return -1;
}
return 0;
}
static void show_info(FILE *out, const struct ufat_bpb *bpb)
{
fprintf(out, "Type: FAT%d\n", bpb->type);
fprintf(out, "Blocks per cluster: %u\n",
1 << bpb->log2_blocks_per_cluster);
fprintf(out, "FAT size (blocks): %llu\n", bpb->fat_size);
fprintf(out, "FAT offset (block): %llu\n", bpb->fat_start);
fprintf(out, "FAT count: %u\n", bpb->fat_count);
fprintf(out, "Cluster starting block: %llu\n", bpb->cluster_start);
fprintf(out, "Clusters: %u\n", bpb->num_clusters);
fprintf(out, "Root directory block start: %llu\n", bpb->root_start);
fprintf(out, "Root directory block count: %llu\n", bpb->root_size);
fprintf(out, "Root directory cluster: %u\n", bpb->root_cluster);
}
static void usage(const char *progname)
{
printf(
"Usage: %s [options] <image file> [command [args]]\n"
"\n"
"Options may be any of the following:\n"
" -b block-size Set the simulated block size\n"
" -S Show performance statistics\n"
" -R seed Randomize file IO request sizes\n"
" -i filename Read input from the given file\n"
" -o filename Write output to the given file\n"
" --mkfs <num blocks> Initialize the filesystem (WARNING: all existing\n"
" data will be lost)\n"
" --help Show this text\n"
" --version Show version information\n"
"\n"
"With no command, basic information is printed. Available commands are:\n"
" dir [directory] Show a directory listing\n"
" fstat [path] Show directory entry details\n"
" read [file] Dump the contents of the given file\n"
" write [file] Write to a file\n"
" rm [path] Remove a directory or file\n"
" mkdir [directory] Create a new empty directory\n"
" chattr [path] [attributes]\n"
" Alter file attributes/dates/times (see below)\n"
" move [src] [dst] Move a file from one place to another\n"
" rename [src] [new-name] Rename a file without moving it\n"
"\n"
"Attributes are specified using arguments with a key=value syntax:\n"
" create_date=YYYY-MM-DD Creation date\n"
" create_time=HH:MM:SS Creation time\n"
" modify_date=YYYY-MM-DD Modification date\n"
" modify_time=HH:MM:SS Modification time\n"
" access_date=YYYY-MM-DD Access date\n"
" [+/~/=]AHRS Alter archive/hidden/read-only/system\n"
"\n"
"The special value \"now\" can be used for either dates or times.\n",
progname);
}
static void version_banner(void)
{
printf(
"ufat version 20120528\n"
"Copyright (C) 2012 TracMap Holdings Ltd\n"
"This is free software; see the source for copying conditions. There is NO\n"
"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
);
}
static int parse_blocksize(const char *arg, unsigned int *out)
{
unsigned int target = atoi(arg);
unsigned int c = 0;
if (!target) {
fprintf(stderr, "Block size must be greater than 0\n");
return -1;
}
while (target > 1) {
if (target & 1) {
fprintf(stderr, "Block size must be a power of 2\n");
return -1;
}
target >>= 1;
c++;
}
*out = c;
return 0;
}
static const struct command command_table[] = {
{"dir", cmd_dir},
{"fstat", cmd_fstat},
{"read", cmd_read},
{"write", cmd_write},
{"rm", cmd_rm},
{"mkdir", cmd_mkdir},
{"chattr", cmd_chattr},
{"move", cmd_move},
{"rename", cmd_rename}
};
static const struct command *find_command(const char *name)
{
size_t i;
for (i = 0; i < sizeof(command_table) /
sizeof(command_table[0]); i++) {
const struct command *c = &command_table[i];
if (!strcasecmp(c->name, name))
return c;
}
return NULL;
}
static int parse_options(int argc, char **argv, struct options *opt)
{
static const struct option longopts[] = {
{"help", 0, 0, 'H'},
{"version", 0, 0, 'V'},
{"mkfs", 1, 0, 'M'},
{NULL, 0, 0, 0}
};
int o;
memset(opt, 0, sizeof(*opt));
opt->log2_bs = 9;
while ((o = getopt_long(argc, argv, "b:SR:i:o:", longopts, NULL)) >= 0)
switch (o) {
case 'i':
opt->in_file = optarg;
break;
case 'o':
opt->out_file = optarg;
break;
case 'M':
opt->flags |= OPTION_MKFS;
opt->num_blocks = atoll(optarg);
break;
case 'R':
opt->flags |= OPTION_RANDOMIZE;
opt->seed = atoi(optarg);
break;
case 'S':
opt->flags |= OPTION_STATISTICS;
break;
case 'H':
usage(argv[0]);
exit(0);
case 'V':
version_banner();
exit(0);
case 'b':
if (parse_blocksize(optarg, &opt->log2_bs) < 0)
return -1;
break;
case '?':
fprintf(stderr, "Try --help for usage.\n");
return -1;
}
argc -= optind;
argv += optind;
if (argc <= 0) {
fprintf(stderr, "Expected an image name\n");
return -1;
}
opt->filename = argv[0];
if (argc >= 2) {
opt->command = find_command(argv[1]);
opt->argv = argv + 2;
opt->argc = argc - 2;
if (!opt->command) {
fprintf(stderr, "Unknown command: %s\n", argv[1]);
return -1;
}
} else {
opt->command = NULL;
opt->argv = NULL;
opt->argc = 0;
}
return 0;
}
static void dump_stats(const struct ufat_stat *st)
{
fprintf(stderr, "\n");
fprintf(stderr,
"Reads: %6d comprising %6d blocks\n",
st->read, st->read_blocks);
fprintf(stderr,
"Writes: %6d comprising %6d blocks\n",
st->write, st->write_blocks);
fprintf(stderr, "Cache write/flush: %6d/%6d\n",
st->cache_write, st->cache_flush);
fprintf(stderr, "Cache hit/miss: %6d/%6d",
st->cache_hit, st->cache_miss);
if (st->cache_hit + st->cache_miss)
fprintf(stderr, " (%02d%% hit rate)\n",
st->cache_hit * 100 / (st->cache_hit + st->cache_miss));
else
fprintf(stderr, "\n");
}
int main(int argc, char **argv)
{
struct file_device dev;
struct ufat uf;
struct options opt;
int err;
if (parse_options(argc, argv, &opt) < 0)
return -1;
srandom(opt.seed);
if (file_device_open(&dev, opt.filename, opt.log2_bs,
opt.flags & OPTION_MKFS) < 0)
return -1;
if (opt.flags & OPTION_MKFS) {
err = ufat_mkfs(&dev.base, opt.num_blocks);
if (err < 0) {
fprintf(stderr, "ufat_mkfs: %s\n", ufat_strerror(err));
file_device_close(&dev);
return -1;
}
}
err = ufat_open(&uf, &dev.base);
if (err) {
fprintf(stderr, "ufat_open: %s\n", ufat_strerror(err));
file_device_close(&dev);
return -1;
}
if (!opt.command) {
FILE *out = open_output(opt.out_file);
if (!out) {
err = -1;
} else {
show_info(out, &uf.bpb);
err = close_output(opt.out_file, out);
}
} else {
err = opt.command->func(&uf, &opt);
}
ufat_close(&uf);
file_device_close(&dev);
if (opt.flags & OPTION_STATISTICS)
dump_stats(&uf.stat);
return err;
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/mirrors_dlbeer/ufat.git
git@gitee.com:mirrors_dlbeer/ufat.git
mirrors_dlbeer
ufat
ufat
master

搜索帮助

0d507c66 1850385 C8b1a773 1850385