diff mbox series

[v2] statvfs01: Convert to new LTP API

Message ID 20221130070500.28664-1-akumar@suse.de
State Superseded
Headers show
Series [v2] statvfs01: Convert to new LTP API | expand

Commit Message

Avinesh Kumar Nov. 30, 2022, 7:05 a.m. UTC
Removed the TINFO statements,
Added a validation of statvfs.f_namemax field by trying to create
files of valid and invalid length names.

Signed-off-by: Avinesh Kumar <akumar@suse.de>
---
 testcases/kernel/syscalls/statvfs/statvfs01.c | 106 ++++++------------
 1 file changed, 34 insertions(+), 72 deletions(-)

Comments

Petr Vorel Nov. 30, 2022, 8:52 a.m. UTC | #1
Hi Avinesh,

> Removed the TINFO statements,
> Added a validation of statvfs.f_namemax field by trying to create
> files of valid and invalid length names.
Very nice rewrite, thanks for adding this veryfication.
It'd be nice to update this in docparse description.

> +
> +/*\
> + * [Description]
> + *
> + * Verify that statvfs() executes successfully for all
> + * available filesystems.
e.g.:
Verify that statvfs() executes successfully for all
available filesystems. Verify statvfs.f_namemax field
by trying to create files of valid and invalid length names.

I can merge it with this change.

Reviewed-by: Petr Vorel <pvorel@suse.cz>

...
> +static struct tst_test test = {
> +	.test_all = run,
> +	.setup = setup,
> +	.needs_root = 1,
> +	.mount_device = 1,
> +	.mntpoint = MNT_POINT,
> +	.all_filesystems = 1,
> +	.skip_filesystems = (const char *const[]) {
> +		"vfat",
> +		"exfat",
I was looking what's wrong with vfat and exfat.
statvfs.f_namemax returns 1530, which is obviously too long, thus valid_fname
obviously returns ENAMETOOLONG (36). Tested on 6.1.0-rc6-1.g4c01546-default.
I wonder why, isn't that a bug?

Kind regards,
Petr
Petr Vorel Nov. 30, 2022, 9:50 a.m. UTC | #2
Hi all,

...
> > +static struct tst_test test = {
> > +	.test_all = run,
> > +	.setup = setup,
> > +	.needs_root = 1,
> > +	.mount_device = 1,
> > +	.mntpoint = MNT_POINT,
> > +	.all_filesystems = 1,
> > +	.skip_filesystems = (const char *const[]) {
> > +		"vfat",
> > +		"exfat",
> I was looking what's wrong with vfat and exfat.
> statvfs.f_namemax returns 1530, which is obviously too long, thus valid_fname
> obviously returns ENAMETOOLONG (36). Tested on 6.1.0-rc6-1.g4c01546-default.
> I wonder why, isn't that a bug?

To reply myself, both glibc and musl defines:
statvfs->f_namemax = statfs->f_namelen;

TL;DR: 6 * 255 = 1530 due names being in UTF-8:

Therefore looking into kernel sources for statfs->f_namelen:

include/linux/nls.h
#define NLS_MAX_CHARSET_SIZE 6 /* for UTF-8 */

=== exfat ===
exfat/exfat_raw.h
#define EXFAT_MAX_FILE_LEN 255

exfat/super.c
static int exfat_statfs(struct dentry *dentry, struct kstatfs *buf)
{
	...
    /* Unicode utf16 255 characters */
    buf->f_namelen = EXFAT_MAX_FILE_LEN * NLS_MAX_CHARSET_SIZE;

=== vfat ===
include/uapi/linux/msdos_fs.h
#define FAT_LFN_LEN 255     /* maximum long name length */

fat/inode.c
static int fat_statfs(struct dentry *dentry, struct kstatfs *buf)
{
	...
    buf->f_namelen =
        (sbi->options.isvfat ? FAT_LFN_LEN : 12) * NLS_MAX_CHARSET_SIZE;

=> i.e. for vfat without long filename support it'd be 72.

How about
1) don't skip exfat and vfat but just skip creating file with valid name? or

2) Add #define NLS_MAX_CHARSET_SIZE 6 and for vfat and exfat calculate
length as: buf.f_namemax / NLS_MAX_CHARSET_SIZE - 1 ?

