stat.2: fixed inode printing in example program
PATCH 1/1 stat.2: fixed inode printing in example program
inode numbers are expected to be positive. Casting them to a signed type may result in printing negative values. E.g. running example program on the following file:
$ ls -li test.txt 9280843260537405888 -r--r--r-- 1 kbukin hardware 300 Jul 21 06:36 test.txt
resutls in the following output:
$ ./example test.txt ID of containing device: [0,480] File type: regular file I-node number: -9165900813172145728 Mode: 100444 (octal) Link count: 1 Ownership: UID=2743 GID=30 Preferred I/O block size: 32768 bytes File size: 300 bytes Blocks allocated: 8 Last status change: Tue Jul 21 06:36:50 2020 Last file access: Sat Sep 12 14:13:38 2020 Last file modification: Tue Jul 21 06:36:50 2020
Such erroneous reporting happens for inode values greater than maximum value which can be stored in signed long. Casting does not seem to be necessary here. Printing inode as unsigned long fixes the issue.
--- man2/stat.2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
man2/stat.2 +1 -1
@@ -681,7 +681,7 @@ main(int argc, char *argv[]) default: printf("unknown?\en"); break; } - printf("I\-node number: %ld\en", (long) sb.st_ino); + printf("I\-node number: %lu\en", sb.st_ino); printf("Mode: %lo (octal)\en", (unsigned long) sb.st_mode);
Signature · 1 line
2.17.0
Quoted 35 lines · Konstantin Bukin
inode numbers are expected to be positive. Casting them to a signed type may result in printing negative values. E.g. running example program on the following file:
$ ls -li test.txt 9280843260537405888 -r--r--r-- 1 kbukin hardware 300 Jul 21 06:36 test.txtresutls in the following output:
$ ./example test.txt ID of containing device: [0,480] File type: regular file I-node number: -9165900813172145728 Mode: 100444 (octal) Link count: 1 Ownership: UID=2743 GID=30 Preferred I/O block size: 32768 bytes File size: 300 bytes Blocks allocated: 8 Last status change: Tue Jul 21 06:36:50 2020 Last file access: Sat Sep 12 14:13:38 2020 Last file modification: Tue Jul 21 06:36:50 2020Such erroneous reporting happens for inode values greater than maximum value which can be stored in signed long. Casting does not seem to be necessary here. Printing inode as unsigned long fixes the issue.
--- man2/stat.2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)man2/stat.2 +0
-0
man2/stat.2 main(int argc, char *argv[]) · line 684
Quoted 5 lines
man2/stat.2 +1
-1@@ -681,7 +681,7 @@ main(int argc, char *argv[]) default: printf("unknown?\en"); break; } - printf("I\-node number: %ld\en", (long) sb.st_ino); + printf("I\-node number: %lu\en", sb.st_ino);
By the way, the type of st_ino is ino_t which might be larger than long, so both the old and the new variants are not correct.
Signature · 1 line
ldv
On x86 the size of ino_t does not appear to be larger than long. It is 4 in 32-bit programs and 8 in 64-bit programs. On what platforms the size of ino_t is larger than long?
Here is the beginning of memory taken by struct stat sb in 32-bit example program run on my file:
(gdb) x/8xw &sb
0xffffd0d8: 0x00400080 0x00000000 0x00ca0000 0x006901c0 0xffffd0e8: 0x00008124 0x00000001 0x00000ab7 0x0000001e
The first eight bytes is st_dev. 0x006901c0 are the lower 4 bytes of inode. I am not sure what 0x00ca0000 is. Is that just padding?
For comparison, here is the beginning of memory taken by struct stat sb in 64-bit example programs run on the same file:
(gdb) x/8xw &sb
0x7fffffffdf30: 0x00400080 0x00000000 0x006901c0 0x80cc2dc6 0x7fffffffdf40: 0x00000001 0x00000000 0x00008124 0x00000ab7
0x006901c0 and 0x80cc2dc6 are lower and upper 4 bytes of the inode. 0x80cc2dc6006901c0 is what “ls -li” reports, but in decimal.
Quoted 49 lines · Dmitry V. Levin
Quoted 35 lines · Konstantin Bukin
inode numbers are expected to be positive. Casting them to a signed type may result in printing negative values. E.g. running example program on the following file:
$ ls -li test.txt 9280843260537405888 -r--r--r-- 1 kbukin hardware 300 Jul 21 06:36 test.txtresutls in the following output:
$ ./example test.txt ID of containing device: [0,480] File type: regular file I-node number: -9165900813172145728 Mode: 100444 (octal) Link count: 1 Ownership: UID=2743 GID=30 Preferred I/O block size: 32768 bytes File size: 300 bytes Blocks allocated: 8 Last status change: Tue Jul 21 06:36:50 2020 Last file access: Sat Sep 12 14:13:38 2020 Last file modification: Tue Jul 21 06:36:50 2020Such erroneous reporting happens for inode values greater than maximum value which can be stored in signed long. Casting does not seem to be necessary here. Printing inode as unsigned long fixes the issue.
--- man2/stat.2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)man2/stat.2 +0
-0man2/stat.2 main(int argc, char *argv[]) · line 684
Quoted 5 lines
man2/stat.2 +1
-1@@ -681,7 +681,7 @@ main(int argc, char *argv[]) default: printf("unknown?\en"); break; } - printf("I\-node number: %ld\en", (long) sb.st_ino); + printf("I\-node number: %lu\en", sb.st_ino);By the way, the type of
st_inoisino_twhich might be larger than long, so both the old and the new variants are not correct.--
ldv
Quoted 1 line · Konstantin Bukin
On x86 the size of
ino_tdoes not appear to be larger than long.
It depends. For example, with glibc on all architectures ino_t is 64-bit when the code is compiled using -D_FILE_OFFSET_BITS=64.
Signature · 1 line
ldv
Hi,
Please, see the patch I just sent:
https://lore.kernel.org/linux-man/[email protected]/T/#u
Do you agree it solves this problem?
Cheers,
Alex
Quoted 1 line
Do you agree it solves this problem?
No, that does not solve the problem. There is still casting to a signed resulting in printing negative inode.
Using %llu might be better since that would not require including an extra header.
Mind I'll send a new patch?
Quoted 12 lines · Alejandro Colomar
Hi,
Please, see the patch I just sent:
https://lore.kernel.org/linux-man/[email protected]/T/#u
Do you agree it solves this problem?
Cheers,
Alex
Hi Konstantin,
Quoted 4 lines · Konstantin Bukin
Quoted 1 line
Do you agree it solves this problem?
No, that does not solve the problem. There is still casting to a signed resulting in printing negative inode.
True. The definition of ino_t is unsigned, so the example was wrong from the beginning.
Quoted 3 lines
Using %llu might be better since that would not require including an extra header.
We just had that discussion in this thread:
https://lore.kernel.org/linux-man/[email protected]/T/#m971e4dcfae5f25e0f26c906679aa7176b6786bdf
We decided to go for [u]intmax_t. But the patch has not yet been applied, so you arrive just in time to give reasons against it.
Quoted 2 lines
Mind I'll send a new patch?
Sure.
Cheers,
Alex
Quoted 2 lines
Quoted 1 line
Mind I'll send a new patch?
Sure.
The new patch uses "%lld" instead of "%ld".
Thank you,
Konsstantin.
Quoted 30 lines · Alejandro Colomar
Hi Konstantin,
Quoted 4 lines · Konstantin Bukin
Quoted 1 line
Do you agree it solves this problem?
No, that does not solve the problem. There is still casting to a signed resulting in printing negative inode.
True. The definition of
ino_tis unsigned, so the example was wrong from the beginning.Quoted 3 lines
Using %llu might be better since that would not require including an extra header.
We just had that discussion in this thread:
https://lore.kernel.org/linux-man/[email protected]/T/#m971e4dcfae5f25e0f26c906679aa7176b6786bdf
We decided to go for [u]intmax_t. But the patch has not yet been applied, so you arrive just in time to give reasons against it.
Quoted 2 lines
Mind I'll send a new patch?
Sure.
Cheers,
Alex
Quoted 7 lines · Konstantin Bukin
Quoted 2 lines
Quoted 1 line
Mind I'll send a new patch?
Sure.
The new patch uses "%lld" instead of "%ld".
Thank you,
Konsstantin.
BTW, please reply to the thread when submitting a new version of a patch, so the thread can be easily followed.
If you use git send-email, this might help:
https://burzalodowa.wordpress.com/2013/10/05/how-to-send-patches-with-git-send-email/
Thanks,
Alex
PATCH 1/1 stat.2: fixed inode printing in example program
inode numbers are expected to be positive. Casting them to a signed type may result in printing negative values. E.g. running example program on the following file:
$ ls -li test.txt 9280843260537405888 -r--r--r-- 1 kbukin hardware 300 Jul 21 06:36 test.txt
resutls in the following output:
$ ./example test.txt ID of containing device: [0,480] File type: regular file I-node number: -9165900813172145728 Mode: 100444 (octal) Link count: 1 Ownership: UID=2743 GID=30 Preferred I/O block size: 32768 bytes File size: 300 bytes Blocks allocated: 8 Last status change: Tue Jul 21 06:36:50 2020 Last file access: Sat Sep 12 14:13:38 2020 Last file modification: Tue Jul 21 06:36:50 2020
Such erroneous reporting happens for inode values greater than maximum value which can be stored in signed long. Casting does not seem to be necessary here. Printing inode as unsigned long long fixes the issue.
--- man2/stat.2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
man2/stat.2 +1 -1
@@ -681,7 +681,7 @@ main(int argc, char *argv[]) default: printf("unknown?\en"); break; } - printf("I\-node number: %ld\en", (long) sb.st_ino); + printf("I\-node number: %llu\en", (unsigned long long) sb.st_ino); printf("Mode: %lo (octal)\en", (unsigned long) sb.st_mode);
Signature · 1 line
2.17.0
I mentioned cast in the commit message. Sending a new patch with a revised commit message.
Quoted 47 lines · Konstantin Bukin
inode numbers are expected to be positive. Casting them to a signed type may result in printing negative values. E.g. running example program on the following file:
$ ls -li test.txt 9280843260537405888 -r--r--r-- 1 kbukin hardware 300 Jul 21 06:36 test.txtresutls in the following output:
$ ./example test.txt ID of containing device: [0,480] File type: regular file I-node number: -9165900813172145728 Mode: 100444 (octal) Link count: 1 Ownership: UID=2743 GID=30 Preferred I/O block size: 32768 bytes File size: 300 bytes Blocks allocated: 8 Last status change: Tue Jul 21 06:36:50 2020 Last file access: Sat Sep 12 14:13:38 2020 Last file modification: Tue Jul 21 06:36:50 2020Such erroneous reporting happens for inode values greater than maximum value which can be stored in signed long. Casting does not seem to be necessary here. Printing inode as unsigned long long fixes the issue.
--- man2/stat.2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)man2/stat.2 +1
-2@@ -681,7 +681,7 @@ main(int argc, char *argv[]) default: printf("unknown?\en"); break; } - printf("I\-node number: %ld\en", (long) sb.st_ino); + printf("I\-node number: %llu\en", (unsigned long long) sb.st_ino); printf("Mode: %lo (octal)\en", (unsigned long) sb.st_mode); --2.17.0
PATCH 1/1 stat.2: fixed inode printing in example program
inode numbers are expected to be positive. Casting them to a signed type may result in printing negative values. E.g. running example program on the following file:
$ ls -li test.txt 9280843260537405888 -r--r--r-- 1 kbukin hardware 300 Jul 21 06:36 test.txt
resutls in the following output:
$ ./example test.txt ID of containing device: [0,480] File type: regular file I-node number: -9165900813172145728 Mode: 100444 (octal) Link count: 1 Ownership: UID=2743 GID=30 Preferred I/O block size: 32768 bytes File size: 300 bytes Blocks allocated: 8 Last status change: Tue Jul 21 06:36:50 2020 Last file access: Sat Sep 12 14:13:38 2020 Last file modification: Tue Jul 21 06:36:50 2020
Such erroneous reporting happens for inode values greater than maximum value which can be stored in signed long. Printing inode as unsigned long long fixes the issue.
--- man2/stat.2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
man2/stat.2 +1 -1
@@ -681,7 +681,7 @@ main(int argc, char *argv[]) default: printf("unknown?\en"); break; } - printf("I\-node number: %ld\en", (long) sb.st_ino); + printf("I\-node number: %llu\en", (unsigned long long) sb.st_ino); printf("Mode: %lo (octal)\en", (unsigned long) sb.st_mode);
Signature · 1 line
2.17.0
Hello Konstantin,
Quoted 35 lines · Konstantin Bukin
inode numbers are expected to be positive. Casting them to a signed type may result in printing negative values. E.g. running example program on the following file:
$ ls -li test.txt 9280843260537405888 -r--r--r-- 1 kbukin hardware 300 Jul 21 06:36 test.txtresutls in the following output:
$ ./example test.txt ID of containing device: [0,480] File type: regular file I-node number: -9165900813172145728 Mode: 100444 (octal) Link count: 1 Ownership: UID=2743 GID=30 Preferred I/O block size: 32768 bytes File size: 300 bytes Blocks allocated: 8 Last status change: Tue Jul 21 06:36:50 2020 Last file access: Sat Sep 12 14:13:38 2020 Last file modification: Tue Jul 21 06:36:50 2020Such erroneous reporting happens for inode values greater than maximum value which can be stored in signed long. Printing inode as unsigned long long fixes the issue.
--- man2/stat.2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)man2/stat.2 +0
-0
man2/stat.2 main(int argc, char *argv[]) · line 687
Quoted 8 lines
man2/stat.2 +1
-1@@ -681,7 +681,7 @@ main(int argc, char *argv[]) default: printf("unknown?\en"); break; } - printf("I\-node number: %ld\en", (long) sb.st_ino); + printf("I\-node number: %llu\en", (unsigned long long) sb.st_ino); printf("Mode: %lo (octal)\en", (unsigned long) sb.st_mode);
Thanks for your patches and problem report. But, it seems best to go with Alejandro's suggestion to use uintmax_t + %ju. See the patch that Alejandro has sent.
Thanks,
Michael
Signature · 3 lines
Michael Kerrisk Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/ Linux/UNIX System Programming Training: http://man7.org/training/
I didn’t know _FILE_OFFSET_BITS also affects size of ino_t. Do you see any issues printing ino_t with %lld ?
Quoted 10 lines · Dmitry V. Levin
Quoted 1 line · Konstantin Bukin
On x86 the size of
ino_tdoes not appear to be larger than long.It depends. For example, with glibc on all architectures
ino_tis 64-bit when the code is compiled using -D_FILE_OFFSET_BITS=64.--
ldv