diff mbox series

[02/17] fs: fat: handle "." and ".." of root dir correctly with fat_itr_resolve()

Message ID 20180720025723.6736-3-takahiro.akashi@linaro.org
State Superseded
Headers show
Series fs: fat: extend FAT write operations | expand

Commit Message

AKASHI Takahiro July 20, 2018, 2:57 a.m. UTC
FAT's root directory does not have "." nor ".."
So care must be taken when scanning root directory with fat_itr_resolve().
Without this patch, any file path starting with "." or ".." will not be
resolved at all.

Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
---
 fs/fat/fat.c | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

Comments

Heinrich Schuchardt July 20, 2018, 6:09 p.m. UTC | #1
On 07/20/2018 04:57 AM, AKASHI Takahiro wrote:
> FAT's root directory does not have "." nor ".."
> So care must be taken when scanning root directory with fat_itr_resolve().
> Without this patch, any file path starting with "." or ".." will not be
> resolved at all.
> 
> Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> ---
>  fs/fat/fat.c | 21 +++++++++++++++++++++
>  1 file changed, 21 insertions(+)
> 
> diff --git a/fs/fat/fat.c b/fs/fat/fat.c
> index b48f48a751..fd6523c66b 100644
> --- a/fs/fat/fat.c
> +++ b/fs/fat/fat.c
> @@ -927,6 +927,27 @@ static int fat_itr_resolve(fat_itr *itr, const char *path, unsigned type)
>  	while (next[0] && !ISDIRDELIM(next[0]))
>  		next++;
>  
> +	if (itr->is_root) {
> +		/* root dir doesn't have "." nor ".." */

I understand why root has no ../ but  /./ should be valid.

On Linux 'ls /./' displays the root directory.

Best regards

Heinrich

> +		if ((((next - path) == 1) && !strncmp(path, ".", 1)) ||
> +		    (((next - path) == 2) && !strncmp(path, "..", 2))) {
> +			/* point back to itself */
> +			itr->clust = itr->fsdata->root_cluster;
> +			itr->dent = NULL;
> +			itr->remaining = 0;
> +			itr->last_cluster = 0;
> +
> +			if (next[0] == 0) {
> +				if (type & TYPE_DIR)
> +					return 0;
> +				else
> +					return -ENOENT;
> +			}
> +
> +			return fat_itr_resolve(itr, next, type);
> +		}
> +	}
> +
>  	while (fat_itr_next(itr)) {
>  		int match = 0;
>  		unsigned n = max(strlen(itr->name), (size_t)(next - path));
>
AKASHI Takahiro July 23, 2018, 7:55 a.m. UTC | #2
On Fri, Jul 20, 2018 at 08:09:00PM +0200, Heinrich Schuchardt wrote:
> On 07/20/2018 04:57 AM, AKASHI Takahiro wrote:
> > FAT's root directory does not have "." nor ".."
> > So care must be taken when scanning root directory with fat_itr_resolve().
> > Without this patch, any file path starting with "." or ".." will not be
> > resolved at all.
> > 
> > Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> > ---
> >  fs/fat/fat.c | 21 +++++++++++++++++++++
> >  1 file changed, 21 insertions(+)
> > 
> > diff --git a/fs/fat/fat.c b/fs/fat/fat.c
> > index b48f48a751..fd6523c66b 100644
> > --- a/fs/fat/fat.c
> > +++ b/fs/fat/fat.c
> > @@ -927,6 +927,27 @@ static int fat_itr_resolve(fat_itr *itr, const char *path, unsigned type)
> >  	while (next[0] && !ISDIRDELIM(next[0]))
> >  		next++;
> >  
> > +	if (itr->is_root) {
> > +		/* root dir doesn't have "." nor ".." */
> 
> I understand why root has no ../ but  /./ should be valid.

What I meant here is that, according to FAT specification, the root
directory has neither "." directory entry nor ".." in its associated
clusters in contrast to ordinary directories.
So when user specifies "." or ".." (and other variants), we will have to
take special care to handle them correctly.

> On Linux 'ls /./' displays the root directory.

My code works with any of the following paths:
 * .
 * ..
 * /
 * /.
 * /.., or
 * even any combination of above, like
     ./.././.././

Note that "ls /.." on linux also shows the root directory.

Please try.

-Takahiro AKASHI


> Best regards
> 
> Heinrich
> 
> > +		if ((((next - path) == 1) && !strncmp(path, ".", 1)) ||
> > +		    (((next - path) == 2) && !strncmp(path, "..", 2))) {
> > +			/* point back to itself */
> > +			itr->clust = itr->fsdata->root_cluster;
> > +			itr->dent = NULL;
> > +			itr->remaining = 0;
> > +			itr->last_cluster = 0;
> > +
> > +			if (next[0] == 0) {
> > +				if (type & TYPE_DIR)
> > +					return 0;
> > +				else
> > +					return -ENOENT;
> > +			}
> > +
> > +			return fat_itr_resolve(itr, next, type);
> > +		}
> > +	}
> > +
> >  	while (fat_itr_next(itr)) {
> >  		int match = 0;
> >  		unsigned n = max(strlen(itr->name), (size_t)(next - path));
> > 
>
diff mbox series

Patch

diff --git a/fs/fat/fat.c b/fs/fat/fat.c
index b48f48a751..fd6523c66b 100644
--- a/fs/fat/fat.c
+++ b/fs/fat/fat.c
@@ -927,6 +927,27 @@  static int fat_itr_resolve(fat_itr *itr, const char *path, unsigned type)
 	while (next[0] && !ISDIRDELIM(next[0]))
 		next++;
 
+	if (itr->is_root) {
+		/* root dir doesn't have "." nor ".." */
+		if ((((next - path) == 1) && !strncmp(path, ".", 1)) ||
+		    (((next - path) == 2) && !strncmp(path, "..", 2))) {
+			/* point back to itself */
+			itr->clust = itr->fsdata->root_cluster;
+			itr->dent = NULL;
+			itr->remaining = 0;
+			itr->last_cluster = 0;
+
+			if (next[0] == 0) {
+				if (type & TYPE_DIR)
+					return 0;
+				else
+					return -ENOENT;
+			}
+
+			return fat_itr_resolve(itr, next, type);
+		}
+	}
+
 	while (fat_itr_next(itr)) {
 		int match = 0;
 		unsigned n = max(strlen(itr->name), (size_t)(next - path));