Kind regards,
Petr
Li Wang Dec. 1, 2022, 5:16 a.m. UTC | #3
On Wed, Nov 30, 2022 at 5:50 PM Petr Vorel <pvorel@suse.cz> wrote:

> Hi all,
>
> ...
> > > +static struct tst_test test = {
> > > +   .test_all = run,
> > > +   .setup = setup,
> > > +   .needs_root = 1,
> > > +   .mount_device = 1,
> > > +   .mntpoint = MNT_POINT,
> > > +   .all_filesystems = 1,
> > > +   .skip_filesystems = (const char *const[]) {
> > > +           "vfat",
> > > +           "exfat",
> > I was looking what's wrong with vfat and exfat.
> > statvfs.f_namemax returns 1530, which is obviously too long, thus
> valid_fname
> > obviously returns ENAMETOOLONG (36). Tested on
> 6.1.0-rc6-1.g4c01546-default.
> > I wonder why, isn't that a bug?
>
> To reply myself, both glibc and musl defines:
> statvfs->f_namemax = statfs->f_namelen;
>
> TL;DR: 6 * 255 = 1530 due names being in UTF-8:
>
> Therefore looking into kernel sources for statfs->f_namelen:
>
> include/linux/nls.h
> #define NLS_MAX_CHARSET_SIZE 6 /* for UTF-8 */
>
> === exfat ===
> exfat/exfat_raw.h
> #define EXFAT_MAX_FILE_LEN 255
>
> exfat/super.c
> static int exfat_statfs(struct dentry *dentry, struct kstatfs *buf)
> {
>         ...
>     /* Unicode utf16 255 characters */
>     buf->f_namelen = EXFAT_MAX_FILE_LEN * NLS_MAX_CHARSET_SIZE;
>
> === vfat ===
> include/uapi/linux/msdos_fs.h
> #define FAT_LFN_LEN 255     /* maximum long name length */
>
> fat/inode.c
> static int fat_statfs(struct dentry *dentry, struct kstatfs *buf)
> {
>         ...
>     buf->f_namelen =
>         (sbi->options.isvfat ? FAT_LFN_LEN : 12) * NLS_MAX_CHARSET_SIZE;
>
> => i.e. for vfat without long filename support it'd be 72.
>
> How about
> 1) don't skip exfat and vfat but just skip creating file with valid name?
> or
>

Sure, I think this method is better.


>
> 2) Add #define NLS_MAX_CHARSET_SIZE 6 and for vfat and exfat calculate
> length as: buf.f_namemax / NLS_MAX_CHARSET_SIZE - 1 ?
>
> Kind regards,
> Petr
>
> --
> Mailing list info: https://lists.linux.it/listinfo/ltp
>
>
Avinesh Kumar Dec. 1, 2022, 8:51 a.m. UTC | #4
Hi Petr,

On Wednesday, November 30, 2022 3:20:37 PM IST Petr Vorel wrote:
> Hi all,
> 
> ...
> > > +static struct tst_test test = {
> > > +	.test_all = run,
> > > +	.setup = setup,
> > > +	.needs_root = 1,
> > > +	.mount_device = 1,
> > > +	.mntpoint = MNT_POINT,
> > > +	.all_filesystems = 1,
> > > +	.skip_filesystems = (const char *const[]) {
> > > +		"vfat",
> > > +		"exfat",
> > I was looking what's wrong with vfat and exfat.
> > statvfs.f_namemax returns 1530, which is obviously too long, thus valid_fname
> > obviously returns ENAMETOOLONG (36). Tested on 6.1.0-rc6-1.g4c01546-default.
> > I wonder why, isn't that a bug?
> 
> To reply myself, both glibc and musl defines:
> statvfs->f_namemax = statfs->f_namelen;
> 
> TL;DR: 6 * 255 = 1530 due names being in UTF-8:
> 
> Therefore looking into kernel sources for statfs->f_namelen:
> 
> include/linux/nls.h
> #define NLS_MAX_CHARSET_SIZE 6 /* for UTF-8 */
> 
> === exfat ===
> exfat/exfat_raw.h
> #define EXFAT_MAX_FILE_LEN 255
> 
> exfat/super.c
> static int exfat_statfs(struct dentry *dentry, struct kstatfs *buf)
> {
> 	...
>     /* Unicode utf16 255 characters */
>     buf->f_namelen = EXFAT_MAX_FILE_LEN * NLS_MAX_CHARSET_SIZE;
> 
> === vfat ===
> include/uapi/linux/msdos_fs.h
> #define FAT_LFN_LEN 255     /* maximum long name length */
> 
> fat/inode.c
> static int fat_statfs(struct dentry *dentry, struct kstatfs *buf)
> {
> 	...
>     buf->f_namelen =
>         (sbi->options.isvfat ? FAT_LFN_LEN : 12) * NLS_MAX_CHARSET_SIZE;
> 
> => i.e. for vfat without long filename support it'd be 72.
> 
> How about
> 1) don't skip exfat and vfat but just skip creating file with valid name? or
> 
> 2) Add #define NLS_MAX_CHARSET_SIZE 6 and for vfat and exfat calculate
> length as: buf.f_namemax / NLS_MAX_CHARSET_SIZE - 1 ?
> 
> Kind regards,
> Petr
> 

Thank you for the review and research on vfat, exfat scenarios.
I have adopted the option 1 for now and sent a v3 of this patch.


Regards,
Avinesh
Li Wang Dec. 1, 2022, 9:17 a.m. UTC | #5
Avinesh Kumar <akumar@suse.de> wrote:

> How about
> > 1) don't skip exfat and vfat but just skip creating file with valid
> name? or
> >
> > 2) Add #define NLS_MAX_CHARSET_SIZE 6 and for vfat and exfat calculate
> > length as: buf.f_namemax / NLS_MAX_CHARSET_SIZE - 1 ?
>


> Thank you for the review and research on vfat, exfat scenarios.
> I have adopted the option 1 for now and sent a v3 of this patch.
>

I thought option_1 meant to skip creating a valide-file when
detecting on "vfat,exfat" FS, but not skip for others.

Or probably I misunderstood Petr's words.

Anyway, don't hurry to send V3 until we get an agreement :).

--- a/testcases/kernel/syscalls/statvfs/statvfs01.c
+++ b/testcases/kernel/syscalls/statvfs/statvfs01.c
@@ -30,7 +30,10 @@ static void run(void)
        memset(valid_fname, 'a', buf.f_namemax - 1);
        memset(invalid_fname, 'b', buf.f_namemax + 1);

-       TST_EXP_FD(creat(valid_fname, 0444));
+       long fs_type = tst_fs_type(TEST_PATH);
+       if  (fs_type != TST_VFAT_MAGIC && fs_type != TST_EXFAT_MAGIC)
+               TST_EXP_FD(creat(valid_fname, 0444));
+
        TST_EXP_FAIL(creat(invalid_fname, 0444), ENAMETOOLONG);
 }

@@ -46,9 +49,4 @@ static struct tst_test test = {
        .mount_device = 1,
        .mntpoint = MNT_POINT,
        .all_filesystems = 1,
-       .skip_filesystems = (const char *const[]) {
-               "vfat",
-               "exfat",
-               NULL
-       }
 };
Richard Palethorpe Dec. 1, 2022, 9:34 a.m. UTC | #6
Hello,

Li Wang <liwang@redhat.com> writes:

> On Wed, Nov 30, 2022 at 5:50 PM Petr Vorel <pvorel@suse.cz> wrote:
>
>> Hi all,
>>
>> ...
>> > > +static struct tst_test test = {
>> > > +   .test_all = run,
>> > > +   .setup = setup,
>> > > +   .needs_root = 1,
>> > > +   .mount_device = 1,
>> > > +   .mntpoint = MNT_POINT,
>> > > +   .all_filesystems = 1,
>> > > +   .skip_filesystems = (const char *const[]) {
>> > > +           "vfat",
>> > > +           "exfat",
>> > I was looking what's wrong with vfat and exfat.
>> > statvfs.f_namemax returns 1530, which is obviously too long, thus
>> valid_fname
>> > obviously returns ENAMETOOLONG (36). Tested on
>> 6.1.0-rc6-1.g4c01546-default.
>> > I wonder why, isn't that a bug?

This is the kind of issue which made me think it should be a separate
patch. Because maybe it is a bug.

>>
>> To reply myself, both glibc and musl defines:
>> statvfs->f_namemax = statfs->f_namelen;
>>
>> TL;DR: 6 * 255 = 1530 due names being in UTF-8:
>>
>> Therefore looking into kernel sources for statfs->f_namelen:
>>
>> include/linux/nls.h
>> #define NLS_MAX_CHARSET_SIZE 6 /* for UTF-8 */
>>
>> === exfat ===
>> exfat/exfat_raw.h
>> #define EXFAT_MAX_FILE_LEN 255
>>
>> exfat/super.c
>> static int exfat_statfs(struct dentry *dentry, struct kstatfs *buf)
>> {
>>         ...
>>     /* Unicode utf16 255 characters */
>>     buf->f_namelen = EXFAT_MAX_FILE_LEN * NLS_MAX_CHARSET_SIZE;
>>
>> === vfat ===
>> include/uapi/linux/msdos_fs.h
>> #define FAT_LFN_LEN 255     /* maximum long name length */
>>
>> fat/inode.c
>> static int fat_statfs(struct dentry *dentry, struct kstatfs *buf)
>> {
>>         ...
>>     buf->f_namelen =
>>         (sbi->options.isvfat ? FAT_LFN_LEN : 12) * NLS_MAX_CHARSET_SIZE;
>>
>> => i.e. for vfat without long filename support it'd be 72.
>>
>> How about
>> 1) don't skip exfat and vfat but just skip creating file with valid name?
>> or
>>
>
> Sure, I think this method is better.

Is it supposed to return the length in bytes or unicode 'characters'? If
it's the later then things get really complicated so I guess it's bytes.

However BTRFS also supports unicode (and bigger file names in theory)
and just reports 255. If you look at the BTRFS code comments, it says
that they limited it to 255 because other things might break.

So will creating a file with > 255 chars ever work, even if we use
UTF-16 symbols?

In the meantime could we just read the data into a guarded buffer and
check it's not all zero's or all one's (for e.g.)?

>
>
>>
>> 2) Add #define NLS_MAX_CHARSET_SIZE 6 and for vfat and exfat calculate
>> length as: buf.f_namemax / NLS_MAX_CHARSET_SIZE - 1 ?
>>
>> Kind regards,
>> Petr
>>
>> --
>> Mailing list info: https://lists.linux.it/listinfo/ltp
>>
>>
Petr Vorel Dec. 1, 2022, 10:45 a.m. UTC | #7
Hi all,

> Avinesh Kumar <akumar@suse.de> wrote:

> > How about
> > > 1) don't skip exfat and vfat but just skip creating file with valid
> > name? or

> > > 2) Add #define NLS_MAX_CHARSET_SIZE 6 and for vfat and exfat calculate
> > > length as: buf.f_namemax / NLS_MAX_CHARSET_SIZE - 1 ?



> > Thank you for the review and research on vfat, exfat scenarios.
> > I have adopted the option 1 for now and sent a v3 of this patch.


> I thought option_1 meant to skip creating a valide-file when
> detecting on "vfat,exfat" FS, but not skip for others.

> Or probably I misunderstood Petr's words.
No, you understood me well. I wanted this to be in v3,
but it's not there :).

Kind regards,
Petr

> Anyway, don't hurry to send V3 until we get an agreement :).

> --- a/testcases/kernel/syscalls/statvfs/statvfs01.c
> +++ b/testcases/kernel/syscalls/statvfs/statvfs01.c
> @@ -30,7 +30,10 @@ static void run(void)
>         memset(valid_fname, 'a', buf.f_namemax - 1);
>         memset(invalid_fname, 'b', buf.f_namemax + 1);

> -       TST_EXP_FD(creat(valid_fname, 0444));
> +       long fs_type = tst_fs_type(TEST_PATH);
> +       if  (fs_type != TST_VFAT_MAGIC && fs_type != TST_EXFAT_MAGIC)
> +               TST_EXP_FD(creat(valid_fname, 0444));
> +
>         TST_EXP_FAIL(creat(invalid_fname, 0444), ENAMETOOLONG);
>  }

> @@ -46,9 +49,4 @@ static struct tst_test test = {
>         .mount_device = 1,
>         .mntpoint = MNT_POINT,
>         .all_filesystems = 1,
> -       .skip_filesystems = (const char *const[]) {
> -               "vfat",
> -               "exfat",
> -               NULL
> -       }
>  };
Avinesh Kumar Dec. 1, 2022, 11:04 a.m. UTC | #8
On Thursday, December 1, 2022 4:15:46 PM IST Petr Vorel wrote:
> Hi all,
> 
> > Avinesh Kumar <akumar@suse.de> wrote:
> 
> > > How about
> > > > 1) don't skip exfat and vfat but just skip creating file with valid
> > > name? or
> 
> > > > 2) Add #define NLS_MAX_CHARSET_SIZE 6 and for vfat and exfat calculate
> > > > length as: buf.f_namemax / NLS_MAX_CHARSET_SIZE - 1 ?
> 
> 
> 
> > > Thank you for the review and research on vfat, exfat scenarios.
> > > I have adopted the option 1 for now and sent a v3 of this patch.
> 
> 
> > I thought option_1 meant to skip creating a valide-file when
> > detecting on "vfat,exfat" FS, but not skip for others.
> 
> > Or probably I misunderstood Petr's words.
> No, you understood me well. I wanted this to be in v3,
> but it's not there :).
> 
> Kind regards,
> Petr
> 
> > Anyway, don't hurry to send V3 until we get an agreement :).

Hi Petr, Li,

Sorry, I misunderstood and had removed the valid filename creation altogether,
I am correcting the patch in v4, as suggested by Li.

Thanks,
Avinesh

> 
> > --- a/testcases/kernel/syscalls/statvfs/statvfs01.c
> > +++ b/testcases/kernel/syscalls/statvfs/statvfs01.c
> > @@ -30,7 +30,10 @@ static void run(void)
> >         memset(valid_fname, 'a', buf.f_namemax - 1);
> >         memset(invalid_fname, 'b', buf.f_namemax + 1);
> 
> > -       TST_EXP_FD(creat(valid_fname, 0444));
> > +       long fs_type = tst_fs_type(TEST_PATH);
> > +       if  (fs_type != TST_VFAT_MAGIC && fs_type != TST_EXFAT_MAGIC)
> > +               TST_EXP_FD(creat(valid_fname, 0444));
> > +
> >         TST_EXP_FAIL(creat(invalid_fname, 0444), ENAMETOOLONG);
> >  }
> 
> > @@ -46,9 +49,4 @@ static struct tst_test test = {
> >         .mount_device = 1,
> >         .mntpoint = MNT_POINT,
> >         .all_filesystems = 1,
> > -       .skip_filesystems = (const char *const[]) {
> > -               "vfat",
> > -               "exfat",
> > -               NULL
> > -       }
> >  };
>
Petr Vorel Dec. 2, 2022, 9:20 a.m. UTC | #9
Hi all,

...
> >> To reply myself, both glibc and musl defines:
> >> statvfs->f_namemax = statfs->f_namelen;

> >> TL;DR: 6 * 255 = 1530 due names being in UTF-8:

> >> Therefore looking into kernel sources for statfs->f_namelen:

> >> include/linux/nls.h
> >> #define NLS_MAX_CHARSET_SIZE 6 /* for UTF-8 */

> >> === exfat ===
> >> exfat/exfat_raw.h
> >> #define EXFAT_MAX_FILE_LEN 255

> >> exfat/super.c
> >> static int exfat_statfs(struct dentry *dentry, struct kstatfs *buf)
> >> {
> >>         ...
> >>     /* Unicode utf16 255 characters */
> >>     buf->f_namelen = EXFAT_MAX_FILE_LEN * NLS_MAX_CHARSET_SIZE;

> >> === vfat ===
> >> include/uapi/linux/msdos_fs.h
> >> #define FAT_LFN_LEN 255     /* maximum long name length */

> >> fat/inode.c
> >> static int fat_statfs(struct dentry *dentry, struct kstatfs *buf)
> >> {
> >>         ...
> >>     buf->f_namelen =
> >>         (sbi->options.isvfat ? FAT_LFN_LEN : 12) * NLS_MAX_CHARSET_SIZE;

> >> => i.e. for vfat without long filename support it'd be 72.

> >> How about
> >> 1) don't skip exfat and vfat but just skip creating file with valid name?
> >> or


> > Sure, I think this method is better.

> Is it supposed to return the length in bytes or unicode 'characters'? If
> it's the later then things get really complicated so I guess it's bytes.
Yes.

TL;DR: I'd test vfat and exfat for valid filename with (f_namelen / 6) + 1.

> However BTRFS also supports unicode (and bigger file names in theory)
> and just reports 255. If you look at the BTRFS code comments, it says
> that they limited it to 255 because other things might break.

> So will creating a file with > 255 chars ever work, even if we use
> UTF-16 symbols?

Wrote some testing code (see below), vfat and exfat behaves differently:

$ gcc -Wall statvfs-test-ms.c -o statvfs-test-ms && ./statvfs-test-ms /tmp/vfat/
=== filesystem: vfat ===

file: test_ϴ_12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678
strlen: 256, mblen: 255
buf.f_namelen: 1530

file: test_ϴ_12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678_
strlen: 257, mblen: 256
creat() failed: File name too long

file: ϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴ
strlen: 510, mblen: 255
buf.f_namelen: 1530

Also NTFS over fuse behaves the same (allows 256 length), but (probably due
fuse) f_namelen is only 255:

=== filesystem: fuse ===

file: test_ϴ_12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678
strlen: 256, mblen: 255
buf.f_namelen: 255

file: test_ϴ_12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678_
strlen: 257, mblen: 256
creat() failed: File name too long

file: ϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴ
strlen: 510, mblen: 255
buf.f_namelen: 255


NOTE: they both allow strlen 256 as max character multibyte length is in that
case just 255 (not counting terminating null byte \0 ?).

When testing on normal linux filesystems (btrfs, ext4, xfs, tmpfs, ...) they all
allow only strlen 255 and obviously does not work with multibyte (output on shortened
filenames):

=== filesystem: btrfs ===

file: test_ϴ_1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567
strlen: 255, mblen: 254
buf.f_namelen: 255

file: test_ϴ_1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567_
strlen: 256, mblen: 255
creat() failed: File name too long

file: ϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴ
strlen: 508, mblen: 254
creat() failed: File name too long

Kind regards,
Petr

> In the meantime could we just read the data into a guarded buffer and
> check it's not all zero's or all one's (for e.g.)?




> >> 2) Add #define NLS_MAX_CHARSET_SIZE 6 and for vfat and exfat calculate
> >> length as: buf.f_namemax / NLS_MAX_CHARSET_SIZE - 1 ?

> >> Kind regards,
> >> Petr

#include <fcntl.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/statfs.h>
#include <unistd.h>

/* test requires C.utf8 locale */
#define LOCALE "C.utf8"

/* here for vfat, exfat, which allow 256, Linux filesystems (btrfs, ext4, tmpfs xfs, ...) allow only 255 */
#define MAX_FILENAME_PATH "test_ϴ_" \
"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" \
"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" \
"123456789012345678901234567890123456789012345678"

#define TOO_LONG_FILENAME MAX_FILENAME_PATH "_"

/* here for vfat, exfat, which allow 256, Linux filesystems (btrfs, ext4, tmpfs xfs, ...) allow only 255 */
#define MAX_FILENAME_PATH_UTF16 \
"ϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴ" \
"ϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴ" \
"ϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴϴ"

/* man 2 statfs or kernel-source/include/linux/magic.h */
#define TST_BTRFS_MAGIC    0x9123683E
#define TST_NFS_MAGIC      0x6969
#define TST_RAMFS_MAGIC    0x858458f6
#define TST_TMPFS_MAGIC    0x01021994
#define TST_V9FS_MAGIC     0x01021997
#define TST_XFS_MAGIC      0x58465342
#define TST_EXT2_OLD_MAGIC 0xEF51
/* ext2, ext3, ext4 have the same magic number */
#define TST_EXT234_MAGIC   0xEF53
#define TST_MINIX_MAGIC    0x137F
#define TST_MINIX_MAGIC2   0x138F
#define TST_MINIX2_MAGIC   0x2468
#define TST_MINIX2_MAGIC2  0x2478
#define TST_MINIX3_MAGIC   0x4D5A
#define TST_UDF_MAGIC      0x15013346
#define TST_SYSV2_MAGIC    0x012FF7B6
#define TST_SYSV4_MAGIC    0x012FF7B5
#define TST_UFS_MAGIC      0x00011954
#define TST_UFS2_MAGIC     0x19540119
#define TST_F2FS_MAGIC     0xF2F52010
#define TST_NILFS_MAGIC    0x3434
#define TST_EXOFS_MAGIC    0x5DF5
#define TST_OVERLAYFS_MAGIC 0x794c7630
#define TST_FUSE_MAGIC     0x65735546
#define TST_VFAT_MAGIC     0x4d44 /* AKA MSDOS */
#define TST_EXFAT_MAGIC    0x2011BAB0UL

