mirror of
https://git.planet-casio.com/Lephenixnoir/gint.git
synced 2024-12-28 04:23: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. */
|
||||
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
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "util.h"
|
||||
#include "fugue.h"
|
||||
|
||||
|
@ -63,7 +64,8 @@ off_t fugue_dir_lseek(void *data, off_t offset, int whence)
|
|||
if(whence == SEEK_END)
|
||||
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;
|
||||
return -1;
|
||||
}
|
||||
|
@ -97,6 +99,7 @@ const fs_descriptor_type_t fugue_dir_descriptor_type = {
|
|||
void *fugue_dir_explore(char const *path)
|
||||
{
|
||||
struct BFile_FileInfo info;
|
||||
char *wildcard=NULL;
|
||||
uint16_t *fc_path=NULL, *search=NULL;
|
||||
|
||||
dir_t *dp = malloc(sizeof *dp);
|
||||
|
@ -111,7 +114,12 @@ void *fugue_dir_explore(char const *path)
|
|||
fc_path = malloc(512 * sizeof *fc_path);
|
||||
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;
|
||||
|
||||
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)
|
||||
ent->d_type = DT_REG;
|
||||
if(info.type == BFile_Type_Archived)
|
||||
ent->d_type = DT_REG;
|
||||
if(info.type == BFile_Type_Directory)
|
||||
ent->d_type = DT_DIR;
|
||||
if(info.type == BFile_Type_Dot)
|
||||
|
@ -160,6 +170,7 @@ alloc_failure:
|
|||
errno = ENOMEM;
|
||||
fugue_dir_close(dp);
|
||||
end:
|
||||
free(wildcard);
|
||||
free(search);
|
||||
free(fc_path);
|
||||
if(sd >= 0)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include <gint/hardware.h>
|
||||
#include <gint/bfile.h>
|
||||
#include <gint/fs.h>
|
||||
#include <errno.h>
|
||||
#include "util.h"
|
||||
|
||||
|
@ -7,7 +8,7 @@ int fugue_mkdir(char const *path, GUNUSED mode_t mode)
|
|||
{
|
||||
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) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
|
@ -16,8 +17,10 @@ int fugue_mkdir(char const *path, GUNUSED mode_t mode)
|
|||
int rc = BFile_Create(fcpath, BFile_Folder, NULL);
|
||||
if(rc < 0) {
|
||||
errno = bfile_error_to_errno(rc);
|
||||
free(fcpath);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(fcpath);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include <gint/bfile.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include "util.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);
|
||||
|
||||
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;
|
||||
|
||||
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 */
|
||||
bool trunc = (flags & O_TRUNC) && (flags & O_CREAT);
|
||||
|
||||
/* Stat the entry */
|
||||
bool exists = (BFile_Ext_Stat(fcpath, &type, NULL) == 0);
|
||||
if(!exists) type = -1;
|
||||
/* Stat the entry. A special case is needed for the root, which doesn't
|
||||
respond well. fs_path_normalize_fc() normalizes the path so we just
|
||||
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(exists && excl) {
|
||||
errno = EEXIST;
|
||||
return -1;
|
||||
rc = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
if((flags & O_DIRECTORY) && type != BFile_Type_Directory) {
|
||||
errno = (exists ? ENOTDIR : ENOENT);
|
||||
return -1;
|
||||
rc = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
if(err < 0) {
|
||||
errno = bfile_error_to_errno(err);
|
||||
rc = -1;
|
||||
goto end;
|
||||
}
|
||||
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,
|
||||
.data = (void *)fugue_fd,
|
||||
};
|
||||
fd = fs_create_descriptor(&data);
|
||||
rc = fd = fs_create_descriptor(&data);
|
||||
|
||||
if(fd == -1) {
|
||||
BFile_Close(fugue_fd);
|
||||
|
@ -112,7 +125,6 @@ int fugue_open(char const *path, int flags, GUNUSED mode_t mode)
|
|||
goto end;
|
||||
}
|
||||
|
||||
rc = fd;
|
||||
end:
|
||||
free(fcpath);
|
||||
return rc;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include <gint/hardware.h>
|
||||
#include <gint/bfile.h>
|
||||
#include <gint/fs.h>
|
||||
#include <errno.h>
|
||||
#include "util.h"
|
||||
|
||||
|
@ -7,7 +8,7 @@ int fugue_unlink(char const *path)
|
|||
{
|
||||
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) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
|
@ -16,9 +17,11 @@ int fugue_unlink(char const *path)
|
|||
int err = BFile_Remove(fcpath);
|
||||
if(err < 0) {
|
||||
errno = bfile_error_to_errno(err);
|
||||
free(fcpath);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(fcpath);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <gint/bfile.h>
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
while(j < fc_len)
|
||||
if(j < fc_len)
|
||||
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];
|
||||
}
|
||||
|
||||
while(j < utf8_len)
|
||||
if(j < utf8_len)
|
||||
utf8[j++] = 0;
|
||||
}
|
||||
|
||||
|
@ -106,3 +107,111 @@ char *fc_to_utf8_alloc(uint16_t const *fc)
|
|||
fc_to_utf8(utf8, fc, len+1);
|
||||
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); }
|
||||
|
||||
/* 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
|
||||
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
|
||||
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. */
|
||||
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(). */
|
||||
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);
|
||||
|
||||
/* 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
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue