git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@15427 27425a3e-05d8-49a3-a47f-9c15f0e5edd8

This commit is contained in:
Giovanni Di Sirio 2022-02-01 14:15:50 +00:00
parent 524e171965
commit 8ed8c6122e
4 changed files with 107 additions and 25 deletions

View File

@ -68,6 +68,7 @@
#define CH_RET_ENOSYS CH_ENCODE_ERROR(ENOSYS) /* Syscall not implemented */
#define CH_RET_EOVERFLOW CH_ENCODE_ERROR(EOVERFLOW) /* File offset overflow */
#define CH_RET_ENOEXEC CH_ENCODE_ERROR(ENOEXEC) /* Invalid executable */
#define CH_RET_EXDEV CH_ENCODE_ERROR(EXDEV) /* Not same volume */
/** @} */
/*===========================================================================*/

View File

@ -61,6 +61,7 @@ extern "C" {
size_t path_add_extension(char *dst, const char *ext, size_t size);
size_t path_copy_element(const char **pathp, char *dst, size_t size);
size_t path_get_element(const char **pathp, char *dst, size_t size);
size_t path_match_element(const char *path, const char *match, size_t size);
size_t path_normalize(char *dst, const char *src, size_t size);
#ifdef __cplusplus
}

View File

@ -211,7 +211,7 @@ size_t path_add_extension(char *dst, const char *ext, size_t size) {
* @note It can return an empty element, it has to be detected outside.
*
* @param[in, out] pathp Pointer to the path under parsing.
* @param[out] dst Buffer for the extracted path element
* @param[out] dst Buffer for the extracted path element.
* @param[in] size Destination buffer size.
* @return The size of the fetched path element, it does
* not fetch beyond @p size.
@ -254,7 +254,7 @@ size_t path_copy_element(const char **pathp, char *dst, size_t size) {
* @note It can return an empty element, it has to be detected outside.
*
* @param[in, out] pathp Pointer to the path under parsing.
* @param[out] dst Buffer for the extracted path element
* @param[out] dst Buffer for the extracted path element.
* @param[in] size Destination buffer size.
* @return The size of the fetched path element, it does
* not fetch beyond @p size.
@ -272,6 +272,45 @@ size_t path_get_element(const char **pathp, char *dst, size_t size) {
return n;
}
/**
* @brief Verifies that the next path element is equal to the match string.
*
* @param[in] path The source path.
* @param[in] match String to be matched.
* @param[in] size Destination buffer size.
* @return The size of the matched path element, it does
* not match beyond @p size.
* @retval 0 Null element.
* @retval size Buffer overflow or no match.
*/
size_t path_match_element(const char *path, const char *match, size_t size) {
size_t n;
n = (size_t)0;
while (true) {
char c1 = *path;
char c2 = *match;
/* Path elements must be terminated by a separator or an end-of-string.*/
if ((c1 == '/') || (c1 == '\0')) {
return c2 == '\0' ? n : size;
}
if (c1 != c2) {
return size;
}
path++;
match++;
n++;
/* Exceeding the maximum length considering the space for the final zero.*/
if (n >= size) {
return size;
}
}
}
/**
* @brief Normalizes an absolute path.
* @note The destination buffer can be the same of the source buffer.

View File

@ -100,23 +100,15 @@ static struct {
static msg_t match_driver(vfs_overlay_driver_c *odp,
const char **pathp,
vfs_driver_c **vdpp) {
char fname[VFS_CFG_NAMELEN_MAX + 1];
size_t n;
msg_t ret;
do {
unsigned i;
n = path_get_element(pathp, fname, VFS_CFG_NAMELEN_MAX + 1);
if (n >= VFS_CFG_NAMELEN_MAX + 1) {
ret = CH_RET_ENAMETOOLONG;
break;
}
/* Searching among registered drivers.*/
i = 0U;
while (i < odp->next_driver) {
if (memcmp(fname, odp->names[i], n) == 0) {
size_t n;
n = path_match_element(*pathp, odp->names[i], VFS_CFG_NAMELEN_MAX + 1);
if (n < VFS_CFG_NAMELEN_MAX + 1) {
*pathp += n;
*vdpp = odp->drivers[i];
return CH_RET_SUCCESS;
}
@ -124,11 +116,7 @@ static msg_t match_driver(vfs_overlay_driver_c *odp,
i++;
}
ret = CH_RET_ENOENT;
}
while (false);
return ret;
return CH_RET_ENOENT;
}
static const char *get_current_directory(vfs_overlay_driver_c *drvp) {
@ -526,7 +514,10 @@ msg_t drv_rename(void *instance, const char *oldpath, const char *newpath) {
}
do {
msg_t oldret, newret;
vfs_overlay_driver_c *drvp = (vfs_overlay_driver_c *)instance;
vfs_driver_c *olddp, *newdp;
const char *op, *np;
/* Building the absolute paths based on current directory.*/
ret = build_absolute_path(drvp, oldbuf, oldpath);
@ -534,7 +525,57 @@ msg_t drv_rename(void *instance, const char *oldpath, const char *newpath) {
ret = build_absolute_path(drvp, newbuf, newpath);
CH_BREAK_ON_ERROR(ret);
/* Skipping root separators.*/
op = oldbuf + 1;
np = newbuf + 1;
/* Searching for a match among registered drivers.*/
oldret = match_driver(drvp, &op, &olddp);
newret = match_driver(drvp, &np, &newdp);
/* There are various combinations to consider.*/
if (!CH_RET_IS_ERROR(oldret) && !CH_RET_IS_ERROR(newret)) {
/* If paths both refer to registered drivers then must refer to
the same driver, we cannot do a rename across drivers.*/
if (olddp == newdp) {
/* Delegating node renaming to the registered driver.*/
ret = olddp->vmt->rename((void *)olddp, op, np);
}
else {
/* Mixed, not allowing it.*/
ret = CH_RET_EXDEV;
}
}
else if (CH_RET_IS_ERROR(oldret) && CH_RET_IS_ERROR(newret)) {
/* If both paths refer to the overlaid driver then passing down the
request.*/
if (drvp->overlaid_drv != NULL) {
/* Processing the prefix, if defined.*/
if (drvp->path_prefix != NULL) {
if (path_prepend(oldbuf,
drvp->path_prefix,
VFS_CFG_PATHLEN_MAX + 1) == (size_t)0) {
ret = CH_RET_ENAMETOOLONG;
break;
}
if (path_prepend(newbuf,
drvp->path_prefix,
VFS_CFG_PATHLEN_MAX + 1) == (size_t)0) {
ret = CH_RET_ENAMETOOLONG;
break;
}
}
/* Passing the combined path to the overlaid driver.*/
ret = drvp->overlaid_drv->vmt->rename((void *)drvp->overlaid_drv,
oldbuf, newbuf);
}
}
else {
/* Mixed, not allowing it.*/
ret = CH_RET_EXDEV;
}
} while (false);
/* Buffers returned, note, in reverse order.*/