long tst_fs_type(const char *path)
{
	struct statfs sbuf;

	if (statfs(path, &sbuf)) {
		perror("statfs");
		exit(EXIT_FAILURE);
		return 0;
	}

	return sbuf.f_type;
}

const char *tst_fs_type_name(long f_type)
{
	switch (f_type) {
	case TST_TMPFS_MAGIC:
		return "tmpfs";
	case TST_NFS_MAGIC:
		return "nfs";
	case TST_V9FS_MAGIC:
		return "9p";
	case TST_RAMFS_MAGIC:
		return "ramfs";
	case TST_BTRFS_MAGIC:
		return "btrfs";
	case TST_XFS_MAGIC:
		return "xfs";
	case TST_EXT2_OLD_MAGIC:
		return "ext2";
	case TST_EXT234_MAGIC:
		return "ext2/ext3/ext4";
	case TST_MINIX_MAGIC:
	case TST_MINIX_MAGIC2:
	case TST_MINIX2_MAGIC:
	case TST_MINIX2_MAGIC2:
	case TST_MINIX3_MAGIC:
		return "minix";
	case TST_UDF_MAGIC:
		return "udf";
	case TST_SYSV2_MAGIC:
	case TST_SYSV4_MAGIC:
		return "sysv";
	case TST_UFS_MAGIC:
	case TST_UFS2_MAGIC:
		return "ufs";
	case TST_F2FS_MAGIC:
		return "f2fs";
	case TST_NILFS_MAGIC:
		return "nilfs";
	case TST_EXOFS_MAGIC:
		return "exofs";
	case TST_OVERLAYFS_MAGIC:
		return "overlayfs";
	case TST_FUSE_MAGIC:
		return "fuse";
	case TST_VFAT_MAGIC:
		return "vfat";
	case TST_EXFAT_MAGIC:
		return "exfat";
	default:
		return "unknown";
	}
}

int creat_file_print_len(char *str)
{
	int fd;
	struct statfs buf;

	printf("\nfile: %s\nstrlen: %zu, mblen: %zu\n", str,
		   strlen(str), mbstowcs(NULL, str, 0));

	if ((fd = creat(str, 0666)) < 0) {
		perror("creat() failed");
		return 1;
	}

	close(fd);

	if (statfs(str, &buf) < 0) {
		perror("statfs() failed");
		return 1;
	}

	printf("buf.f_namelen: %zu\n", buf.f_namelen);

	return 0;
}

int main(int argc, char *argv[]) {

	int ret = 0;

	if (argc < 2) {
		fprintf(stderr, "Usage: %s DIR\n", argv[0]);
		exit(EXIT_FAILURE);
	}

	if (chdir(argv[1]) > 0) {
		perror("chdir() failed");
		exit(EXIT_FAILURE);
	}
	printf("=== filesystem: %s ===\n", tst_fs_type_name(tst_fs_type(".")));

	if (setlocale(LC_ALL, LOCALE) == NULL) {
		perror("setlocale");
		exit(EXIT_FAILURE);
	}

	ret |= creat_file_print_len(MAX_FILENAME_PATH);
	ret |= creat_file_print_len(TOO_LONG_FILENAME);
	ret |= creat_file_print_len(MAX_FILENAME_PATH_UTF16);

	return ret;
}
diff mbox series

Patch

