mirror of
https://git.planet-casio.com/Lephenixnoir/gint.git
synced 2024-12-28 20:43:36 +01:00
fs: folder support, part 2 (path normalization and root)
This commit is contained in:
parent
9cae0040b5
commit
aed90d9b3c
7 changed files with 177 additions and 19 deletions
|
@ -87,6 +87,26 @@ void fs_free_descriptor(int fd);
|
||||||
itself. */
|
itself. */
|
||||||
int open_generic(fs_descriptor_type_t *type, void *data, int reuse_fd);
|
int open_generic(fs_descriptor_type_t *type, void *data, int reuse_fd);
|
||||||
|
|
||||||
|
/* fs_path_normalize(): Normalize a path to eliminate ., .. and redundant /
|
||||||
|
|
||||||
|
This function creates a copy of the specified path which is an absolute path
|
||||||
|
with redundant / removed and . and .. components resolved. For instance:
|
||||||
|
|
||||||
|
"" -> "/"
|
||||||
|
"/subfolder/./" -> "/subfolder"
|
||||||
|
"/../subfolder/../subfolder" -> "/subfolder"
|
||||||
|
"/../../x/y/../t" -> "/x/t"
|
||||||
|
|
||||||
|
The new string is created with malloc() and should be free()'d after use. */
|
||||||
|
char *fs_path_normalize(char const *path);
|
||||||
|
|
||||||
|
/* fs_path_normalize_fc(): Normalize a path and translate it to FONTCHARACTER
|
||||||
|
|
||||||
|
This function is similar to fs_path_normalize(), but it creates a 16-bit
|
||||||
|
string that starts with \\fls0\ rather than /, and can be used in direct
|
||||||
|
calls to BFile. */
|
||||||
|
uint16_t *fs_path_normalize_fc(char const *path);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "fugue.h"
|
#include "fugue.h"
|
||||||
|
|
||||||
|
@ -63,7 +64,8 @@ off_t fugue_dir_lseek(void *data, off_t offset, int whence)
|
||||||
if(whence == SEEK_END)
|
if(whence == SEEK_END)
|
||||||
offset += dp->count;
|
offset += dp->count;
|
||||||
|
|
||||||
if(offset < 0 || offset >= dp->count) {
|
/* dp->count, being at the end of the enumeration, is a valid offset */
|
||||||
|
if(offset < 0 || offset >= dp->count + 1) {
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -97,6 +99,7 @@ const fs_descriptor_type_t fugue_dir_descriptor_type = {
|
||||||
void *fugue_dir_explore(char const *path)
|
void *fugue_dir_explore(char const *path)
|
||||||
{
|
{
|
||||||
struct BFile_FileInfo info;
|
struct BFile_FileInfo info;
|
||||||
|
char *wildcard=NULL;
|
||||||
uint16_t *fc_path=NULL, *search=NULL;
|
uint16_t *fc_path=NULL, *search=NULL;
|
||||||
|
|
||||||
dir_t *dp = malloc(sizeof *dp);
|
dir_t *dp = malloc(sizeof *dp);
|
||||||
|
@ -111,7 +114,12 @@ void *fugue_dir_explore(char const *path)
|
||||||
fc_path = malloc(512 * sizeof *fc_path);
|
fc_path = malloc(512 * sizeof *fc_path);
|
||||||
if(!fc_path) goto alloc_failure;
|
if(!fc_path) goto alloc_failure;
|
||||||
|
|
||||||
search = utf8_to_fc_alloc(u"\\\\fls0\\", path, u"\\*");
|
wildcard = malloc(strlen(path) + 3);
|
||||||
|
if(!wildcard) goto alloc_failure;
|
||||||
|
strcpy(wildcard, path);
|
||||||
|
strcat(wildcard, "/*");
|
||||||
|
|
||||||
|
search = fs_path_normalize_fc(wildcard);
|
||||||
if(!search) goto alloc_failure;
|
if(!search) goto alloc_failure;
|
||||||
|
|
||||||
rc = BFile_FindFirst(search, &sd, fc_path, &info);
|
rc = BFile_FindFirst(search, &sd, fc_path, &info);
|
||||||
|
@ -142,6 +150,8 @@ void *fugue_dir_explore(char const *path)
|
||||||
|
|
||||||
if(info.type == BFile_Type_File)
|
if(info.type == BFile_Type_File)
|
||||||
ent->d_type = DT_REG;
|
ent->d_type = DT_REG;
|
||||||
|
if(info.type == BFile_Type_Archived)
|
||||||
|
ent->d_type = DT_REG;
|
||||||
if(info.type == BFile_Type_Directory)
|
if(info.type == BFile_Type_Directory)
|
||||||
ent->d_type = DT_DIR;
|
ent->d_type = DT_DIR;
|
||||||
if(info.type == BFile_Type_Dot)
|
if(info.type == BFile_Type_Dot)
|
||||||
|
@ -160,6 +170,7 @@ alloc_failure:
|
||||||
errno = ENOMEM;
|
errno = ENOMEM;
|
||||||
fugue_dir_close(dp);
|
fugue_dir_close(dp);
|
||||||
end:
|
end:
|
||||||
|
free(wildcard);
|
||||||
free(search);
|
free(search);
|
||||||
free(fc_path);
|
free(fc_path);
|
||||||
if(sd >= 0)
|
if(sd >= 0)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include <gint/hardware.h>
|
#include <gint/hardware.h>
|
||||||
#include <gint/bfile.h>
|
#include <gint/bfile.h>
|
||||||
|
#include <gint/fs.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
@ -7,7 +8,7 @@ int fugue_mkdir(char const *path, GUNUSED mode_t mode)
|
||||||
{
|
{
|
||||||
ENOTSUP_IF_NOT_FUGUE(-1);
|
ENOTSUP_IF_NOT_FUGUE(-1);
|
||||||
|
|
||||||
uint16_t *fcpath = utf8_to_fc_alloc(u"\\\\fls0\\", path, NULL);
|
uint16_t *fcpath = fs_path_normalize_fc(path);
|
||||||
if(!fcpath) {
|
if(!fcpath) {
|
||||||
errno = ENOMEM;
|
errno = ENOMEM;
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -16,8 +17,10 @@ int fugue_mkdir(char const *path, GUNUSED mode_t mode)
|
||||||
int rc = BFile_Create(fcpath, BFile_Folder, NULL);
|
int rc = BFile_Create(fcpath, BFile_Folder, NULL);
|
||||||
if(rc < 0) {
|
if(rc < 0) {
|
||||||
errno = bfile_error_to_errno(rc);
|
errno = bfile_error_to_errno(rc);
|
||||||
|
free(fcpath);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(fcpath);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include <gint/bfile.h>
|
#include <gint/bfile.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "fugue.h"
|
#include "fugue.h"
|
||||||
|
|
||||||
|
@ -11,7 +12,7 @@ int fugue_open(char const *path, int flags, GUNUSED mode_t mode)
|
||||||
{
|
{
|
||||||
ENOTSUP_IF_NOT_FUGUE(-1);
|
ENOTSUP_IF_NOT_FUGUE(-1);
|
||||||
|
|
||||||
uint16_t *fcpath = utf8_to_fc_alloc(u"\\\\fls0\\", path, NULL);
|
uint16_t *fcpath = fs_path_normalize_fc(path);
|
||||||
int fugue_fd, err, rc=-1, type, fd=-1;
|
int fugue_fd, err, rc=-1, type, fd=-1;
|
||||||
|
|
||||||
if(!fcpath) {
|
if(!fcpath) {
|
||||||
|
@ -31,21 +32,32 @@ int fugue_open(char const *path, int flags, GUNUSED mode_t mode)
|
||||||
/* Truncation requires the file to be removed/recreated */
|
/* Truncation requires the file to be removed/recreated */
|
||||||
bool trunc = (flags & O_TRUNC) && (flags & O_CREAT);
|
bool trunc = (flags & O_TRUNC) && (flags & O_CREAT);
|
||||||
|
|
||||||
/* Stat the entry */
|
/* Stat the entry. A special case is needed for the root, which doesn't
|
||||||
bool exists = (BFile_Ext_Stat(fcpath, &type, NULL) == 0);
|
respond well. fs_path_normalize_fc() normalizes the path so we just
|
||||||
if(!exists) type = -1;
|
have to check for the fixed string "\\fls0\". */
|
||||||
|
bool exists;
|
||||||
|
if(!memcmp(fcpath, u"\\\\fls0\\", 16)) {
|
||||||
|
exists = true;
|
||||||
|
type = BFile_Type_Directory;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
exists = (BFile_Ext_Stat(fcpath, &type, NULL) == 0);
|
||||||
|
if(!exists) type = -1;
|
||||||
|
}
|
||||||
|
|
||||||
/* If the entry exists and O_EXCL was requested, fail. */
|
/* If the entry exists and O_EXCL was requested, fail. */
|
||||||
if(exists && excl) {
|
if(exists && excl) {
|
||||||
errno = EEXIST;
|
errno = EEXIST;
|
||||||
return -1;
|
rc = -1;
|
||||||
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the entry is not a directory but O_DIRECTORY is set, fail. If the
|
/* If the entry is not a directory but O_DIRECTORY is set, fail. If the
|
||||||
directory doesn't exist, we fail regardless of O_CREAT. */
|
directory doesn't exist, we fail regardless of O_CREAT. */
|
||||||
if((flags & O_DIRECTORY) && type != BFile_Type_Directory) {
|
if((flags & O_DIRECTORY) && type != BFile_Type_Directory) {
|
||||||
errno = (exists ? ENOTDIR : ENOENT);
|
errno = (exists ? ENOTDIR : ENOENT);
|
||||||
return -1;
|
rc = -1;
|
||||||
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the entry is a directory, open it as such */
|
/* If the entry is a directory, open it as such */
|
||||||
|
@ -83,6 +95,7 @@ int fugue_open(char const *path, int flags, GUNUSED mode_t mode)
|
||||||
err = BFile_Create(fcpath, BFile_File, &size);
|
err = BFile_Create(fcpath, BFile_File, &size);
|
||||||
if(err < 0) {
|
if(err < 0) {
|
||||||
errno = bfile_error_to_errno(err);
|
errno = bfile_error_to_errno(err);
|
||||||
|
rc = -1;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
fugue_fd = BFile_Open(fcpath, bfile_mode);
|
fugue_fd = BFile_Open(fcpath, bfile_mode);
|
||||||
|
@ -104,7 +117,7 @@ int fugue_open(char const *path, int flags, GUNUSED mode_t mode)
|
||||||
.type = &fugue_descriptor_type,
|
.type = &fugue_descriptor_type,
|
||||||
.data = (void *)fugue_fd,
|
.data = (void *)fugue_fd,
|
||||||
};
|
};
|
||||||
fd = fs_create_descriptor(&data);
|
rc = fd = fs_create_descriptor(&data);
|
||||||
|
|
||||||
if(fd == -1) {
|
if(fd == -1) {
|
||||||
BFile_Close(fugue_fd);
|
BFile_Close(fugue_fd);
|
||||||
|
@ -112,7 +125,6 @@ int fugue_open(char const *path, int flags, GUNUSED mode_t mode)
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = fd;
|
|
||||||
end:
|
end:
|
||||||
free(fcpath);
|
free(fcpath);
|
||||||
return rc;
|
return rc;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include <gint/hardware.h>
|
#include <gint/hardware.h>
|
||||||
#include <gint/bfile.h>
|
#include <gint/bfile.h>
|
||||||
|
#include <gint/fs.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
@ -7,7 +8,7 @@ int fugue_unlink(char const *path)
|
||||||
{
|
{
|
||||||
ENOTSUP_IF_NOT_FUGUE(-1);
|
ENOTSUP_IF_NOT_FUGUE(-1);
|
||||||
|
|
||||||
uint16_t *fcpath = utf8_to_fc_alloc(u"\\\\fls0\\", path, NULL);
|
uint16_t *fcpath = fs_path_normalize_fc(path);
|
||||||
if(!fcpath) {
|
if(!fcpath) {
|
||||||
errno = ENOMEM;
|
errno = ENOMEM;
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -16,9 +17,11 @@ int fugue_unlink(char const *path)
|
||||||
int err = BFile_Remove(fcpath);
|
int err = BFile_Remove(fcpath);
|
||||||
if(err < 0) {
|
if(err < 0) {
|
||||||
errno = bfile_error_to_errno(err);
|
errno = bfile_error_to_errno(err);
|
||||||
|
free(fcpath);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(fcpath);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <stdarg.h>
|
||||||
#include <gint/bfile.h>
|
#include <gint/bfile.h>
|
||||||
|
|
||||||
int bfile_error_to_errno(int e)
|
int bfile_error_to_errno(int e)
|
||||||
|
@ -52,7 +53,7 @@ void utf8_to_fc(uint16_t *fc, char const *utf8, size_t fc_len)
|
||||||
fc[j++] = utf8[i];
|
fc[j++] = utf8[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
while(j < fc_len)
|
if(j < fc_len)
|
||||||
fc[j++] = 0;
|
fc[j++] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,7 +68,7 @@ void fc_to_utf8(char *utf8, uint16_t const *fc, size_t utf8_len)
|
||||||
utf8[j++] = fc[i];
|
utf8[j++] = fc[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
while(j < utf8_len)
|
if(j < utf8_len)
|
||||||
utf8[j++] = 0;
|
utf8[j++] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,3 +107,111 @@ char *fc_to_utf8_alloc(uint16_t const *fc)
|
||||||
fc_to_utf8(utf8, fc, len+1);
|
fc_to_utf8(utf8, fc, len+1);
|
||||||
return utf8;
|
return utf8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Split a path into components. Only the top array needs to be freed */
|
||||||
|
char **fs_split_components(char *path, int *count)
|
||||||
|
{
|
||||||
|
char **comps = NULL;
|
||||||
|
*count = 0;
|
||||||
|
int allocated = 0;
|
||||||
|
|
||||||
|
char *token = strtok(path, "/");
|
||||||
|
|
||||||
|
while(token) {
|
||||||
|
if(*count + 1 > allocated) {
|
||||||
|
allocated += 8;
|
||||||
|
char **new_comps = realloc(comps,
|
||||||
|
allocated * sizeof *comps);
|
||||||
|
if(!new_comps) {
|
||||||
|
*count = -1;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
comps = new_comps;
|
||||||
|
}
|
||||||
|
comps[*count] = token;
|
||||||
|
*count += 1;
|
||||||
|
|
||||||
|
token = strtok(NULL, "/");
|
||||||
|
}
|
||||||
|
|
||||||
|
return comps;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generalization of fs_path_normalize(). Returns a [char *] if use_fc=false,
|
||||||
|
otherwise returns an [uint16_t *]. */
|
||||||
|
static void *path_normalize(char const *path, bool use_fc)
|
||||||
|
{
|
||||||
|
char *path_dup = strdup(path);
|
||||||
|
if(!path_dup) return NULL;
|
||||||
|
|
||||||
|
int components=0;
|
||||||
|
char **comps = fs_split_components(path_dup, &components);
|
||||||
|
if(components == -1) {
|
||||||
|
free(path_dup);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now rewrite comps[] to skip "." and apply ".." */
|
||||||
|
int wr = 0;
|
||||||
|
for(int rd=0; rd < components; rd++) {
|
||||||
|
char *comp = comps[rd];
|
||||||
|
if(!strcmp(comp, "."))
|
||||||
|
continue;
|
||||||
|
else if(!strcmp(comp, ".."))
|
||||||
|
wr -= (wr > 0);
|
||||||
|
else
|
||||||
|
comps[wr++] = comp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Count total length */
|
||||||
|
int length = (use_fc ? 7 : 1) + (wr >= 1 ? wr - 1 : 0);
|
||||||
|
for(int i = 0; i < wr; i++) {
|
||||||
|
length += utf8_len(comps[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate string then copy */
|
||||||
|
if(use_fc) {
|
||||||
|
uint16_t *fc = malloc((length + 1) * sizeof *fc);
|
||||||
|
uint16_t *fc_init = fc;
|
||||||
|
|
||||||
|
memcpy(fc, u"\\\\fls0\\", 7*2);
|
||||||
|
fc += 7;
|
||||||
|
|
||||||
|
for(int i = 0; i < wr; i++) {
|
||||||
|
if(i > 0) *fc++ = '\\';
|
||||||
|
utf8_to_fc(fc, comps[i], (size_t)-1);
|
||||||
|
fc += utf8_len(comps[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
*fc++ = 0;
|
||||||
|
free(path_dup);
|
||||||
|
free(comps);
|
||||||
|
return fc_init;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
char *utf8 = malloc(length + 1);
|
||||||
|
char *utf8_init = utf8;
|
||||||
|
*utf8++ = '/';
|
||||||
|
|
||||||
|
for(int i = 0; i < wr; i++) {
|
||||||
|
if(i > 0) *utf8++ = '/';
|
||||||
|
strcpy(utf8, comps[i]);
|
||||||
|
utf8 += utf8_len(comps[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
*utf8++ = 0;
|
||||||
|
free(path_dup);
|
||||||
|
free(comps);
|
||||||
|
return utf8_init;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char *fs_path_normalize(char const *path)
|
||||||
|
{
|
||||||
|
return path_normalize(path, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t *fs_path_normalize_fc(char const *path)
|
||||||
|
{
|
||||||
|
return path_normalize(path, true);
|
||||||
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ extern "C" {
|
||||||
if(gint[HWFS] != HWFS_FUGUE) { errno = ENOTSUP; return (rc); }
|
if(gint[HWFS] != HWFS_FUGUE) { errno = ENOTSUP; return (rc); }
|
||||||
|
|
||||||
/* Translate common BFile error codes to errno values. */
|
/* Translate common BFile error codes to errno values. */
|
||||||
extern int bfile_error_to_errno(int bfile_error_code);
|
int bfile_error_to_errno(int bfile_error_code);
|
||||||
|
|
||||||
/* TODO: These functions do not actually translate special characters between
|
/* TODO: These functions do not actually translate special characters between
|
||||||
encodings, they simply strip them. */
|
encodings, they simply strip them. */
|
||||||
|
@ -26,17 +26,17 @@ size_t fc_len(uint16_t const *fc);
|
||||||
|
|
||||||
/* Convert UTF-8 to FONTCHARACTER; outputs fc_len characters with padding. If
|
/* Convert UTF-8 to FONTCHARACTER; outputs fc_len characters with padding. If
|
||||||
fc[fc_len-1] is not 0 after the call, then fc is too short. */
|
fc[fc_len-1] is not 0 after the call, then fc is too short. */
|
||||||
extern void utf8_to_fc(uint16_t *fc, char const *utf8, size_t fc_len);
|
void utf8_to_fc(uint16_t *fc, char const *utf8, size_t fc_len);
|
||||||
|
|
||||||
/* Same in the other direction. */
|
/* Same in the other direction. */
|
||||||
extern void fc_to_utf8(char *utf8, uint16_t const *fc, size_t utf8_len);
|
void fc_to_utf8(char *utf8, uint16_t const *fc, size_t utf8_len);
|
||||||
|
|
||||||
/* Same as utf8_to_fc() but allocates a string with malloc(). */
|
/* Same as utf8_to_fc() but allocates a string with malloc(). */
|
||||||
extern uint16_t *utf8_to_fc_alloc(uint16_t *prefix, char const *utf8,
|
uint16_t *utf8_to_fc_alloc(uint16_t *prefix, char const *utf8,
|
||||||
uint16_t *suffix);
|
uint16_t *suffix);
|
||||||
|
|
||||||
/* Same as fc_to_utf8() but allocates a string with malloc(). */
|
/* Same as fc_to_utf8() but allocates a string with malloc(). */
|
||||||
extern char *fc_to_utf8_alloc(uint16_t const *fc);
|
char *fc_to_utf8_alloc(uint16_t const *fc);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue