Skip to content

Commit

Permalink
make parent directory if necessary
Browse files Browse the repository at this point in the history
  • Loading branch information
JimmyZ authored and JimmyZ committed Sep 22, 2017
1 parent 9abb4a8 commit b517192
Show file tree
Hide file tree
Showing 12 changed files with 155 additions and 55 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ include $(DEVKITARM)/ds_rules
export TARGET := twlnf
export TOPDIR := $(CURDIR)

export VERSION := 0.1.0
export VERSION := 0.2.0

.PHONY: arm7/$(TARGET).elf arm9/$(TARGET).elf

Expand Down
27 changes: 18 additions & 9 deletions arm9/source/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -200,12 +200,12 @@ void menu() {
view_pos = 0;
cur_pos = 0;
draw_file_list();
int needs_redraw = 0;
while (1) {
swiWaitForVBlank();
scanKeys();
uint32 keys = keysDown();
consoleSelect(&bottomScreen);
int needs_redraw = 0;
if (keys & KEY_B) {
break;
}else if(keys & (KEY_UP|KEY_DOWN|KEY_LEFT|KEY_RIGHT)){
Expand All @@ -221,14 +221,23 @@ void menu() {
needs_redraw = 1;
} else if (keys & KEY_A) {
menu_action(file_list[view_pos + cur_pos].name);
} else if ((keys & KEY_START) && (keys & KEY_L)) {
FILE * f = fopen("nand_files.lst", "w");
iprintf("walk returned %d\n", walk(nand_root, walk_cb_lst, f));
fclose(f);
} else if ((keys & KEY_START) && (keys & KEY_R)) {
FILE * f = fopen("nand_files.sha1", "w");
iprintf("walk returned %d\n", walk(nand_root, walk_cb_sha1, f));
fclose(f);
} else if ((keys & KEY_L) && (keys & KEY_R)) {
iprintf("\t(A) list NAND files\n"
"\t(X) sha1 NAND files\n"
"\t(Y) walk NAND\n"
"\t(B) cancel\n");
unsigned keys = wait_keys(KEY_A | KEY_B | KEY_X | KEY_Y);
if (keys & KEY_A) {
FILE * f = fopen("nand_files.lst", "w");
iprintf("walk returned %d\n", walk(nand_root, walk_cb_lst, f));
fclose(f);
} else if (keys & KEY_X) {
FILE * f = fopen("nand_files.sha1", "w");
iprintf("walk returned %d\n", walk(nand_root, walk_cb_sha1, f));
fclose(f);
} else if (keys & KEY_Y) {
iprintf("walk returned %d\n", walk(nand_root, 0, 0));
}
}
if (needs_redraw) {
consoleSelect(&topScreen);
Expand Down
128 changes: 113 additions & 15 deletions arm9/source/scripting.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@

#include <nds.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <dirent.h>
Expand Down Expand Up @@ -129,7 +130,7 @@ static void rm(const char *name) {
if (r == 0) {
iprintf("removed: %s\n", name);
} else {
iprintf("removed() returned %d for %s\n", r, name);
iprintf("remove() returned %d for %s, errno: %d\n", r, name, errno);
}
}

Expand All @@ -154,6 +155,7 @@ static int cmd_rm(const char * arg) {
sniprintf(name_buf1, LINE_BUF_LEN, "%s%s", name_buf0, de->d_name);
struct stat s;
if (stat(name_buf1, &s) != 0) {
iprintf("weird stat failure, errno: %d\n", errno);
continue;
}
if ((s.st_mode & S_IFMT) == S_IFREG) {
Expand All @@ -179,6 +181,23 @@ static int cmd_rm(const char * arg) {
return NO_ERR;
}

/*
rmdir() returns errno 88(ENOSYS, function not implemented)
then I found out unlink works on directory, and remove works too
so no reason for a separate rmdir now
static int cmd_rmdir(const char *arg) {
sniprintf(name_buf0, LINE_BUF_LEN, "%s%s", nand_root, arg);
convert_backslash(name_buf0);
int r = unlink(name_buf0);
if (r == 0) {
iprintf("unlink succeed: %s\n", name_buf0);
} else {
iprintf("unlink() returned %d for: %s, errno: %d\n", r, name_buf0, errno);
}
return NO_ERR;
}
*/

static int execute_cmd(const char * line, unsigned len, int dry_run) {
unsigned cmd;
const char * arg = 0;
Expand Down Expand Up @@ -234,6 +253,73 @@ int sha1_file(void *digest, const char *name) {
return size;
}

int validate_path(const char *root, const char *name, unsigned fmt) {
// like a mkdir -p dry run
unsigned root_len = root == 0 ? 0 : strlen(root);
unsigned full_len = root == 0 ? strlen(name) : 0;
if (root == 0) {
strcpy(name_buf0, name);
} else {
full_len = sniprintf(name_buf0, LINE_BUF_LEN, "%s%s", root, name);
}
struct stat s;
if (stat(name_buf0, &s) == 0) {
// target already exist
if ((s.st_mode & S_IFMT) == fmt) {
return 0;
} else {
// can't create a file if a dir with the same name already exist and vice versa
return -1;
}
}
// now check all ancestor available as S_IFDIR
// since we have dry run mode, we can't just mkdir and check errno
// recursive seems risky so a loop here
for (unsigned i = root_len; i < full_len; ++i) {
if (name_buf0[i] != '/') {
continue;
}
strncpy(name_buf1, name_buf0, i);
name_buf1[i] = 0;
if (stat(name_buf1, &s) != 0) {
// any ancestor doesn't exist, it is valid
return 0;
} else if ((s.st_mode & S_IFMT) != S_IFDIR) {
// any ancestor exist but not dir, it is invalid
return -1;
}
}
return 0;
}

void mkdir_parent(const char *root, const char *name) {
// this shares a lot of code with validate_path
// I thought about combine them with a dry_run flag
// but decided to write them separated instead
unsigned root_len = root == 0 ? 0 : strlen(root);
unsigned full_len = root == 0 ? strlen(name) : 0;
if (root == 0) {
strcpy(name_buf0, name);
} else {
full_len = sniprintf(name_buf0, LINE_BUF_LEN, "%s%s", root, name);
}
struct stat s;
for (unsigned i = root_len; i < full_len; ++i) {
if (name_buf0[i] != '/') {
continue;
}
strncpy(name_buf1, name_buf0, i);
name_buf1[i] = 0;
if (stat(name_buf1, &s) != 0) {
// any ancestor doesn't exist, create it
if (mkdir(name_buf1, S_IRWXU | S_IRWXG | S_IRWXO) != 0) {
iprintf("mkdir fail(%d): %s\n", errno, name_buf1);
}
}
}
return;
}

int cp(const char *from, const char *to) {
FILE *f = fopen(from, "r");
if (f == 0) {
Expand Down Expand Up @@ -272,6 +358,7 @@ int scripting(const char *scriptname, int dry_run, unsigned *p_size){
unsigned size = 0;
unsigned missing = 0;
unsigned wrong = 0;
unsigned invalid = 0;
unsigned check = 0;
int ret = 0;
while (fgets(line_buf, LINE_BUF_LEN, f) != 0) {
Expand Down Expand Up @@ -314,23 +401,31 @@ int scripting(const char *scriptname, int dry_run, unsigned *p_size){
// hash
unsigned char digest[SHA1_LEN];
if (dry_run) {
// TODO: maybe a "files on NAND are identical" test
int sha1_ret = sha1_file(digest, name);
if (sha1_ret == -1) {
iprintf(" missing\n");
++missing;
// make sure the target path is valid
if (validate_path(nand_root, name, S_IFREG) != 0) {
iprintf("invalid target path: %s%s\n", nand_root, name);
++invalid;
} else {
size += sha1_ret;
if (memcmp(line, digest, SHA1_LEN)) {
iprintf(" wrong\n");
++wrong;
// TODO: maybe a "files on NAND are identical" test
int sha1_ret = sha1_file(digest, name);
if (sha1_ret == -1) {
iprintf(" missing\n");
++missing;
} else {
iprintf(" OK\n");
++check;
size += sha1_ret;
if (memcmp(line, digest, SHA1_LEN)) {
iprintf(" wrong\n");
++wrong;
} else {
iprintf(" OK\n");
++check;
}
}
}
} else {
sniprintf(name_buf0, LINE_BUF_LEN, "%s%s", nand_root, name);
mkdir_parent(nand_root, name);
// name_buf0 should have been prepared by mkdir_parent
// sniprintf(name_buf0, LINE_BUF_LEN, "%s%s", nand_root, name);
int cp_ret = cp(name, name_buf0);
if (cp_ret != 0) {
iprintf(" failed to copy, cp() returned %d, you may panic now\n", cp_ret);
Expand Down Expand Up @@ -359,10 +454,13 @@ int scripting(const char *scriptname, int dry_run, unsigned *p_size){
iprintf("%u wrong, %u missing\n", wrong, missing);
}
if (irregular > 0) {
iprintf("%u irregular lines\n", irregular);
iprintf("%u irregular line(s)\n", irregular);
}
if (invalid > 0) {
iprintf("%u invalid target path(s)\n", invalid);
}
*p_size = size;
return ret != 0 ? ret : irregular + missing + wrong;
return ret != 0 ? ret : irregular + invalid + missing + wrong;
} else {
return ret;
}
Expand Down
30 changes: 23 additions & 7 deletions arm9/source/walk.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@
// a POSIX directory tree walk
// walk down subdirectories and calls callback on regular files, skip all others

#include <stdio.h>
#include <errno.h>
#include <malloc.h>
#include <inttypes.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
#include <stdio.h>
#include <string.h>
#include "walk.h"

#define NAME_BUF_LEN 0x100
Expand All @@ -19,6 +21,7 @@ static unsigned head;

static unsigned stack_usage;
static unsigned stack_max_depth;
static unsigned longest_path;

// I suppose no need for a linked stack
static void s_alloc() {
Expand Down Expand Up @@ -64,6 +67,7 @@ int walk(const char *dir, void (*callback)(const char*, void*), void *p_cb_param
// init the stack
stack_max_depth = 0;
stack_usage = 0;
longest_path = 0;
s_alloc();
char *p = (char*)malloc(strlen(dir) + 1);
if (p == 0) {
Expand All @@ -84,35 +88,46 @@ int walk(const char *dir, void (*callback)(const char*, void*), void *p_cb_param
if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
continue;
}
char *fullname = (char*)malloc(len_parent + 1 + strlen(de->d_name) + 1);
unsigned full_len = len_parent + 1 + strlen(de->d_name);
if (full_len > longest_path) {
longest_path = full_len;
}
char *fullname = (char*)malloc(full_len + 1);
if (fullname == 0) {
s_deep_free();
return -1;
}
siprintf(fullname, p[strlen(p) - 1] == '/' ? "%s%s" : "%s/%s", p, de->d_name);
struct stat s;
if (stat(fullname, &s) != 0) {
iprintf("weird stat failure, errno: %d\n", errno);
free(fullname);
continue;
}
if (s.st_mode & S_IFREG) {
callback(fullname, p_cb_param);
if ((s.st_mode & S_IFMT) == S_IFREG) {
if (callback != 0) {
callback(fullname, p_cb_param);
}
free(fullname);
} else if (s.st_mode & S_IFDIR) {
} else if ((s.st_mode & S_IFMT) == S_IFDIR) {
if (callback == 0) {
iprintf("%s\n", fullname);
}
if (s_push(fullname) == 0) {
free(fullname);
s_deep_free();
return -2;
}
} else {
iprintf("weird type 0x%08" PRIx32 ": %s\n", s.st_mode & S_IFMT, fullname);
free(fullname);
}
}
closedir(d);
free(p);
}
s_free();
iprintf("stack stats: %u/%u\n", stack_max_depth, stack_usage);
iprintf("walk stats: %u, %u, %u\n", stack_max_depth, stack_usage, longest_path);
return 0;
}

Expand All @@ -129,6 +144,7 @@ void listdir(const char *dir, int want_full, void(*callback)(const char*, size_t
sniprintf(name_buf, NAME_BUF_LEN, dir[strlen(dir) - 1] == '/' ? "%s%s" : "%s/%s", dir, de->d_name);
struct stat s;
if (stat(name_buf, &s) != 0) {
iprintf("weird stat failure, errno: %d\n", errno);
continue;
}
if ((s.st_mode & S_IFMT) == S_IFREG) {
Expand Down
3 changes: 0 additions & 3 deletions test scripts/cp.nfs

This file was deleted.

4 changes: 0 additions & 4 deletions test scripts/dir_exist.nfs

This file was deleted.

4 changes: 0 additions & 4 deletions test scripts/file_exist.nfs

This file was deleted.

2 changes: 0 additions & 2 deletions test scripts/rm wild.nfs

This file was deleted.

2 changes: 0 additions & 2 deletions test scripts/rm.nfs

This file was deleted.

6 changes: 0 additions & 6 deletions test scripts/sha1sum.nfs

This file was deleted.

1 change: 0 additions & 1 deletion tmp/test.sha

This file was deleted.

1 change: 0 additions & 1 deletion tmp/test.txt

This file was deleted.

0 comments on commit b517192

Please sign in to comment.