diff --git a/testcases/kernel/syscalls/statvfs/statvfs01.c b/testcases/kernel/syscalls/statvfs/statvfs01.c
index e3b356c93..94e17ba1d 100644
--- a/testcases/kernel/syscalls/statvfs/statvfs01.c
+++ b/testcases/kernel/syscalls/statvfs/statvfs01.c
@@ -1,92 +1,54 @@ 
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Copyright (c) Wipro Technologies Ltd, 2005.  All Rights Reserved.
  *    AUTHOR: Prashant P Yendigeri <prashant.yendigeri@wipro.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
+ * Copyright (c) 2022 SUSE LLC Avinesh Kumar <avinesh.kumar@suse.com>
  */
-/*
- *    DESCRIPTION
- *      This is a Phase I test for the statvfs(2) system call.
- *      It is intended to provide a limited exposure of the system call.
- *	This call behaves similar to statfs.
+
+/*\
+ * [Description]
+ *
+ * Verify that statvfs() executes successfully for all
+ * available filesystems.
  */
 
-#include <stdio.h>
-#include <unistd.h>
-#include <errno.h>
 #include <sys/statvfs.h>
-#include <stdint.h>
-
-#include "test.h"
-
-#define TEST_PATH "/"
+#include "tst_test.h"
 
-static void setup(void);
-static void cleanup(void);
+#define MNT_POINT "mntpoint"
+#define TEST_PATH MNT_POINT"/testfile"
 
-char *TCID = "statvfs01";
-int TST_TOTAL = 1;
-
-int main(int ac, char **av)
+static void run(void)
 {
 	struct statvfs buf;
-	int lc;
-
-	tst_parse_opts(ac, av, NULL, NULL);
+	char *valid_fname, *invalid_fname;
 
-	setup();
+	TST_EXP_PASS(statvfs(TEST_PATH, &buf));
 
-	for (lc = 0; TEST_LOOPING(lc); lc++) {
+	valid_fname = SAFE_MALLOC(buf.f_namemax - 1);
+	invalid_fname = SAFE_MALLOC(buf.f_namemax + 1);
+	memset(valid_fname, 'a', buf.f_namemax - 1);
+	memset(invalid_fname, 'b', buf.f_namemax + 1);
 
-		tst_count = 0;
-
-		TEST(statvfs(TEST_PATH, &buf));
-
-		if (TEST_RETURN == -1) {
-			tst_resm(TFAIL | TTERRNO, "statvfs(%s, ...) failed",
-				 TEST_PATH);
-		} else {
-			tst_resm(TPASS, "statvfs(%s, ...) passed", TEST_PATH);
-		}
-
-	}
-
-	tst_resm(TINFO, "This call is similar to statfs");
-	tst_resm(TINFO, "Extracting info about the '%s' file system",
-		 TEST_PATH);
-	tst_resm(TINFO, "file system block size = %lu bytes", buf.f_bsize);
-	tst_resm(TINFO, "file system fragment size = %lu bytes", buf.f_frsize);
-	tst_resm(TINFO, "file system free blocks = %ju",
-		 (uintmax_t) buf.f_bfree);
-	tst_resm(TINFO, "file system total inodes = %ju",
-		 (uintmax_t) buf.f_files);
-	tst_resm(TINFO, "file system free inodes = %ju",
-		 (uintmax_t) buf.f_ffree);
-	tst_resm(TINFO, "file system id = %lu", buf.f_fsid);
-	tst_resm(TINFO, "file system max filename length = %lu", buf.f_namemax);
-
-	cleanup();
-	tst_exit();
+	TST_EXP_FD(creat(valid_fname, 0444));
+	TST_EXP_FAIL(creat(invalid_fname, 0444), ENAMETOOLONG);
 }
 
 static void setup(void)
 {
-	tst_sig(NOFORK, DEF_HANDLER, cleanup);
-
-	TEST_PAUSE;
+	SAFE_TOUCH(TEST_PATH, 0666, NULL);
 }
 
-static void cleanup(void)
-{
-}
+static struct tst_test test = {
+	.test_all = run,
+	.setup = setup,
+	.needs_root = 1,
+	.mount_device = 1,
+	.mntpoint = MNT_POINT,
+	.all_filesystems = 1,
+	.skip_filesystems = (const char *const[]) {
+		"vfat",
+		"exfat",
+		NULL
+	}
+};