From 0b3e0d143274d8c38ac7f6d44e6d9f5f5a554d45 Mon Sep 17 00:00:00 2001 From: Mauricio Garrido Date: Tue, 30 Dec 2025 12:37:37 -0600 Subject: [PATCH] 3ds: Small changes to port sources. This commit does the following changes: - Replace buffered io implementation with a simpler, lighter, slightly faster version. - Turn off both screens when backlight goes off. - Small change to enable plugins in the folling commit (s). Change-Id: I45df30be037c3a1686bd85c16c87bcd248db456f --- firmware/target/hosted/ctru/backlight-ctru.c | 3 +- firmware/target/hosted/ctru/lc-ctru.c | 6 + .../hosted/ctru/lib/bfile/bfile-internal.h | 40 +- firmware/target/hosted/ctru/lib/bfile/bfile.c | 478 +++------------ firmware/target/hosted/ctru/lib/bfile/bfile.h | 34 +- firmware/target/hosted/ctru/lib/cmap.h | 209 ------- firmware/target/hosted/ctru/lib/cslice.h | 63 -- firmware/target/hosted/ctru/lib/cvector.h | 549 ------------------ firmware/target/hosted/ctru/lib/sys_dir.c | 2 +- firmware/target/hosted/ctru/lib/sys_file.c | 126 ++-- firmware/target/hosted/ctru/lib/sys_file.h | 2 +- 11 files changed, 192 insertions(+), 1320 deletions(-) delete mode 100644 firmware/target/hosted/ctru/lib/cmap.h delete mode 100644 firmware/target/hosted/ctru/lib/cslice.h delete mode 100644 firmware/target/hosted/ctru/lib/cvector.h diff --git a/firmware/target/hosted/ctru/backlight-ctru.c b/firmware/target/hosted/ctru/backlight-ctru.c index 917db29405..8d45ba0b84 100644 --- a/firmware/target/hosted/ctru/backlight-ctru.c +++ b/firmware/target/hosted/ctru/backlight-ctru.c @@ -89,8 +89,9 @@ void backlight_hw_off(void) { lcd_mutex_lock(); if (last_bl != 0) { - /* only power off rockbox ui screen */ + /* power off both screens to save battery */ GSPLCD_PowerOffBacklight(GSPLCD_SCREEN_BOTTOM); + GSPLCD_PowerOffBacklight(GSPLCD_SCREEN_TOP); #ifdef HAVE_LCD_ENABLE lcd_enable(false); #endif diff --git a/firmware/target/hosted/ctru/lc-ctru.c b/firmware/target/hosted/ctru/lc-ctru.c index e65adbbf5a..84b0e4534d 100644 --- a/firmware/target/hosted/ctru/lc-ctru.c +++ b/firmware/target/hosted/ctru/lc-ctru.c @@ -27,11 +27,17 @@ #include "filesystem-ctru.h" #include "debug.h" +extern u32 __ctrl_code_allocator_pages; + void* programResolver(const char* sym, void *userData); void * lc_open(const char *filename, unsigned char *buf, size_t buf_size) { DEBUGF("dlopen(path=\"%s\")\n", filename); + /* We need to increase __ctrl_code_allocator_pages value to 8 MB + to enable big plugins */ + __ctrl_code_allocator_pages = 2048; + /* note: the 3ds dlopen implementation needs a custom resolver for the unresolved symbols in shared objects */ /* void *handle = dlopen(filename, RTLD_NOW | RTLD_LOCAL); */ diff --git a/firmware/target/hosted/ctru/lib/bfile/bfile-internal.h b/firmware/target/hosted/ctru/lib/bfile/bfile-internal.h index e274daf5f5..24618d3fc2 100644 --- a/firmware/target/hosted/ctru/lib/bfile/bfile-internal.h +++ b/firmware/target/hosted/ctru/lib/bfile/bfile-internal.h @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -19,11 +20,6 @@ /* #define MALLOC_DEBUG #include "rmalloc/rmalloc.h" */ -#include "cslice.h" -#include "cmap.h" - -#define nil NULL - /* in go functions can return two values */ #define two_type_value(type1, type2, name1, name2, type_name) \ typedef struct { \ @@ -68,32 +64,14 @@ two_type_value(int, const char*, n, err, int_error); two_type_value(struct stat, const char*, fi, err, stat_error); typedef const char* file_error_t; -typedef struct page { - s64 num; - struct page* prev; - struct page* next; - u8* data; -} page; +typedef struct { + Handle file; + s64 start; + s64 end; + s64 size; + bool isLastPage; -/* the two map types used by this library */ -cmap_declare(page, s64, struct page*); -cmap_declare(bool, s64, bool); - -typedef struct shard { - sync_Mutex mu; - cmap(page) pages; - cmap(bool) dirty; - struct page* head; - struct page* tail; -} shard; - -typedef struct Pager { - Handle file; - s64 pgsize; - s64 pgmax; - /* sync_RWMutex mu; */ - s64 size; - cslice(shard) shards; -} Pager; + u8 *buffer; +} PageReader; #endif /* _BFILE_INTERNAL_H_ */ diff --git a/firmware/target/hosted/ctru/lib/bfile/bfile.c b/firmware/target/hosted/ctru/lib/bfile/bfile.c index 8542cf3ae0..e63ecf008b 100644 --- a/firmware/target/hosted/ctru/lib/bfile/bfile.c +++ b/firmware/target/hosted/ctru/lib/bfile/bfile.c @@ -1,20 +1,12 @@ -/* - * This code is based on bfile.go by Josh Baker. - * Converted to C code by Mauricio G. - * Released under the MIT License. - */ -/* IMPORTANT: this code only works for O_RDONLY and O_RDWR files. */ +// This is a very simple code that reads blocks of data (pages) from a +// file and then simulates file reads, reading from a memory buffer. +// This is significantly faster than reading small chunks of data +// directly from a file. #include "bfile.h" -/* note: for ease of reading and ease of comparing go code - with c implementation, function names are similar to the - go version */ - -/* note2: sync_RWMutex calls have been moved to rockbox sys_file - implementation. To use as standalone code please uncomment those calls. */ - +// rw mutex implementation void sync_RWMutexInit(sync_RWMutex *m) { LightLock_Init(&m->shared); CondVar_Init(&m->reader_q); @@ -67,405 +59,117 @@ void sync_RWMutexUnlock(sync_RWMutex *m) { LightLock_Unlock(lk); } -void s_init(shard* s); - -void s_push(shard* s, page* p) { - s->head->next->prev = p; - p->next = s->head->next; - p->prev = s->head; - s->head->next = p; -} - -void s_pop(shard* s, page* p) { - p->prev->next = p->next; - p->next->prev = p->prev; -} - -void s_bump(shard* s, page* p) { - s_pop(s, p); - s_push(s, p); -} - -/* page_pair_t destructor */ -/* page_pair_t type is defined by cmap_declare(page, s64, struct page*) */ -/* struct { - s64 key; - struct page* value; - } page_pair_t; -*/ -void page_pair_free(void* pair_ptr) { - if (pair_ptr) { - page_pair_t *pair = (page_pair_t*) pair_ptr; - struct page *p = pair->value; - if (p != nil) { - if (p->data != nil) { - free(p->data); - } - free(p); - } - } -} - -/* shard destructor */ -void s_free(void* s_ptr) { - if (s_ptr) { - shard *s = (shard*) s_ptr; - if (s->pages != nil) { - cmap_set_elem_destructor(s->pages, page_pair_free); - cmap_clear(page, s->pages); - cmap_clear(bool, s->dirty); - free(s->head); - free(s->tail); - } - } -} - -Pager* NewPager(Handle file) { - return NewPagerSize(file, 0, 0); -} - -Pager* NewPagerSize(Handle file, int pageSize, int bufferSize) { - if (pageSize <= 0) { - pageSize = defaultPageSize; - } else if ((pageSize & 4095) != 0) { - // must be a power of two - int x = 1; - while (x < pageSize) { - x *= 2; - } - pageSize = x; - } - - if (bufferSize <= 0) { - bufferSize = defaultBufferSize; - } else if (bufferSize < pageSize) { - bufferSize = pageSize; - } - - Pager* f = (Pager*) malloc(sizeof(Pager)); - f->file = file; - f->size = -1; - f->pgsize = (s64) pageSize; - - /* sync_RWMutexInit(&f->mu); */ - - // calculate the max number of pages across all shards - s64 pgmax = (s64) bufferSize / f->pgsize; - if (pgmax < minPages) { - pgmax = minPages; - } - - // calculate how many shards are needed, power of 2 - s64 nshards = (s64) ceil((double) pgmax / (double) pagesPerShard); - if (nshards > maxShards) { - nshards = maxShards; - } - s64 x = 1; - while (x < nshards) { - x *= 2; - } - nshards = x; - - // calculate the max number of pages per shard - f->pgmax = (s64) floor((double) pgmax / (double) nshards); - cslice_make(f->shards, nshards, (shard) { 0 }); - - // initialize sync mutex - size_t i; - for (i = 0; i < cslice_len(f->shards); i++) { - sync_MutexInit(&f->shards[i].mu); - } - return f; -} - -static int_error_t read_at(Handle file, u8 *data, size_t data_len, off_t off) +// page reader implementation +file_error_t readPage(PageReader *p, u64 offset) { u32 read_bytes = 0; - if (R_FAILED(FSFILE_Read(file, &read_bytes, (u64) off, data, (u32) data_len))) { - return (int_error_t) { -1, "I/O error" }; + if (R_FAILED(FSFILE_Read(p->file, + &read_bytes, + offset, + p->buffer, + p->size))) { + printf("readPage: FSFILE_Read failed (I/O Error)\n"); + return "I/O Error"; } - /* io.EOF */ - if (read_bytes == 0) { - return (int_error_t) { 0, "io.EOF" }; + // we are at the last page of the file + if (read_bytes < p->size) { + p->isLastPage = true; } - return (int_error_t) { (int) read_bytes, nil }; + p->size = read_bytes; + p->start = offset; + p->end = offset + p->size; + + /* printf("page: 0x%llx, 0x%llx, %lld (last_page: %s)\n", p->start, p->end, p->size, p->isLastPage == true ? "true": "false"); */ + return NULL; } -static int_error_t write_at(Handle file, u8 *data, size_t data_len, off_t off) +PageReader* NewPageReader(Handle file, s64 pageSize) { - u32 written = 0; - if (R_FAILED(FSFILE_Write(file, &written, (u64) off, data, (u32) data_len, FS_WRITE_FLUSH))) { - return (int_error_t) { -1, "I/O error" }; + PageReader *p = (PageReader *) malloc(sizeof(PageReader)); + if (p == NULL) { + printf("NewPageReader: memory error\n"); + return NULL; } - /* I/O error */ - if ((written == 0) || (written < (u32) data_len)) { - return (int_error_t) { -1, "I/O error" }; + p->buffer = (u8 *) malloc(sizeof(u8) * pageSize); + if (p->buffer == NULL) { + printf("NewPagereader: memory error (buffer)\n"); + return NULL; } - return (int_error_t) { (int) written, nil }; + // clear buffer data + memset(p->buffer, 0x0, sizeof(u8) + pageSize); + + p->start = 0; + p->end = 0; + p->isLastPage = false; + p->size = pageSize; + p->file = file; + + // read ahead first page buffer from file + file_error_t err = readPage(p, 0); + if (err != NULL) { + free(p); + return NULL; + } + + return p; } -static stat_error_t file_stat(Handle file) +void PageReader_Free(PageReader *p) { - u64 size = 0; - struct stat fi = { 0 }; - if (R_FAILED(FSFILE_GetSize(file, &size))) { - fi.st_size = 0; - return (stat_error_t) { fi, "I/O error" }; - } - - fi.st_size = (off_t) size; - return (stat_error_t) { fi, nil }; -} - -void s_init(shard* s) -{ - if (s->pages == nil) { - s->pages = cmap_make(/*s64*/page); - s->dirty = cmap_make(/*s64*/bool); - s->head = (page*) malloc(sizeof(page)); - s->tail = (page*) malloc(sizeof(page)); - s->head->next = s->tail; - s->tail->prev = s->head; - } -} - -file_error_t f_write(Pager* f, page* p) { - s64 off = p->num * f->pgsize; - s64 end = f->pgsize; - if ((off + end) > f->size) { - end = f->size - off; - } - int_error_t __err = write_at(f->file, p->data, end, off); - if (__err.err != nil) { - return __err.err; - } - return nil; -} - -file_error_t f_read(Pager* f, page* p) { - int_error_t __err = read_at(f->file, p->data, f->pgsize, p->num * f->pgsize); - if ((__err.err != nil) && strcmp(__err.err, "io.EOF")) { - return "I/O error"; - } - - return nil; -} - -const char* f_incrSize(Pager* f, s64 end, bool write) -{ -#define defer(m) \ - sync_RWMutexUnlock(&f->mu); \ - sync_RWMutexRLock(&f->mu); - - /* sync_RWMutexRUnlock(&f->mu); - sync_RWMutexLock(&f->mu); */ - - if (f->size == -1) { - stat_error_t fi_err = file_stat(f->file); - if (fi_err.err != nil) { - /* defer(&f->mu); */ - return nil; + if (p != NULL) { + if (p->buffer != NULL) { + free(p->buffer); + p->buffer = NULL; } - f->size = fi_err.fi.st_size; - } - if (write && (end > f->size)) { - f->size = end; - } - /* defer(&f->mu); */ - return nil; + free(p); + } } -int_error_t f_pio(Pager *f, u8 *b, size_t len_b, s64 pnum, s64 pstart, s64 pend, bool write); -int_error_t f_io(Pager *f, u8 *b, size_t len_b, s64 off, bool write) { - if (f == nil) { - return (int_error_t) { 0, "invalid argument" }; - } +static inline void copyPage(PageReader *p, u8 *buffer, size_t size, off_t offset) +{ + off_t off = offset - p->start; + memcpy(buffer, p->buffer + off, size); +} + +int_error_t PageReader_ReadAt(PageReader *p, u8 *buffer, size_t size, off_t offset) +{ bool eof = false; - s64 start = off, end = off + len_b; - if (start < 0) { - return (int_error_t) { 0, "negative offset" }; + + // higher probability, buffer is in cached page range + if ((offset >= p->start) && ((offset + size) < p->end)) { + copyPage(p, buffer, size, offset); + return (int_error_t) { size, NULL }; } - // Check the upper bounds of the input to the known file size. - // Increase the file size if needed. - /* sync_RWMutexRLock(&f->mu); */ - if (end > f->size) { - file_error_t err = f_incrSize(f, end, write); - if (err != nil) { - /* sync_RWMutexRUnlock(&f->mu); */ - return (int_error_t) { 0, err }; - } - if (!write && (end > f->size)) { - end = f->size; - if ((end - start) < 0) { - end = start; - } - eof = true; - len_b = end-start; /* b = b[:end-start] */ - } - } - /* sync_RWMutexRUnlock(&f->mu); */ - - // Perform the page I/O. - int total = 0; - while (len_b > 0) { - s64 pnum = off / f->pgsize; - s64 pstart = off & (f->pgsize - 1); - s64 pend = pstart + (s64) len_b; - if (pend > f->pgsize) { - pend = f->pgsize; + // less higher probability, read new page at offset + if (p->isLastPage == false) { + file_error_t err = readPage(p, offset); + if (err != NULL) { + return (int_error_t) { -1, "I/O Error" }; } - int_error_t result = f_pio(f, b, pend - pstart, pnum, pstart, pend, write); - if (result.err != nil) { - return (int_error_t) { total, result.err }; - } - - off += (s64) result.n; - total += result.n; - b = &b[result.n]; len_b -= result.n; /* b = b[n:] */ - } - if (eof) { - return (int_error_t) { total, "io.EOF" }; + // we could have reached last page here so continue to + // last page handling } - return (int_error_t) { total, nil }; + // lower probability, we are at the last page + + // trying to read past end of file + if (offset >= p->end) { + return (int_error_t) { 0, "io.EOF" }; + } + + // we reached the end of file so adjust buffer size to remaining bytes number + if ((p->end - offset) < size) { + size = p->end - offset; + eof = true; + } + + copyPage(p, buffer, size, offset); + return (int_error_t) { size, eof == true ? "io.EOF" : NULL }; } - -int_error_t f_pio(Pager *f, u8 *b, size_t len_b, s64 pnum, s64 pstart, s64 pend, bool write) { - /* printf("pio(%p, %d, %lld, %lld, %lld, %s)\n", b, len_b, pnum, pstart, pend, write == true ? "true" : "false"); */ - shard *s = &f->shards[pnum & (s64) (cslice_len(f->shards) - 1)]; - sync_MutexLock(&s->mu); - s_init(s); - page *p = cmap_get_ptr(page, s->pages, pnum); - if (p == nil) { - // Page does not exist in memory. - // Acquire a new one. - if (cmap_len(s->pages) == f->pgmax) { - // The buffer is at capacity. - // Evict lru page and hang on to it. - p = s->tail->prev; - s_pop(s, p); - cmap_delete(page, s->pages, p->num); - if (cmap_get(bool, s->dirty, p->num)) { - // dirty page. flush it now - file_error_t err = f_write(f, p); - if (err != nil) { - sync_MutexUnlock(&s->mu); - return (int_error_t) { 0, err }; - } - cmap_delete(bool, s->dirty, p->num); - } - // Clear the previous page memory for partial page writes for - // pages that are being partially written to. - if (write && ((pend - pstart) < f->pgsize)) { - memset(p->data, 0, f->pgsize); - } - } else { - // Allocate an entirely new page. - p = (page *) malloc(sizeof(page)); - p->data = (u8 *) malloc(f->pgsize); - } - p->num = pnum; - // Read contents of page from file for all read operations, and - // partial write operations. Ignore for full page writes. - if (!write || ((pend-pstart) < f->pgsize)) { - file_error_t err = f_read(f, p); - if (err != nil) { - sync_MutexUnlock(&s->mu); - return (int_error_t) { 0, err }; - } - } - // Add the newly acquired page to the list. - cmap_set(page, s->pages, p->num, p); - s_push(s, p); - } else { - // Bump the page to the front of the list. - s_bump(s, p); - } - if (write) { - memcpy(p->data + pstart, b, pend - pstart); - cmap_set(bool, s->dirty, pnum, true); - } else { - memcpy(b, p->data + pstart, pend - pstart); - } - sync_MutexUnlock(&s->mu); - return (int_error_t) { len_b, nil }; -} - -// Flush writes any unwritten buffered data to the underlying file. -file_error_t PagerFlush(Pager *f) { - if (f == nil) { - return "invalid argument"; - } - - /* sync_RWMutexLock(&f->mu); */ - for (size_t i = 0; i < cslice_len(f->shards); i++) { - cmap_iterator(bool) pnum; - if (f->shards[i].dirty != nil) { - for (pnum = cmap_begin(f->shards[i].dirty); - pnum != cmap_end(f->shards[i].dirty); pnum++) { - if (pnum->value == true) { - page *p = cmap_get_ptr(page, f->shards[i].pages, pnum->key); - if (p != nil) { - file_error_t err = f_write(f, p); - if (err != nil) { - /* sync_RWMutexUnlock(&f->mu); */ - return err; - } - } - cmap_set(bool, f->shards[i].dirty, pnum->key, false); - } - } - } - } - /* sync_RWMutexUnlock(&f->mu); */ - return nil; -} - -// ReadAt reads len(b) bytes from the File starting at byte offset off. -int_error_t PagerReadAt(Pager *f, u8 *b, size_t len_b, off_t off) { - return f_io(f, b, len_b, off, false); -} - -// WriteAt writes len(b) bytes to the File starting at byte offset off. -int_error_t PagerWriteAt(Pager *f, u8 *b, size_t len_b, off_t off) { - return f_io(f, b, len_b, off, true); -} - -file_error_t PagerTruncate(Pager *f, off_t length) { - if (f == nil) { - return "invalid argument"; - } - - /* flush unwritten changes to disk */ - PagerFlush(f); - - /* sync_RWMutexRLock(&f->mu); */ - /* set new file size */ - Handle handle = f->file; - Result res = FSFILE_SetSize(handle, (u64) length); - if (R_FAILED(res)) { - return "I/O error"; - } - /* sync_RWMutexRUnlock(&f->mu); */ - - /* FIXME: truncate only required pages. Remove all for now */ - PagerClear(f); - f = NewPager(handle); - return nil; -} - -void PagerClear(Pager *f) { - if (f) { - cslice_set_elem_destructor(f->shards, s_free); - cslice_clear(f->shards); - free(f); - } -} - diff --git a/firmware/target/hosted/ctru/lib/bfile/bfile.h b/firmware/target/hosted/ctru/lib/bfile/bfile.h index 870a9248d0..dab6c69309 100644 --- a/firmware/target/hosted/ctru/lib/bfile/bfile.h +++ b/firmware/target/hosted/ctru/lib/bfile/bfile.h @@ -3,35 +3,15 @@ #include "bfile-internal.h" -static const int defaultPageSize = 4096; // all pages are this size -static const int defaultBufferSize = 0x800000; // default buffer size, 8 MB -static const int minPages = 4; // minimum total pages per file -static const int pagesPerShard = 32; // ideal number of pages per shard -static const int maxShards = 128; // maximum number of shards per file +static const int defaultPageSize = 0x80000; // default page buffer size, 512 kB -// NewPager returns a new Pager that is backed by the provided file. -Pager* NewPager(Handle file); +// NewPageReader creates a new PageReader struct with pageSize +PageReader *NewPageReader(Handle file, s64 pageSize); -// NewPagerSize returns a new Pager with a custom page size and buffer size. -// The bufferSize is the maximum amount of memory dedicated to individual -// pages. Setting pageSize and bufferSize to zero will use their defaults, -// which are 4096 and 8 MB respectively. Custom values are rounded up to the -// nearest power of 2. -Pager* NewPagerSize(Handle file, int pageSize, int bufferSize); +// Free all memory associated to the PageReader pointer +void PageReader_Free(PageReader *p); -// ReadAt reads len(b) bytes from the File starting at byte offset off. -int_error_t PagerReadAt(Pager *f, u8 *b, size_t len_b, off_t off); - -// WriteAt writes len(b) bytes to the File starting at byte offset off. -int_error_t PagerWriteAt(Pager *f, u8 *b, size_t len_b, off_t off); - -// Flush writes any unwritten buffered data to the underlying file. -file_error_t PagerFlush(Pager *f); - -// Truncates pager to specified length -file_error_t PagerTruncate(Pager *f, off_t length); - -// Free all memory associated to a Pager file -void PagerClear(Pager *f); +// ReadAt reads size bytes from the PageReader starting at offset. +int_error_t PageReader_ReadAt(PageReader *p, u8 *buffer, size_t size, off_t offset); #endif /* _B_FILE_H_ */ diff --git a/firmware/target/hosted/ctru/lib/cmap.h b/firmware/target/hosted/ctru/lib/cmap.h deleted file mode 100644 index faa1eff9f3..0000000000 --- a/firmware/target/hosted/ctru/lib/cmap.h +++ /dev/null @@ -1,209 +0,0 @@ -#ifndef CMAP_H_ -#define CMAP_H_ - -#define CVECTOR_LINEAR_GROWTH -#include "cvector.h" - -/* note: for ease of porting go code to c, many functions (macros) names - remain similar to the ones used by go */ - -/* note2: this is a very basic map implementation. It does not do any sorting, and only works for basic types (and pointers) that can be compared with the equality operator */ - -#define nil NULL - -#define cmap_elem_destructor_t cvector_elem_destructor_t - -/** - * @brief cmap_declare - The map type used in this library - * @param name - The name associated to a map type. - * @param key_type - The map pair key type. - * @param val_type - The map pair value type. - * @param compare_func - The function used to compare for key_type. Should return value < 0 when a < b, 0 when a == b and value > 0 when a > b. - */ -#define cmap_declare(name, key_type, val_type) \ -typedef struct { \ - key_type key; \ - val_type value; \ -} name##_pair_t; \ -\ -typedef struct { \ - cvector(name##_pair_t) tree; \ - cmap_elem_destructor_t elem_destructor; \ -} name##_map_t; \ -\ -static inline val_type name##_get_( \ - name##_map_t *this, const key_type key) \ -{ \ - if (this) { \ - size_t i; \ - for (i = 0; i < cvector_size(this->tree); i++) { \ - if (key == this->tree[i].key) { \ - return this->tree[i].value; \ - } \ - } \ - } \ - return 0; \ -} \ -\ -static inline val_type name##_get_ptr_( \ - name##_map_t *this, const key_type key) \ -{ \ - if (this) { \ - size_t i; \ - for (i = 0; i < cvector_size(this->tree); i++) { \ - if (key == this->tree[i].key) { \ - return this->tree[i].value; \ - } \ - } \ - } \ - return nil; \ -} \ -\ -static inline void name##_set_( \ - name##_map_t *this, const key_type key, val_type value) \ -{ \ - if (this) { \ - size_t i; \ - for (i = 0; i < cvector_size(this->tree); i++) { \ - if (key == this->tree[i].key) { \ - this->tree[i].value = value; \ - return; \ - } \ - } \ - name##_pair_t new_pair = (name##_pair_t) { key, value }; \ - cvector_push_back(this->tree, new_pair); \ - } \ -} \ -\ -static inline void name##_delete_( \ - name##_map_t *this, const key_type key) \ -{ \ - if (this) { \ - size_t i; \ - for (i = 0; i < cvector_size(this->tree); i++) { \ - if (key == this->tree[i].key) { \ - cvector_erase(this->tree, i); \ - return; \ - } \ - } \ - } \ -} \ -\ -static inline name##_map_t* name##_map_make_(void) \ -{ \ - name##_map_t *map = (name##_map_t*) malloc(sizeof(name##_map_t)); \ - if (map) { \ - map->tree = nil; \ - cvector_init(map->tree, 0, nil); \ - return map; \ - } \ - return nil; \ -} \ -\ -static inline void name##_clear_(name##_map_t *this) \ -{ \ - if (this) { \ - cvector_free(this->tree); \ - free(this); \ - } \ -} \ -\ - - -/** - * @brief cmap - The map type used in this library - * @param name - The name associated to a map type. - */ -#define cmap(name) name##_map_t * - -/** - * @brief cmap_make - creates a new map. Automatically initializes the map. - * @param name - the name asociated to the map type - * @return a pointer to a new map. - */ -#define cmap_make(name) name##_map_make_() - -/** - * @brief cmap_size - gets the current size of the map - * @param map_ptr - the map pointer - * @return the size as a size_t - */ -#define cmap_len(map_ptr) cvector_size(map_ptr->tree) - -/** - * @brief cmap_get - gets value associated to a key. - * @param name - the name asociated to the map type - * @param map_ptr - the map pointer - * @param key - the key to search for - * @return the value associated to a key - */ -#define cmap_get(name, map_ptr, key) name##_get_(map_ptr, key) - -/** - * @brief cmap_get-ptr - gets ptr_value associated to a key. Use it to avoid assigning a ptr to 0. - * @param name - the name asociated to the map type - * @param map_ptr - the map pointer - * @param key - the key to search for - * @return the value associated to a key - */ -#define cmap_get_ptr(name, map_ptr, key) name##_get_ptr_(map_ptr, key) - - -/** - * @brief cmap_set - sets value associated to a key. - * @param name - the name asociated to the map type - * @param map_ptr - the map pointer - * @param key - the key to search for - * @param value - the new value - * @return void - */ -#define cmap_set(name, map_ptr, key, val) name##_set_(map_ptr, key, val) - -/** - * @brief cmap_delete - deletes map entry associated to a key. - * @param name - the name asociated to the map type - * @param map_ptr - the map pointer - * @param key - the key to search for - * @return void - */ -#define cmap_delete(name, map_ptr, key) name##_delete_(map_ptr, key) - -/** - * @brief cmap_set_elem_destructor - set the element destructor function - * used to clean up removed elements. The map must NOT be NULL for this to do anything. - * @param map_ptr - the map pointer - * @param elem_destructor_fn - function pointer of type cvector_elem_destructor_t used to destroy elements - * @return void - */ -#define cmap_set_elem_destructor(map_ptr, elem_destructor_fn) \ - cvector_set_elem_destructor(map_ptr->tree, elem_destructor_fn) - -/** - * @brief cmap_clear - deletes all map entries. And frees memory is an element destructor was set previously. - * @param name - the name asociated to the map type - * @param map_ptr - the map pointer - * @return void - */ -#define cmap_clear(name, map_ptr) name##_clear_(map_ptr) - -/** - * @brief cmap_iterator - The iterator type used for cmap - * @param type The type of iterator to act on. - */ -#define cmap_iterator(name) cvector_iterator(name##_pair_t) - -/** - * @brief cmap_begin - returns an iterator to first element of the vector - * @param map_ptr - the map pointer - * @return a pointer to the first element (or NULL) - */ -#define cmap_begin(map_ptr) ((map_ptr) ? cvector_begin(map_ptr->tree) : nil) - -/** - * @brief cmap_end - returns an iterator to one past the last element of the vector - * @param map_ptrs - the map pointer - * @return a pointer to one past the last element (or NULL) - */ -#define cmap_end(map_ptr) ((map_ptr) ? cvector_end(map_ptr->tree) : nil) - -#endif /* CMAP_H_ */ diff --git a/firmware/target/hosted/ctru/lib/cslice.h b/firmware/target/hosted/ctru/lib/cslice.h deleted file mode 100644 index 36ec6d6faa..0000000000 --- a/firmware/target/hosted/ctru/lib/cslice.h +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef CSLICE_H_ -#define CSLICE_H_ - -#define CVECTOR_LINEAR_GROWTH -#include "cvector.h" - -/* note: for ease of porting go code to c, many functions (macros) names - remain similar to the ones used by go */ - -#define nil NULL - -/** - * @brief cslice - The slice type used in this library - * @param type The type of slice to act on. - */ -#define cslice(type) cvector(type) - -/** - * @brief cslice_make - creates a new slice. Automatically initializes the slice. - * @param slice - the slice - * @param count - new size of the slice - * @param value - the value to initialize new elements with - * @return void - */ -#define cslice_make(slice, capacity, value) \ - do { \ - slice = nil; \ - cvector_init(slice, capacity, nil); \ - cvector_resize(slice, capacity, value); \ - } while(0) - -/** - * @brief cslice_size - gets the current size of the slice - * @param slice - the slice - * @return the size as a size_t - */ -#define cslice_len(slice) cvector_size(slice) - -/** - * @brief cslice_capacity - gets the current capacity of the slice - * @param slice - the slice - * @return the capacity as a size_t - */ -#define cslice_cap(slice) cvector_capacity(slice) - -/** - * @brief cslice_set_elem_destructor - set the element destructor function - * used to clean up removed elements. The vector must NOT be NULL for this to do anything. - * @param slice - the slice - * @param elem_destructor_fn - function pointer of type cslice_elem_destructor_t used to destroy elements - * @return void - */ -#define cslice_set_elem_destructor(slice, elem_destructor_fn) \ - cvector_set_elem_destructor(slice, elem_destructor_fn) - -/** - * @brief cslice_free - frees all memory associated with the slice - * @param slice - the slice - * @return void - */ -#define cslice_clear(slice) cvector_free(slice) - -#endif /* CSLICE_H_ */ diff --git a/firmware/target/hosted/ctru/lib/cvector.h b/firmware/target/hosted/ctru/lib/cvector.h deleted file mode 100644 index 5045025c73..0000000000 --- a/firmware/target/hosted/ctru/lib/cvector.h +++ /dev/null @@ -1,549 +0,0 @@ -#ifndef CVECTOR_H_ -#define CVECTOR_H_ -/** - * @copyright Copyright (c) 2015 Evan Teran, - * License: The MIT License (MIT) - * @brief cvector heap implemented using C library malloc() - * @file cvector.h - */ - -/* in case C library malloc() needs extra protection, - * allow these defines to be overridden. - */ -/* functions for allocation and deallocation need to correspond to each other, fall back to C library functions if not all are overridden */ -#if !defined(cvector_clib_free) || !defined(cvector_clib_malloc) || !defined(cvector_clib_calloc) || !defined(cvector_clib_realloc) -#ifdef cvector_clib_free -#undef cvector_clib_free -#endif -#ifdef cvector_clib_malloc -#undef cvector_clib_malloc -#endif -#ifdef cvector_clib_calloc -#undef cvector_clib_calloc -#endif -#ifdef cvector_clib_realloc -#undef cvector_clib_realloc -#endif -#include -#define cvector_clib_free free -#define cvector_clib_malloc malloc -#define cvector_clib_calloc calloc -#define cvector_clib_realloc realloc -#endif -/* functions independent of memory allocation */ -#ifndef cvector_clib_assert -#include /* for assert */ -#define cvector_clib_assert assert -#endif -#ifndef cvector_clib_memcpy -#include /* for memcpy */ -#define cvector_clib_memcpy memcpy -#endif -#ifndef cvector_clib_memmove -#include /* for memmove */ -#define cvector_clib_memmove memmove -#endif - -/* NOTE: Similar to C's qsort and bsearch, you will receive a T* - * for a vector of Ts. This means that you cannot use `free` directly - * as a destructor. Instead if you have for example a cvector_vector_type(int *) - * you will need to supply a function which casts `elem_ptr` to an `int**` - * and then does a free on what that pointer points to: - * - * ex: - * - * void free_int(void *p) { free(*(int **)p); } - */ -typedef void (*cvector_elem_destructor_t)(void *elem_ptr); - -typedef struct cvector_metadata_t { - size_t size; - size_t capacity; - cvector_elem_destructor_t elem_destructor; -} cvector_metadata_t; - -/** - * @brief cvector_vector_type - The vector type used in this library - * @param type The type of vector to act on. - */ -#define cvector_vector_type(type) type * - -/** - * @brief cvector - Syntactic sugar to retrieve a vector type - * @param type The type of vector to act on. - */ -#define cvector(type) cvector_vector_type(type) - -/** - * @brief cvector_iterator - The iterator type used for cvector - * @param type The type of iterator to act on. - */ -#define cvector_iterator(type) cvector_vector_type(type) - -/** - * @note you can also safely pass a pointer to a cvector iterator to a function - * but you have to update the pointer at the end to update the original - * iterator. - * example: - * void function( cvector_vector_type( type ) * p_it ) - * { - * cvector_vector_type( type ) it = *p_it; - * it ++; - * - * ... - * - * *p_it = it; - * } - */ - -/** - * @brief cvector_vector_type_ptr - helper to make code more "readable" - * @param type - the vector type pointer - */ -#define cvector_ptr_type(type) \ - cvector_vector_type(type) * - -/** - * @brief cvector_vector_ptr_get_iterator/set - helpers to make code more "readable" - * @param it - the vector iterator - * @param ptr - the vector pointer - */ -#define cvector_ptr_get_iterator(ptr) \ - *(ptr) - -#define cvector_ptr_set(ptr, it) \ - *(ptr) = it - -/** - * @brief cvector_vector_container_declare - defined a vector container type - */ -#define cvector_vector_container_declare(name, type) \ -struct cvector_vector_container_##name { \ - cvector_vector_type(type) vector; \ -} - -/** - * @brief cvector_vector_container - used to pass a cvector wrapped inside a container as a function parameter - */ -#define cvector_vector_container(name) \ - struct cvector_vector_container_##name - - -/** - * @brief cvector_vec_to_base - For internal use, converts a vector pointer to a metadata pointer - * @param vec - the vector - * @return the metadata pointer of the vector - * @internal - */ -#define cvector_vec_to_base(vec) \ - (&((cvector_metadata_t *)(void *)(vec))[-1]) - -/** - * @brief cvector_base_to_vec - For internal use, converts a metadata pointer to a vector pointer - * @param ptr - pointer to the metadata - * @return the vector - * @internal - */ -#define cvector_base_to_vec(ptr) \ - ((void *)&((cvector_metadata_t *)(ptr))[1]) - -/** - * @brief cvector_capacity - gets the current capacity of the vector - * @param vec - the vector - * @return the capacity as a size_t - */ -#define cvector_capacity(vec) \ - ((vec) ? cvector_vec_to_base(vec)->capacity : (size_t)0) - -/** - * @brief cvector_size - gets the current size of the vector - * @param vec - the vector - * @return the size as a size_t - */ -#define cvector_size(vec) \ - ((vec) ? cvector_vec_to_base(vec)->size : (size_t)0) - -/** - * @brief cvector_elem_destructor - get the element destructor function used - * to clean up elements - * @param vec - the vector - * @return the function pointer as cvector_elem_destructor_t - */ -#define cvector_elem_destructor(vec) \ - ((vec) ? cvector_vec_to_base(vec)->elem_destructor : NULL) - -/** - * @brief cvector_empty - returns non-zero if the vector is empty - * @param vec - the vector - * @return non-zero if empty, zero if non-empty - */ -#define cvector_empty(vec) \ - (cvector_size(vec) == 0) - -/** - * @brief cvector_reserve - Requests that the vector capacity be at least enough - * to contain n elements. If n is greater than the current vector capacity, the - * function causes the container to reallocate its storage increasing its - * capacity to n (or greater). - * @param vec - the vector - * @param n - Minimum capacity for the vector. - * @return void - */ -#define cvector_reserve(vec, n) \ - do { \ - size_t cv_reserve_cap__ = cvector_capacity(vec); \ - if (cv_reserve_cap__ < (n)) { \ - cvector_grow((vec), (n)); \ - } \ - } while (0) - -/** - * @brief cvector_init - Initialize a vector. The vector must be NULL for this to do anything. - * @param vec - the vector - * @param capacity - vector capacity to reserve - * @param elem_destructor_fn - element destructor function - * @return void - */ -#define cvector_init(vec, capacity, elem_destructor_fn) \ - do { \ - if (!(vec)) { \ - cvector_reserve((vec), capacity); \ - cvector_set_elem_destructor((vec), (elem_destructor_fn)); \ - } \ - } while (0) - -/** - * @brief cvector_init_default - Initialize a vector with default value. The vector must be NULL for this to do anything. Does NOT work for struct types. - * @param vec - the vector - * @param capacity - vector capacity to reserve - * @param elem_destructor_fn - element destructor function - * @return void - */ -#define cvector_init_default(vec, capacity, default) \ - do { \ - if (!(vec)) { \ - cvector_reserve((vec), capacity); \ - cvector_set_elem_destructor((vec), (elem_destructor_fn)); \ - } \ - } while (0) - -/** - * @brief cvector_erase - removes the element at index i from the vector - * @param vec - the vector - * @param i - index of element to remove - * @return void - */ -#define cvector_erase(vec, i) \ - do { \ - if (vec) { \ - const size_t cv_erase_sz__ = cvector_size(vec); \ - if ((i) < cv_erase_sz__) { \ - cvector_elem_destructor_t cv_erase_elem_dtor__ = cvector_elem_destructor(vec); \ - if (cv_erase_elem_dtor__) { \ - cv_erase_elem_dtor__(&(vec)[i]); \ - } \ - cvector_set_size((vec), cv_erase_sz__ - 1); \ - cvector_clib_memmove( \ - (vec) + (i), \ - (vec) + (i) + 1, \ - sizeof(*(vec)) * (cv_erase_sz__ - 1 - (i))); \ - } \ - } \ - } while (0) - -/** - * @brief cvector_clear - erase all of the elements in the vector - * @param vec - the vector - * @return void - */ -#define cvector_clear(vec) \ - do { \ - if (vec) { \ - cvector_elem_destructor_t cv_clear_elem_dtor__ = cvector_elem_destructor(vec); \ - if (cv_clear_elem_dtor__) { \ - size_t cv_clear_i__; \ - for (cv_clear_i__ = 0; cv_clear_i__ < cvector_size(vec); ++cv_clear_i__) { \ - cv_clear_elem_dtor__(&(vec)[cv_clear_i__]); \ - } \ - } \ - cvector_set_size(vec, 0); \ - } \ - } while (0) - -/** - * @brief cvector_free - frees all memory associated with the vector - * @param vec - the vector - * @return void - */ -#define cvector_free(vec) \ - do { \ - if (vec) { \ - void *cv_free_p__ = cvector_vec_to_base(vec); \ - cvector_elem_destructor_t cv_free_elem_dtor__ = cvector_elem_destructor(vec); \ - if (cv_free_elem_dtor__) { \ - size_t cv_free_i__; \ - for (cv_free_i__ = 0; cv_free_i__ < cvector_size(vec); ++cv_free_i__) { \ - cv_free_elem_dtor__(&(vec)[cv_free_i__]); \ - } \ - } \ - cvector_clib_free(cv_free_p__); \ - } \ - } while (0) - -/** - * @brief cvector_begin - returns an iterator to first element of the vector - * @param vec - the vector - * @return a pointer to the first element (or NULL) - */ -#define cvector_begin(vec) \ - (vec) - -/** - * @brief cvector_end - returns an iterator to one past the last element of the vector - * @param vec - the vector - * @return a pointer to one past the last element (or NULL) - */ -#define cvector_end(vec) \ - ((vec) ? &((vec)[cvector_size(vec)]) : NULL) - -/* user request to use linear growth algorithm */ -#ifdef CVECTOR_LINEAR_GROWTH - -/** - * @brief cvector_compute_next_grow - returns an the computed size in next vector grow - * size is increased by 1 - * @param size - current size - * @return size after next vector grow - */ -#define cvector_compute_next_grow(size) \ - ((size) + 1) - -#else - -/** - * @brief cvector_compute_next_grow - returns an the computed size in next vector grow - * size is increased by multiplication of 2 - * @param size - current size - * @return size after next vector grow - */ -#define cvector_compute_next_grow(size) \ - ((size) ? ((size) << 1) : 1) - -#endif /* CVECTOR_LINEAR_GROWTH */ - -/** - * @brief cvector_push_back - adds an element to the end of the vector - * @param vec - the vector - * @param value - the value to add - * @return void - */ -#define cvector_push_back(vec, value) \ - do { \ - size_t cv_push_back_cap__ = cvector_capacity(vec); \ - if (cv_push_back_cap__ <= cvector_size(vec)) { \ - cvector_grow((vec), cvector_compute_next_grow(cv_push_back_cap__)); \ - } \ - (vec)[cvector_size(vec)] = (value); \ - cvector_set_size((vec), cvector_size(vec) + 1); \ - } while (0) - -/** - * @brief cvector_insert - insert element at position pos to the vector - * @param vec - the vector - * @param pos - position in the vector where the new elements are inserted. - * @param val - value to be copied (or moved) to the inserted elements. - * @return void - */ -#define cvector_insert(vec, pos, val) \ - do { \ - size_t cv_insert_cap__ = cvector_capacity(vec); \ - if (cv_insert_cap__ <= cvector_size(vec)) { \ - cvector_grow((vec), cvector_compute_next_grow(cv_insert_cap__)); \ - } \ - if ((pos) < cvector_size(vec)) { \ - cvector_clib_memmove( \ - (vec) + (pos) + 1, \ - (vec) + (pos), \ - sizeof(*(vec)) * ((cvector_size(vec)) - (pos))); \ - } \ - (vec)[(pos)] = (val); \ - cvector_set_size((vec), cvector_size(vec) + 1); \ - } while (0) - -/** - * @brief cvector_pop_back - removes the last element from the vector - * @param vec - the vector - * @return void - */ -#define cvector_pop_back(vec) \ - do { \ - cvector_elem_destructor_t cv_pop_back_elem_dtor__ = cvector_elem_destructor(vec); \ - if (cv_pop_back_elem_dtor__) { \ - cv_pop_back_elem_dtor__(&(vec)[cvector_size(vec) - 1]); \ - } \ - cvector_set_size((vec), cvector_size(vec) - 1); \ - } while (0) - -/** - * @brief cvector_copy - copy a vector - * @param from - the original vector - * @param to - destination to which the function copy to - * @return void - */ -#define cvector_copy(from, to) \ - do { \ - if ((from)) { \ - cvector_grow(to, cvector_size(from)); \ - cvector_set_size(to, cvector_size(from)); \ - cvector_clib_memcpy((to), (from), cvector_size(from) * sizeof(*(from))); \ - } \ - } while (0) - -/** - * @brief cvector_swap - exchanges the content of the vector by the content of another vector of the same type - * @param vec - the original vector - * @param other - the other vector to swap content with - * @param type - the type of both vectors - * @return void - */ -#define cvector_swap(vec, other, type) \ - do { \ - if (vec && other) { \ - cvector_vector_type(type) cv_swap__ = vec; \ - vec = other; \ - other = cv_swap__; \ - } \ - } while (0) - -/** - * @brief cvector_set_capacity - For internal use, sets the capacity variable of the vector - * @param vec - the vector - * @param size - the new capacity to set - * @return void - * @internal - */ -#define cvector_set_capacity(vec, size) \ - do { \ - if (vec) { \ - cvector_vec_to_base(vec)->capacity = (size); \ - } \ - } while (0) - -/** - * @brief cvector_set_size - For internal use, sets the size variable of the vector - * @param vec - the vector - * @param _size - the new capacity to set - * @return void - * @internal - */ -#define cvector_set_size(vec, _size) \ - do { \ - if (vec) { \ - cvector_vec_to_base(vec)->size = (_size); \ - } \ - } while (0) - -/** - * @brief cvector_set_elem_destructor - set the element destructor function - * used to clean up removed elements. The vector must NOT be NULL for this to do anything. - * @param vec - the vector - * @param elem_destructor_fn - function pointer of type cvector_elem_destructor_t used to destroy elements - * @return void - */ -#define cvector_set_elem_destructor(vec, elem_destructor_fn) \ - do { \ - if (vec) { \ - cvector_vec_to_base(vec)->elem_destructor = (elem_destructor_fn); \ - } \ - } while (0) - -/** - * @brief cvector_grow - For internal use, ensures that the vector is at least `count` elements big - * @param vec - the vector - * @param count - the new capacity to set - * @return void - * @internal - */ -#define cvector_grow(vec, count) \ - do { \ - const size_t cv_grow_sz__ = (count) * sizeof(*(vec)) + sizeof(cvector_metadata_t); \ - if (vec) { \ - void *cv_grow_p1__ = cvector_vec_to_base(vec); \ - void *cv_grow_p2__ = cvector_clib_realloc(cv_grow_p1__, cv_grow_sz__); \ - cvector_clib_assert(cv_grow_p2__); \ - (vec) = cvector_base_to_vec(cv_grow_p2__); \ - } else { \ - void *cv_grow_p__ = cvector_clib_malloc(cv_grow_sz__); \ - cvector_clib_assert(cv_grow_p__); \ - (vec) = cvector_base_to_vec(cv_grow_p__); \ - cvector_set_size((vec), 0); \ - cvector_set_elem_destructor((vec), NULL); \ - } \ - cvector_set_capacity((vec), (count)); \ - } while (0) - -/** - * @brief cvector_shrink_to_fit - requests the container to reduce its capacity to fit its size - * @param vec - the vector - * @return void - */ -#define cvector_shrink_to_fit(vec) \ - do { \ - if (vec) { \ - const size_t cv_shrink_to_fit_sz__ = cvector_size(vec); \ - cvector_grow(vec, cv_shrink_to_fit_sz__); \ - } \ - } while (0) - -/** - * @brief cvector_at - returns a reference to the element at position n in the vector. - * @param vec - the vector - * @param n - position of an element in the vector. - * @return the element at the specified position in the vector. - */ -#define cvector_at(vec, n) \ - ((vec) ? (((int)(n) < 0 || (size_t)(n) >= cvector_size(vec)) ? NULL : &(vec)[n]) : NULL) - -/** - * @brief cvector_front - returns a reference to the first element in the vector. Unlike member cvector_begin, which returns an iterator to this same element, this function returns a direct reference. - * @param vec - the vector - * @return a reference to the first element in the vector container. - */ -#define cvector_front(vec) \ - ((vec) ? ((cvector_size(vec) > 0) ? cvector_at(vec, 0) : NULL) : NULL) - -/** - * @brief cvector_back - returns a reference to the last element in the vector.Unlike member cvector_end, which returns an iterator just past this element, this function returns a direct reference. - * @param vec - the vector - * @return a reference to the last element in the vector. - */ -#define cvector_back(vec) \ - ((vec) ? ((cvector_size(vec) > 0) ? cvector_at(vec, cvector_size(vec) - 1) : NULL) : NULL) - -/** - * @brief cvector_resize - resizes the container to contain count elements. - * @param vec - the vector - * @param count - new size of the vector - * @param value - the value to initialize new elements with - * @return void - */ -#define cvector_resize(vec, count, value) \ - do { \ - if (vec) { \ - size_t cv_resize_count__ = (size_t)(count); \ - size_t cv_resize_sz__ = cvector_vec_to_base(vec)->size; \ - if (cv_resize_count__ > cv_resize_sz__) { \ - cvector_reserve((vec), cv_resize_count__); \ - cvector_set_size((vec), cv_resize_count__); \ - do { \ - (vec)[cv_resize_sz__++] = (value); \ - } while (cv_resize_sz__ < cv_resize_count__); \ - } else { \ - while (cv_resize_count__ < cv_resize_sz__--) { \ - cvector_pop_back(vec); \ - } \ - } \ - } \ - } while (0) - -#endif /* CVECTOR_H_ */ diff --git a/firmware/target/hosted/ctru/lib/sys_dir.c b/firmware/target/hosted/ctru/lib/sys_dir.c index 0b9a0300fb..5571d40c8e 100644 --- a/firmware/target/hosted/ctru/lib/sys_dir.c +++ b/firmware/target/hosted/ctru/lib/sys_dir.c @@ -120,7 +120,7 @@ u32 fs_error(void) { /* Initialize the base descriptor */ static void filestr_base_init(struct filestr_base *stream) { - stream->cache = nil; + stream->cache = NULL; stream->handle = 0; stream->size = 0; LightLock_Init(&stream->mtx); diff --git a/firmware/target/hosted/ctru/lib/sys_file.c b/firmware/target/hosted/ctru/lib/sys_file.c index 1df88282d6..fe884b2531 100644 --- a/firmware/target/hosted/ctru/lib/sys_file.c +++ b/firmware/target/hosted/ctru/lib/sys_file.c @@ -53,7 +53,7 @@ static struct filestr_desc u64 *sizep; /* shortcut to file size in fileobj */ } open_streams[MAX_OPEN_FILES] = { - [0 ... MAX_OPEN_FILES-1] = { .stream = { .cache = nil, .flags = 0 } } + [0 ... MAX_OPEN_FILES-1] = { .stream = { .cache = NULL, .flags = 0 } } }; extern FS_Archive sdmcArchive; @@ -65,11 +65,11 @@ static struct filestr_desc * get_filestr(int fildes) if ((unsigned int)fildes >= MAX_OPEN_FILES) file = NULL; - else if (file->stream.cache != nil) + else if (file->stream.cache != NULL) return file; logf("fildes %d: bad file number\n", fildes); - errno = (file && (file->stream.cache == nil)) ? ENXIO : EBADF; + errno = (file && (file->stream.cache == NULL)) ? ENXIO : EBADF; return NULL; } @@ -98,7 +98,7 @@ static int alloc_filestr(struct filestr_desc **filep) for (int fildes = 0; fildes < MAX_OPEN_FILES; fildes++) { struct filestr_desc *file = &open_streams[fildes]; - if (file->stream.cache == nil) + if (file->stream.cache == NULL) { *filep = file; return fildes; @@ -117,10 +117,10 @@ int test_stream_exists_internal(const char *path) Handle handle; Result res = FSUSER_OpenFile(&handle, - sdmcArchive, - fsMakePath(PATH_ASCII, path), - FS_OPEN_READ, - 0); + sdmcArchive, + fsMakePath(PATH_ASCII, path), + FS_OPEN_READ, + 0); if (R_FAILED(res)) { /* not a file, try to open a directory */ res = FSUSER_OpenDirectory(&handle, @@ -234,12 +234,50 @@ static ssize_t readwrite(struct filestr_desc *file, void *buf, size_t nbyte, int rc = 0; int_error_t n_err; - if (write) - n_err = PagerWriteAt(file->stream.cache, (u8 *) buf, nbyte, AtomicLoad(&file->offset)); - else - n_err = PagerReadAt(file->stream.cache, (u8 *) buf, nbyte, AtomicLoad(&file->offset)); + if (write) { + // we will use direct file access for writing + u32 written = 0; + Result res = FSFILE_Write(file->stream.handle, + &written, + AtomicLoad(&file->offset), + buf, + nbyte, + FS_WRITE_FLUSH); + if (R_FAILED(res)) { + n_err.err = "I/O error"; + } - if ((n_err.err != nil) && strcmp(n_err.err, "io.EOF")) { + n_err.n = written; + } + else { + // only use page_reader if buffer size is smaller than page size + if (nbyte < file->stream.cache->size) { + n_err = PageReader_ReadAt(file->stream.cache, + (u8 *) buf, + nbyte, + AtomicLoad(&file->offset)); + } + else { + u32 bytes_read = 0; + Result res = FSFILE_Read(file->stream.handle, + &bytes_read, + AtomicLoad(&file->offset), + buf, + nbyte); + if (R_FAILED(res)) { + n_err.err = "I/O error"; + } + + // io.EOF + if (bytes_read == 0) { + n_err.err = "io.EOF"; + } + + n_err.n = bytes_read; + } + } + + if ((n_err.err != NULL) && strcmp(n_err.err, "io.EOF")) { FILE_ERROR(ERRNO, -3); } @@ -271,7 +309,7 @@ file_error:; /* initialize the base descriptor */ static void filestr_base_init(struct filestr_base *stream) { - stream->cache = nil; + stream->cache = NULL; stream->handle = 0; stream->size = 0; LightLock_Init(&stream->mtx); @@ -281,10 +319,10 @@ int open_internal_inner2(Handle *handle, const char *path, u32 openFlags, u32 at { int rc; Result res = FSUSER_OpenFile(handle, - sdmcArchive, - fsMakePath(PATH_ASCII, path), - openFlags, - attributes); + sdmcArchive, + fsMakePath(PATH_ASCII, path), + openFlags, + attributes); if (R_FAILED(res)) { FILE_ERROR(ERRNO, -1); } @@ -372,21 +410,8 @@ static int open_internal_inner1(const char *path, int oflag) FILE_ERROR(ERRNO, -8); } - int pageSize = 4096; /* 4096 bytes */ - int bufferSize = 512 * 1024; /* 512 kB */ - - /* streamed file formats like flac and mp3 need very large page - sizes to avoid stuttering */ - if (((oflag & O_ACCMODE) == O_RDONLY) && (size > 0x200000)) { - /* printf("open(%s)_BIG_pageSize\n", path); */ - pageSize = 32 * 1024; - bufferSize = MIN(size, defaultBufferSize); - } - - file->stream.cache = NewPagerSize(file->stream.handle, - pageSize, - bufferSize); - if (file->stream.cache == nil) { + file->stream.cache = NewPageReader(file->stream.handle, defaultPageSize); + if (file->stream.cache == NULL) { FILE_ERROR(ERRNO, -7); } @@ -402,10 +427,10 @@ static int open_internal_inner1(const char *path, int oflag) file_error: if (fildes >= 0) { - if (file->stream.cache != nil) { - PagerFlush(file->stream.cache); - PagerClear(file->stream.cache); - file->stream.cache = nil; + if (file->stream.cache != NULL) { + /* FSFILE_Flush(file->stream.handle); */ + PageReader_Free(file->stream.cache); + file->stream.cache = NULL; } FSFILE_Close(file->stream.handle); @@ -445,16 +470,16 @@ int ctru_close(int fildes) /* needs to work even if marked "nonexistant" */ struct filestr_desc *file = &open_streams[fildes]; - if ((unsigned int)fildes >= MAX_OPEN_FILES || (file->stream.cache == nil)) + if ((unsigned int)fildes >= MAX_OPEN_FILES || (file->stream.cache == NULL)) { logf("filedes %d not open\n", fildes); FILE_ERROR(EBADF, -2); } - if (file->stream.cache != nil) { - PagerFlush(file->stream.cache); - PagerClear(file->stream.cache); - file->stream.cache = nil; + if (file->stream.cache != NULL) { + /* FSFILE_Flush(file->stream.handle); */ + PageReader_Free(file->stream.cache); + file->stream.cache = NULL; } FSFILE_Close(file->stream.handle); @@ -490,8 +515,8 @@ int ctru_ftruncate(int fildes, off_t length) FILE_ERROR(EINVAL, -3); } - file_error_t err = PagerTruncate(file->stream.cache, length); - if (err) { + Result res = FSFILE_SetSize(file->stream.handle, length); + if (R_FAILED(res)) { FILE_ERROR(ERRNO, -11); } @@ -521,8 +546,8 @@ int ctru_fsync(int fildes) } /* flush all pending changes to disk */ - file_error_t err = PagerFlush(file->stream.cache); - if (err != nil) { + Result res = FSFILE_Flush(file->stream.handle); + if (R_FAILED(res)) { FILE_ERROR(ERRNO, -3); } @@ -646,10 +671,10 @@ int ctru_rename(const char *old, const char *new) /* open 'old'; it must exist */ Handle open1rc; Result res = FSUSER_OpenFile(&open1rc, - sdmcArchive, - fsMakePath(PATH_ASCII, old), - FS_OPEN_READ, - 0); + sdmcArchive, + fsMakePath(PATH_ASCII, old), + FS_OPEN_READ, + 0); if (R_FAILED(res)) { /* not a file, try to open a directory */ res = FSUSER_OpenDirectory(&open1rc, @@ -774,4 +799,3 @@ ssize_t ctru_readlink(const char *path, char *buf, size_t bufsiz) { return readlink(path, buf, bufsiz); } - diff --git a/firmware/target/hosted/ctru/lib/sys_file.h b/firmware/target/hosted/ctru/lib/sys_file.h index cfed6017fc..112d932b5e 100644 --- a/firmware/target/hosted/ctru/lib/sys_file.h +++ b/firmware/target/hosted/ctru/lib/sys_file.h @@ -32,7 +32,7 @@ #define AtomicAdd(ptr, value) __atomic_add_fetch((u32*)(ptr), value, __ATOMIC_SEQ_CST) struct filestr_base { - Pager* cache; /* buffer IO implementation (cache) */ + PageReader* cache; /* buffer IO implementation (cache) */ Handle handle; /* file handle */ u64 size; /* file size */ int flags; /* stream flags */