2017-10-18 22:19:53 +02:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include <stdint.h>
|
2018-05-14 09:54:05 +02:00
|
|
|
#include <inttypes.h>
|
2019-10-30 22:54:12 +01:00
|
|
|
#include <limits.h>
|
2018-04-23 12:09:46 +02:00
|
|
|
#include <stdlib.h>
|
2019-10-21 04:51:56 +02:00
|
|
|
#include <stddef.h>
|
2017-11-02 21:41:11 +01:00
|
|
|
#include <string.h>
|
2018-04-26 15:07:34 +02:00
|
|
|
#include <unistd.h>
|
2017-10-18 22:19:53 +02:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <fcntl.h>
|
2018-06-18 03:55:51 +02:00
|
|
|
#include <assert.h>
|
2019-10-31 21:26:53 +01:00
|
|
|
#include <time.h>
|
2018-05-09 23:08:52 +02:00
|
|
|
#include "kolibri.h"
|
2019-10-09 01:35:47 +02:00
|
|
|
#include "trace.h"
|
2017-10-18 22:19:53 +02:00
|
|
|
|
2019-10-25 03:48:13 +02:00
|
|
|
#define PATH_MAX 4096
|
2018-04-26 11:17:55 +02:00
|
|
|
#define FGETS_BUF_LEN 4096
|
|
|
|
#define MAX_COMMAND_ARGS 42
|
2018-06-18 03:55:51 +02:00
|
|
|
#define PRINT_BYTES_PER_LINE 32
|
|
|
|
#define MAX_DIRENTS_TO_READ 100
|
2019-10-21 04:51:56 +02:00
|
|
|
#define MAX_BYTES_TO_READ (16*1024)
|
2018-04-26 11:17:55 +02:00
|
|
|
|
2019-12-08 02:32:07 +01:00
|
|
|
#define DEFAULT_PATH_ENCODING UTF8
|
|
|
|
|
2019-10-25 03:48:13 +02:00
|
|
|
char cur_dir[PATH_MAX] = "/";
|
|
|
|
const char *last_dir = cur_dir;
|
|
|
|
bool cur_dir_changed = true;
|
|
|
|
|
2018-04-26 11:17:55 +02:00
|
|
|
char cmd_buf[FGETS_BUF_LEN];
|
2019-10-30 22:54:12 +01:00
|
|
|
int trace = false;
|
2018-04-26 11:17:55 +02:00
|
|
|
|
2019-10-25 03:48:13 +02:00
|
|
|
const char *f70_status_name[] = {
|
|
|
|
"success",
|
|
|
|
"disk_base",
|
|
|
|
"unsupported_fs",
|
|
|
|
"unknown_fs",
|
|
|
|
"partition",
|
|
|
|
"file_not_found",
|
|
|
|
"end_of_file",
|
|
|
|
"memory_pointer",
|
|
|
|
"disk_full",
|
|
|
|
"fs_fail",
|
|
|
|
"access_denied",
|
|
|
|
"device",
|
|
|
|
"out_of_memory"
|
|
|
|
};
|
|
|
|
|
2019-12-08 02:32:07 +01:00
|
|
|
const char *get_f70_status_name(f70status_t s) {
|
2019-10-25 03:48:13 +02:00
|
|
|
switch (s) {
|
2019-12-08 02:32:07 +01:00
|
|
|
case ERROR_SUCCESS:
|
2019-10-27 02:54:38 +02:00
|
|
|
// return "";
|
2019-12-08 02:32:07 +01:00
|
|
|
case ERROR_DISK_BASE:
|
|
|
|
case ERROR_UNSUPPORTED_FS:
|
|
|
|
case ERROR_UNKNOWN_FS:
|
|
|
|
case ERROR_PARTITION:
|
|
|
|
case ERROR_FILE_NOT_FOUND:
|
|
|
|
case ERROR_END_OF_FILE:
|
|
|
|
case ERROR_MEMORY_POINTER:
|
|
|
|
case ERROR_DISK_FULL:
|
|
|
|
case ERROR_FS_FAIL:
|
|
|
|
case ERROR_ACCESS_DENIED:
|
|
|
|
case ERROR_DEVICE:
|
|
|
|
case ERROR_OUT_OF_MEMORY:
|
2019-10-25 03:48:13 +02:00
|
|
|
return f70_status_name[s];
|
|
|
|
default:
|
|
|
|
return "unknown";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-07 00:51:55 +01:00
|
|
|
void convert_f70_file_attr(uint32_t attr, char s[KF_ATTR_CNT+1]) {
|
|
|
|
s[0] = (attr & KF_READONLY) ? 'r' : '-';
|
|
|
|
s[1] = (attr & KF_HIDDEN) ? 'h' : '-';
|
|
|
|
s[2] = (attr & KF_SYSTEM) ? 's' : '-';
|
|
|
|
s[3] = (attr & KF_LABEL) ? 'l' : '-';
|
|
|
|
s[4] = (attr & KF_FOLDER) ? 'f' : '-';
|
|
|
|
s[5] = '\0';
|
|
|
|
}
|
|
|
|
|
2019-12-08 02:32:07 +01:00
|
|
|
void print_f70_status(f7080ret_t *r, int use_ebx) {
|
2019-10-27 02:54:38 +02:00
|
|
|
printf("status = %d %s", r->status, get_f70_status_name(r->status));
|
2019-12-08 02:32:07 +01:00
|
|
|
if (use_ebx && (r->status == ERROR_SUCCESS || r->status == ERROR_END_OF_FILE))
|
2019-10-25 03:48:13 +02:00
|
|
|
printf(", count = %d", r->count);
|
|
|
|
putchar('\n');
|
|
|
|
}
|
|
|
|
|
2019-10-21 04:51:56 +02:00
|
|
|
bool parse_uintmax(const char *str, uintmax_t *res) {
|
|
|
|
char *endptr;
|
|
|
|
*res = strtoumax(str, &endptr, 0);
|
|
|
|
bool ok = (str != endptr) && (*endptr == '\0');
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool parse_uint32(const char *str, uint32_t *res) {
|
|
|
|
uintmax_t x;
|
|
|
|
if (parse_uintmax(str, &x) && x <= UINT32_MAX) {
|
2019-10-22 04:24:44 +02:00
|
|
|
*res = (uint32_t)x;
|
2019-10-21 04:51:56 +02:00
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
perror("invalid number");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool parse_uint64(const char *str, uint64_t *res) {
|
|
|
|
uintmax_t x;
|
|
|
|
if (parse_uintmax(str, &x) && x <= UINT64_MAX) {
|
|
|
|
*res = x;
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
perror("invalid number");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void print_bytes(uint8_t *x, size_t len) {
|
|
|
|
for (size_t i = 0; i < len; i++) {
|
|
|
|
if (i % PRINT_BYTES_PER_LINE == 0 && i != 0) {
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
printf("%2.2x", x[i]);
|
|
|
|
}
|
|
|
|
putchar('\n');
|
|
|
|
}
|
|
|
|
|
|
|
|
void print_hash(uint8_t *x, size_t len) {
|
|
|
|
hash_context ctx;
|
|
|
|
hash_oneshot(&ctx, x, len);
|
|
|
|
for (size_t i = 0; i < HASH_SIZE; i++) {
|
|
|
|
printf("%2.2x", ctx.hash[i]);
|
|
|
|
}
|
|
|
|
putchar('\n');
|
|
|
|
}
|
|
|
|
|
2019-10-25 03:48:13 +02:00
|
|
|
const char *get_last_dir(const char *path) {
|
|
|
|
const char *last = strrchr(path, '/');
|
|
|
|
if (!last) {
|
|
|
|
last = path;
|
|
|
|
} else if (last != path || last[1] != '\0') {
|
|
|
|
last++;
|
|
|
|
}
|
|
|
|
return last;
|
|
|
|
}
|
|
|
|
|
2017-10-18 22:19:53 +02:00
|
|
|
void prompt() {
|
2019-10-25 03:48:13 +02:00
|
|
|
if (cur_dir_changed) {
|
|
|
|
kos_getcwd(cur_dir, PATH_MAX);
|
|
|
|
last_dir = get_last_dir(cur_dir);
|
|
|
|
cur_dir_changed = false;
|
|
|
|
}
|
|
|
|
printf("%s> ", last_dir);
|
2018-05-19 17:48:10 +02:00
|
|
|
fflush(stdout);
|
2017-10-18 22:19:53 +02:00
|
|
|
}
|
|
|
|
|
2019-10-30 22:54:12 +01:00
|
|
|
int next_line(FILE *file, int is_tty) {
|
2018-04-26 15:07:34 +02:00
|
|
|
if (is_tty) {
|
|
|
|
prompt();
|
|
|
|
}
|
2019-10-30 22:54:12 +01:00
|
|
|
return fgets(cmd_buf, FGETS_BUF_LEN, file) != NULL;
|
2018-04-26 11:17:55 +02:00
|
|
|
}
|
|
|
|
|
2019-10-13 03:17:29 +02:00
|
|
|
int split_args(char *s, const char **argv) {
|
2018-04-26 11:17:55 +02:00
|
|
|
int argc = -1;
|
2019-10-30 22:54:12 +01:00
|
|
|
for (; (argv[++argc] = strtok(s, " \t\n")) != NULL; s = NULL);
|
2019-10-13 03:17:29 +02:00
|
|
|
return argc;
|
|
|
|
}
|
|
|
|
|
|
|
|
void kofu_disk_add(int argc, const char **argv) {
|
|
|
|
(void)argc;
|
|
|
|
const char *file_name = argv[1];
|
|
|
|
const char *disk_name = argv[2];
|
|
|
|
if (kos_disk_add(file_name, disk_name)) {
|
|
|
|
printf("[!!] can't add file '%s' as disk '%s'\n", file_name, disk_name);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
void kofu_disk_del(int argc, const char **argv) {
|
|
|
|
(void)argc;
|
|
|
|
const char *name = argv[1];
|
|
|
|
if (kos_disk_del(name)) {
|
|
|
|
printf("[!!] can't find or delete disk '%s'\n", name);
|
|
|
|
}
|
|
|
|
return;
|
2018-04-26 11:17:55 +02:00
|
|
|
}
|
|
|
|
|
2019-10-25 03:48:13 +02:00
|
|
|
void kofu_pwd(int argc, const char **argv) {
|
|
|
|
(void)argc;
|
|
|
|
(void)argv;
|
|
|
|
bool quoted = false;
|
|
|
|
const char *quote = quoted ? "'" : "";
|
|
|
|
kos_getcwd(cur_dir, PATH_MAX);
|
|
|
|
printf("%s%s%s\n", quote, cur_dir, quote);
|
|
|
|
}
|
|
|
|
|
|
|
|
void kofu_cd(int argc, const char **argv) {
|
|
|
|
(void)argc;
|
|
|
|
kos_cd(argv[1]);
|
|
|
|
cur_dir_changed = true;
|
|
|
|
}
|
|
|
|
|
2019-12-08 02:32:07 +01:00
|
|
|
void ls_range(f7080s1arg_t *fX0, f70or80_t f70or80) {
|
|
|
|
f7080ret_t r;
|
|
|
|
size_t bdfe_len = (fX0->encoding == CP866) ? BDFE_LEN_CP866 : BDFE_LEN_UNICODE;
|
|
|
|
uint32_t requested = fX0->size;
|
|
|
|
if (fX0->size > MAX_DIRENTS_TO_READ) {
|
|
|
|
fX0->size = MAX_DIRENTS_TO_READ;
|
2018-06-18 03:55:51 +02:00
|
|
|
}
|
2019-12-08 02:32:07 +01:00
|
|
|
for (; requested; requested -= fX0->size) {
|
|
|
|
if (fX0->size > requested) {
|
|
|
|
fX0->size = requested;
|
2018-06-13 03:29:17 +02:00
|
|
|
}
|
2019-12-08 02:32:07 +01:00
|
|
|
kos_lfn(fX0, &r, f70or80);
|
|
|
|
fX0->offset += fX0->size;
|
2019-10-25 03:48:13 +02:00
|
|
|
print_f70_status(&r, 1);
|
2019-12-08 02:32:07 +01:00
|
|
|
f7080s1info_t *dir = fX0->buf;
|
|
|
|
int ok = (r.count <= fX0->size);
|
2019-11-07 00:51:55 +01:00
|
|
|
ok &= (dir->cnt == r.count);
|
2019-12-08 02:32:07 +01:00
|
|
|
ok &= (r.status == ERROR_SUCCESS && r.count == fX0->size)
|
|
|
|
|| (r.status == ERROR_END_OF_FILE && r.count < fX0->size);
|
2019-11-07 00:51:55 +01:00
|
|
|
assert(ok);
|
|
|
|
if (!ok)
|
|
|
|
break;
|
2019-12-08 02:32:07 +01:00
|
|
|
bdfe_t *bdfe = dir->bdfes;
|
2018-06-18 03:55:51 +02:00
|
|
|
for (size_t i = 0; i < dir->cnt; i++) {
|
2019-11-07 00:51:55 +01:00
|
|
|
char fattr[KF_ATTR_CNT+1];
|
2019-12-08 02:32:07 +01:00
|
|
|
convert_f70_file_attr(bdfe->attr, fattr);
|
|
|
|
printf("%s %s\n", fattr, bdfe->name);
|
|
|
|
bdfe = (bdfe_t*)((uintptr_t)bdfe + bdfe_len);
|
2018-06-18 03:55:51 +02:00
|
|
|
}
|
2019-12-08 02:32:07 +01:00
|
|
|
if (r.status == ERROR_END_OF_FILE) {
|
2018-06-18 03:55:51 +02:00
|
|
|
break;
|
2018-05-14 09:54:05 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-08 02:32:07 +01:00
|
|
|
void ls_all(f7080s1arg_t *fX0, f70or80_t f70or80) {
|
|
|
|
f7080ret_t r;
|
|
|
|
size_t bdfe_len = (fX0->encoding == CP866) ? BDFE_LEN_CP866 : BDFE_LEN_UNICODE;
|
2018-05-09 23:08:52 +02:00
|
|
|
while (true) {
|
2019-12-08 02:32:07 +01:00
|
|
|
kos_lfn(fX0, &r, f70or80);
|
2019-10-25 03:48:13 +02:00
|
|
|
print_f70_status(&r, 1);
|
2019-12-08 02:32:07 +01:00
|
|
|
assert((r.status == ERROR_SUCCESS && r.count == fX0->size)
|
|
|
|
|| (r.status == ERROR_END_OF_FILE && r.count < fX0->size));
|
|
|
|
f7080s1info_t *dir = fX0->buf;
|
|
|
|
fX0->offset += dir->cnt;
|
|
|
|
int ok = (r.count <= fX0->size);
|
2019-11-07 00:51:55 +01:00
|
|
|
ok &= (dir->cnt == r.count);
|
2019-12-08 02:32:07 +01:00
|
|
|
ok &= (r.status == ERROR_SUCCESS && r.count == fX0->size)
|
|
|
|
|| (r.status == ERROR_END_OF_FILE && r.count < fX0->size);
|
2019-11-07 00:51:55 +01:00
|
|
|
assert(ok);
|
|
|
|
if (!ok)
|
|
|
|
break;
|
2019-11-11 03:20:06 +01:00
|
|
|
printf("total = %"PRIi32"\n", dir->total_cnt);
|
2019-12-08 02:32:07 +01:00
|
|
|
bdfe_t *bdfe = dir->bdfes;
|
2018-05-09 23:08:52 +02:00
|
|
|
for (size_t i = 0; i < dir->cnt; i++) {
|
2019-11-07 00:51:55 +01:00
|
|
|
char fattr[KF_ATTR_CNT+1];
|
2019-12-08 02:32:07 +01:00
|
|
|
convert_f70_file_attr(bdfe->attr, fattr);
|
|
|
|
printf("%s %s\n", fattr, bdfe->name);
|
|
|
|
bdfe = (bdfe_t*)((uintptr_t)bdfe + bdfe_len);
|
2018-05-09 23:08:52 +02:00
|
|
|
}
|
2019-12-08 02:32:07 +01:00
|
|
|
if (r.status == ERROR_END_OF_FILE) {
|
2018-05-09 23:08:52 +02:00
|
|
|
break;
|
|
|
|
}
|
2018-04-26 11:17:55 +02:00
|
|
|
}
|
2018-05-14 09:54:05 +02:00
|
|
|
}
|
|
|
|
|
2019-12-08 02:32:07 +01:00
|
|
|
void kofu_ls(int argc, const char **argv, f70or80_t f70or80) {
|
2019-10-13 03:17:29 +02:00
|
|
|
(void)argc;
|
2019-12-08 02:32:07 +01:00
|
|
|
uint32_t encoding = UTF8;
|
|
|
|
size_t bdfe_len = (encoding == CP866) ? BDFE_LEN_CP866 : BDFE_LEN_UNICODE;
|
|
|
|
f7080s1info_t *dir = (f7080s1info_t*)malloc(sizeof(f7080s1info_t) + bdfe_len * MAX_DIRENTS_TO_READ);
|
|
|
|
f7080s1arg_t fX0 = {.sf = 1, .offset = 0, .encoding = encoding, .size = MAX_DIRENTS_TO_READ, .buf = dir};
|
|
|
|
if (f70or80 == F70) {
|
|
|
|
fX0.u.f70.zero = 0;
|
|
|
|
fX0.u.f70.path = argv[1];
|
|
|
|
} else {
|
|
|
|
fX0.u.f80.path_encoding = DEFAULT_PATH_ENCODING;
|
|
|
|
fX0.u.f80.path = argv[1];
|
|
|
|
}
|
2019-10-13 03:17:29 +02:00
|
|
|
if (argv[2]) {
|
2019-12-08 02:32:07 +01:00
|
|
|
sscanf(argv[2], "%"SCNu32, &fX0.size);
|
2019-10-13 03:17:29 +02:00
|
|
|
if (argv[3]) {
|
2019-12-08 02:32:07 +01:00
|
|
|
sscanf(argv[3], "%"SCNu32, &fX0.offset);
|
2018-05-14 09:54:05 +02:00
|
|
|
}
|
2019-12-08 02:32:07 +01:00
|
|
|
ls_range(&fX0, f70or80);
|
2018-05-14 09:54:05 +02:00
|
|
|
} else {
|
2019-12-08 02:32:07 +01:00
|
|
|
ls_all(&fX0, f70or80);
|
2018-05-14 09:54:05 +02:00
|
|
|
}
|
2018-05-09 23:08:52 +02:00
|
|
|
free(dir);
|
2018-04-26 11:17:55 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-12-08 02:32:07 +01:00
|
|
|
void kofu_ls70(int argc, const char **argv) {
|
|
|
|
kofu_ls(argc, argv, F70);
|
|
|
|
}
|
|
|
|
|
|
|
|
void kofu_ls80(int argc, const char **argv) {
|
|
|
|
kofu_ls(argc, argv, F80);
|
|
|
|
}
|
|
|
|
|
|
|
|
void kofu_stat(int argc, const char **argv, f70or80_t f70or80) {
|
2019-10-13 03:17:29 +02:00
|
|
|
(void)argc;
|
2019-12-08 02:32:07 +01:00
|
|
|
f7080s5arg_t fX0 = {.sf = 5, .flags = 0};
|
|
|
|
f7080ret_t r;
|
2019-10-21 04:51:56 +02:00
|
|
|
bdfe_t file;
|
2019-12-08 02:32:07 +01:00
|
|
|
fX0.buf = &file;
|
|
|
|
if (f70or80 == F70) {
|
|
|
|
fX0.u.f70.zero = 0;
|
|
|
|
fX0.u.f70.path = argv[1];
|
|
|
|
} else {
|
|
|
|
fX0.u.f80.path_encoding = DEFAULT_PATH_ENCODING;
|
|
|
|
fX0.u.f80.path = argv[1];
|
|
|
|
}
|
|
|
|
kos_lfn(&fX0, &r, f70or80);
|
2019-10-25 03:48:13 +02:00
|
|
|
print_f70_status(&r, 0);
|
2019-12-08 02:32:07 +01:00
|
|
|
if (r.status != ERROR_SUCCESS)
|
2019-10-31 21:26:53 +01:00
|
|
|
return;
|
2019-11-07 00:51:55 +01:00
|
|
|
char fattr[KF_ATTR_CNT+1];
|
|
|
|
convert_f70_file_attr(file.attr, fattr);
|
|
|
|
printf("attr: %s\n", fattr);
|
|
|
|
if ((file.attr & KF_FOLDER) == 0) { // don't show size for dirs
|
2019-10-31 21:26:53 +01:00
|
|
|
printf("size: %llu\n", file.size);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if PRINT_DATE_TIME == 1
|
|
|
|
time_t time;
|
|
|
|
struct tm *t;
|
|
|
|
time = kos_time_to_epoch(&file.ctime);
|
|
|
|
t = localtime(&time);
|
|
|
|
printf("ctime: %4.4i.%2.2i.%2.2i %2.2i:%2.2i:%2.2i\n",
|
|
|
|
t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
|
|
|
|
t->tm_hour, t->tm_min, t->tm_sec);
|
|
|
|
time = kos_time_to_epoch(&file.atime);
|
|
|
|
t = localtime(&time);
|
|
|
|
printf("atime: %4.4i.%2.2i.%2.2i %2.2i:%2.2i:%2.2i\n",
|
|
|
|
t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
|
|
|
|
t->tm_hour, t->tm_min, t->tm_sec);
|
|
|
|
time = kos_time_to_epoch(&file.mtime);
|
|
|
|
t = localtime(&time);
|
|
|
|
printf("mtime: %4.4i.%2.2i.%2.2i %2.2i:%2.2i:%2.2i\n",
|
|
|
|
t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
|
|
|
|
t->tm_hour, t->tm_min, t->tm_sec);
|
|
|
|
#endif
|
2018-04-26 11:17:55 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-12-08 02:32:07 +01:00
|
|
|
void kofu_stat70(int argc, const char **argv) {
|
|
|
|
kofu_stat(argc, argv, F70);
|
|
|
|
}
|
|
|
|
|
|
|
|
void kofu_stat80(int argc, const char **argv) {
|
|
|
|
kofu_stat(argc, argv, F80);
|
|
|
|
}
|
|
|
|
|
|
|
|
void kofu_read(int argc, const char **argv, f70or80_t f70or80) {
|
2019-10-13 03:17:29 +02:00
|
|
|
(void)argc;
|
2019-12-08 02:32:07 +01:00
|
|
|
f7080s0arg_t fX0 = {.sf = 0};
|
|
|
|
f7080ret_t r;
|
2019-10-21 04:51:56 +02:00
|
|
|
bool dump_bytes = false, dump_hash = false;
|
|
|
|
if (argc < 4) {
|
2019-12-08 02:32:07 +01:00
|
|
|
printf("usage: %s <offset> <length> [-b] [-h] [-e cp866|utf8|utf16]\n", argv[0]);
|
2019-10-21 04:51:56 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
int opt = 1;
|
2019-12-08 02:32:07 +01:00
|
|
|
if (f70or80 == F70) {
|
|
|
|
fX0.u.f70.zero = 0;
|
|
|
|
fX0.u.f70.path = argv[opt++];
|
|
|
|
} else {
|
|
|
|
fX0.u.f80.path_encoding = DEFAULT_PATH_ENCODING;
|
|
|
|
fX0.u.f80.path = argv[opt++];
|
|
|
|
}
|
|
|
|
if ((opt >= argc) || !parse_uint64(argv[opt++], &fX0.offset))
|
2019-10-21 04:51:56 +02:00
|
|
|
return;
|
2019-12-08 02:32:07 +01:00
|
|
|
if ((opt >= argc) || !parse_uint32(argv[opt++], &fX0.count))
|
2019-10-21 04:51:56 +02:00
|
|
|
return;
|
|
|
|
for (; opt < argc; opt++) {
|
|
|
|
if (!strcmp(argv[opt], "-b")) {
|
|
|
|
dump_bytes = true;
|
|
|
|
} else if (!strcmp(argv[opt], "-h")) {
|
|
|
|
dump_hash = true;
|
2019-12-08 02:32:07 +01:00
|
|
|
} else if (!strcmp(argv[opt], "-e")) {
|
|
|
|
if (f70or80 == F70) {
|
|
|
|
printf("f70 doesn't accept encoding parameter, use f80\n");
|
|
|
|
return;
|
|
|
|
}
|
2019-10-21 04:51:56 +02:00
|
|
|
} else {
|
|
|
|
printf("invalid option: '%s'\n", argv[opt]);
|
|
|
|
return;
|
2018-05-07 17:31:42 +02:00
|
|
|
}
|
|
|
|
}
|
2019-12-08 02:32:07 +01:00
|
|
|
fX0.buf = (uint8_t*)malloc(fX0.count);
|
2019-10-21 04:51:56 +02:00
|
|
|
|
2019-12-08 02:32:07 +01:00
|
|
|
kos_lfn(&fX0, &r, f70or80);
|
2019-10-25 03:48:13 +02:00
|
|
|
|
|
|
|
print_f70_status(&r, 1);
|
2019-12-08 02:32:07 +01:00
|
|
|
if (r.status == ERROR_SUCCESS || r.status == ERROR_END_OF_FILE) {
|
|
|
|
if (dump_bytes)
|
|
|
|
print_bytes(fX0.buf, r.count);
|
|
|
|
if (dump_hash)
|
|
|
|
print_hash(fX0.buf, r.count);
|
|
|
|
}
|
2019-10-21 04:51:56 +02:00
|
|
|
|
2019-12-08 02:32:07 +01:00
|
|
|
free(fX0.buf);
|
2018-05-07 17:31:42 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-12-08 02:32:07 +01:00
|
|
|
void kofu_read70(int argc, const char **argv) {
|
|
|
|
kofu_read(argc, argv, F70);
|
|
|
|
}
|
|
|
|
|
|
|
|
void kofu_read80(int argc, const char **argv) {
|
|
|
|
kofu_read(argc, argv, F80);
|
|
|
|
}
|
|
|
|
|
2019-10-25 03:48:13 +02:00
|
|
|
typedef struct {
|
2018-04-26 11:17:55 +02:00
|
|
|
char *name;
|
2019-10-13 03:17:29 +02:00
|
|
|
void (*func) (int, const char **);
|
2019-10-25 03:48:13 +02:00
|
|
|
} func_table_t;
|
2018-04-26 11:17:55 +02:00
|
|
|
|
2019-10-25 03:48:13 +02:00
|
|
|
func_table_t funcs[] = {
|
2019-10-13 03:17:29 +02:00
|
|
|
{ "disk_add", kofu_disk_add },
|
|
|
|
{ "disk_del", kofu_disk_del },
|
2019-12-08 02:32:07 +01:00
|
|
|
{ "ls70", kofu_ls70 },
|
|
|
|
{ "ls80", kofu_ls80 },
|
|
|
|
{ "stat70", kofu_stat70 },
|
|
|
|
{ "stat80", kofu_stat80 },
|
|
|
|
{ "read70", kofu_read70 },
|
|
|
|
{ "read80", kofu_read80 },
|
2019-11-08 23:37:01 +01:00
|
|
|
{ "pwd", kofu_pwd },
|
|
|
|
{ "cd", kofu_cd },
|
|
|
|
{ NULL, NULL },
|
2018-04-26 11:17:55 +02:00
|
|
|
};
|
|
|
|
|
2019-10-30 22:54:12 +01:00
|
|
|
void usage() {
|
|
|
|
printf("usage: kofu [test_file.t]\n");
|
|
|
|
}
|
2018-04-23 12:09:46 +02:00
|
|
|
|
2019-10-30 22:54:12 +01:00
|
|
|
void *run_test(const char *infile_name) {
|
|
|
|
FILE *infile, *outfile;
|
|
|
|
|
|
|
|
if (!infile_name) {
|
|
|
|
infile = stdin;
|
|
|
|
outfile = stdout;
|
|
|
|
} else {
|
|
|
|
char outfile_name[PATH_MAX];
|
|
|
|
strncpy(outfile_name, infile_name, PATH_MAX-2); // ".t" is shorter that ".out"
|
|
|
|
char *last_dot = strrchr(outfile_name, '.');
|
|
|
|
if (!last_dot) {
|
|
|
|
printf("test file must have '.t' suffix\n");
|
|
|
|
usage();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
strcpy(last_dot, ".out");
|
|
|
|
infile = fopen(infile_name, "r");
|
|
|
|
outfile = fopen(outfile_name, "w");
|
|
|
|
if (!infile || !outfile) {
|
|
|
|
printf("can't open in/out files\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
2018-04-23 13:42:32 +02:00
|
|
|
}
|
2018-04-26 11:17:55 +02:00
|
|
|
|
2019-10-30 22:54:12 +01:00
|
|
|
int is_tty = isatty(fileno(infile));
|
2019-10-25 03:48:13 +02:00
|
|
|
const char **cargv = (const char**)malloc(sizeof(const char*) * (MAX_COMMAND_ARGS + 1));
|
2019-10-30 22:54:12 +01:00
|
|
|
while(next_line(infile, is_tty)) {
|
2019-10-28 04:10:38 +01:00
|
|
|
if (cmd_buf[0] == '#' || cmd_buf[0] == '\n') {
|
|
|
|
printf("%s", cmd_buf);
|
|
|
|
continue;
|
|
|
|
}
|
2019-10-25 03:48:13 +02:00
|
|
|
if (cmd_buf[0] == 'X') break;
|
2018-04-26 15:07:34 +02:00
|
|
|
if (!is_tty) {
|
|
|
|
prompt();
|
2018-05-19 17:48:10 +02:00
|
|
|
printf("%s", cmd_buf);
|
2019-10-30 22:54:12 +01:00
|
|
|
fflush(outfile);
|
2018-04-26 15:07:34 +02:00
|
|
|
}
|
2019-10-13 03:17:29 +02:00
|
|
|
int cargc = split_args(cmd_buf, cargv);
|
2019-10-25 03:48:13 +02:00
|
|
|
func_table_t *ft;
|
|
|
|
for (ft = funcs; ft->name != NULL; ft++) {
|
2019-10-13 03:17:29 +02:00
|
|
|
if (!strcmp(cargv[0], ft->name)) {
|
2018-04-26 11:17:55 +02:00
|
|
|
break;
|
2017-11-02 21:41:11 +01:00
|
|
|
}
|
2018-04-26 11:17:55 +02:00
|
|
|
}
|
2019-10-25 03:48:13 +02:00
|
|
|
if (ft->name) {
|
|
|
|
ft->func(cargc, cargv);
|
|
|
|
} else {
|
2019-10-13 03:17:29 +02:00
|
|
|
printf("unknown command: %s\n", cargv[0]);
|
2017-10-18 22:19:53 +02:00
|
|
|
}
|
|
|
|
}
|
2019-10-25 03:48:13 +02:00
|
|
|
free(cargv);
|
2019-10-09 01:35:47 +02:00
|
|
|
|
2019-10-30 22:54:12 +01:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char **argv) {
|
|
|
|
if (trace)
|
|
|
|
trace_begin();
|
|
|
|
kos_init();
|
|
|
|
|
|
|
|
switch (argc) {
|
|
|
|
case 1:
|
|
|
|
run_test(NULL);
|
|
|
|
break;
|
|
|
|
case 2: {
|
|
|
|
run_test(argv[1]);
|
|
|
|
break;
|
2019-10-13 03:17:29 +02:00
|
|
|
}
|
2019-10-30 22:54:12 +01:00
|
|
|
default:
|
|
|
|
usage();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (trace)
|
|
|
|
trace_end();
|
|
|
|
|
2017-10-18 22:19:53 +02:00
|
|
|
return 0;
|
|
|
|
}
|