Sender: rich AT phekda DOT freeserve DOT co DOT uk Message-ID: <3BF82D64.84C50E28@phekda.freeserve.co.uk> Date: Sun, 18 Nov 2001 21:51:32 +0000 From: Richard Dawe X-Mailer: Mozilla 4.77 [en] (X11; U; Linux 2.2.19 i586) X-Accept-Language: de,fr MIME-Version: 1.0 To: djgpp-workers AT delorie DOT com Subject: Re: RESEND: Patch to computer st_blksize in struct stat References: Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Reply-To: djgpp-workers AT delorie DOT com Hello. Eli Zaretskii wrote: [snip] > 2) I'm a bit worried by the possible slow-down, due to the call to > statfs. Could you compare the old and the new versions, at least > on hard disks, floppies, and CDs? Using gprof on src/libc/sys/stat/*stat.c I managed to get the following information. Here is the time spent in __dpmi_int() for running the fstat.c test on a file with the new block size support in *stat(): HD, CD-ROM drives: 0s (probably too short to measure) Floppy drive: 0.11s Network drive: 0.06s In all cases the current code in CVS takes 0s on my machine (Athlon 850MHz) for the same files. I've added code to return 512 bytes as the block size for A:, B:. I've also defaulted the block size to 32K for remote drives. If you don't think 0.06s is much overhead, then I can remove the hard-coded size for remote drives. Anyhow, please find below a new version of the patch. Thanks to Eli & Charles for their helpful comments. Also I just noticed that _STAT_* are defined in include/sys/stat.h, but src/libc/posix/sys/stat/xstat.c does not use the definitions from sys/stat.h. Shouldn't xstat.c include sys/stat.h, to get common definitions for _STAT_*? BTW there seems to be some cruft in include/dos.h - should this be removed? /* int _get_default_drive(void); void _fixpath(const char *, char *); */ Thanks, bye, Rich =] -- Richard Dawe http://www.phekda.freeserve.co.uk/richdawe/ Index: include/sys/types.h =================================================================== RCS file: /cvs/djgpp/djgpp/include/sys/types.h,v retrieving revision 1.6 diff -p -u -3 -r1.6 types.h --- include/sys/types.h 2000/12/05 14:05:53 1.6 +++ include/sys/types.h 2001/11/18 21:46:36 @@ -13,7 +13,9 @@ extern "C" { #ifndef __STRICT_ANSI__ #include - + +typedef int blkcnt_t; +typedef int blksize_t; typedef int dev_t; typedef int ino_t; typedef int mode_t; Index: include/sys/stat.h =================================================================== RCS file: /cvs/djgpp/djgpp/include/sys/stat.h,v retrieving revision 1.4 diff -p -u -3 -r1.4 stat.h --- include/sys/stat.h 2000/12/05 14:05:53 1.4 +++ include/sys/stat.h 2001/11/18 21:46:42 @@ -49,9 +49,9 @@ struct stat { time_t st_mtime; nlink_t st_nlink; off_t st_size; - off_t st_blksize; + blksize_t st_blksize; uid_t st_uid; - dev_t st_rdev; /* unused */ + dev_t st_rdev; }; int chmod(const char *_path, mode_t _mode); Index: include/libc/fd_props.h =================================================================== RCS file: /cvs/djgpp/djgpp/include/libc/fd_props.h,v retrieving revision 1.6 diff -p -u -3 -r1.6 fd_props.h --- include/libc/fd_props.h 2001/06/06 21:09:50 1.6 +++ include/libc/fd_props.h 2001/11/18 21:47:01 @@ -8,6 +8,8 @@ extern "C" { #ifndef __dj_ENFORCE_ANSI_FREESTANDING +#include + #ifndef __STRICT_ANSI__ #ifndef _POSIX_SOURCE @@ -63,6 +65,11 @@ static __inline__ void __clear_fd_flags( static __inline__ unsigned long __get_fd_flags(int _fd) { return __has_fd_properties(_fd) ? __fd_properties[_fd]->flags : 0; +} + +static __inline__ const char * __get_fd_name(int _fd) +{ + return __has_fd_properties(_fd) ? __fd_properties[_fd]->filename : NULL; } #endif /* !_POSIX_SOURCE */ Index: src/libc/posix/sys/stat/fstat.c =================================================================== RCS file: /cvs/djgpp/djgpp/src/libc/posix/sys/stat/fstat.c,v retrieving revision 1.7 diff -p -u -3 -r1.7 fstat.c --- src/libc/posix/sys/stat/fstat.c 2001/09/25 01:00:52 1.7 +++ src/libc/posix/sys/stat/fstat.c 2001/11/18 21:47:24 @@ -106,6 +106,8 @@ #include #include #include +#include +#include #include #include @@ -434,7 +436,21 @@ fstat_assist(int fhandle, struct stat *s stat_buf->st_gid = getgid(); stat_buf->st_nlink = 1; #ifndef NO_ST_BLKSIZE - stat_buf->st_blksize = _go32_info_block.size_of_transfer_buffer; + if (__get_fd_name(fhandle)) + { + const char *filename; + char fixed_filename[PATH_MAX + 1]; + + filename = __get_fd_name(fhandle); + _fixpath(filename, fixed_filename); + stat_buf->st_blksize = _get_cached_blksize(fixed_filename); + } + else + { + /* Fall back on transfer buffer size, if we can't determine file name + * (which gives the drive letter and then the drive's cluster size). */ + stat_buf->st_blksize = _go32_info_block.size_of_transfer_buffer; + } #endif /* If SFT entry for our handle is required and available, we will use it. */ @@ -936,6 +952,9 @@ int main(int argc, char *argv[]) _djstat_describe_lossage(stderr); } + if (!argc) + return EXIT_SUCCESS; + /* Now call fstat() for each command-line argument. */ while (++argv, --argc) { @@ -956,6 +975,8 @@ int main(int argc, char *argv[]) fprintf (stderr, "\t\t\tTimes: %lu %lu\n", (unsigned long)stat_buf.st_atime, (unsigned long)stat_buf.st_ctime); + fprintf(stderr, "\t\t\tBlock size: %d\n", + stat_buf.st_blksize); _djstat_describe_lossage(stderr); } else @@ -965,7 +986,7 @@ int main(int argc, char *argv[]) _djstat_describe_lossage(stderr); } } - return 0; + return EXIT_SUCCESS; } #endif /* TEST */ Index: src/libc/posix/sys/stat/lstat.c =================================================================== RCS file: /cvs/djgpp/djgpp/src/libc/posix/sys/stat/lstat.c,v retrieving revision 1.7 diff -p -u -3 -r1.7 lstat.c --- src/libc/posix/sys/stat/lstat.c 2001/10/17 05:08:39 1.7 +++ src/libc/posix/sys/stat/lstat.c 2001/11/18 21:47:38 @@ -445,7 +445,7 @@ stat_assist(const char *path, struct sta statbuf->st_gid = getgid(); statbuf->st_nlink = 1; #ifndef NO_ST_BLKSIZE - statbuf->st_blksize = _go32_info_block.size_of_transfer_buffer; + statbuf->st_blksize = _get_cached_blksize(path); #endif /* Make the path explicit. This makes the rest of our job much @@ -932,9 +932,11 @@ lstat(const char *path, struct stat *sta #ifdef TEST +#include + unsigned short _djstat_flags = 0; -void +int main(int argc, char *argv[]) { struct stat stat_buf; @@ -943,7 +945,7 @@ main(int argc, char *argv[]) if (argc < 2) { fprintf (stderr, "Usage: %s <_djstat_flags> \n", argv[0]); - exit(0); + return (EXIT_FAILURE); } if (lstat(*argv, &stat_buf) != 0) @@ -968,6 +970,8 @@ main(int argc, char *argv[]) (long)stat_buf.st_size, (unsigned long)stat_buf.st_mtime, ctime(&stat_buf.st_mtime)); + fprintf(stderr, "\t\t\tBlock size: %d\n", + stat_buf.st_blksize); _djstat_describe_lossage(stderr); } else @@ -980,7 +984,7 @@ main(int argc, char *argv[]) ++argv; } - exit (0); + return (EXIT_SUCCESS); } #endif Index: src/libc/posix/sys/stat/xstat.c =================================================================== RCS file: /cvs/djgpp/djgpp/src/libc/posix/sys/stat/xstat.c,v retrieving revision 1.3 diff -p -u -3 -r1.3 xstat.c --- src/libc/posix/sys/stat/xstat.c 2000/08/05 16:53:46 1.3 +++ src/libc/posix/sys/stat/xstat.c 2001/11/18 21:47:59 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -116,6 +117,76 @@ _getftime(int fhandle, unsigned int *dos *dos_ftime = ((unsigned int)regs.x.dx << 16) + (unsigned int)regs.x.cx; return 0; +} + +/* Cache the cluster size (aka block size) for each drive letter, so we can + * populate the st_blksize of struct stat easily. The cluster size is + * measured in bytes. + * + * ASSUMPTION: path has already been fixed by `_fixpath'. + */ + +/* Comment copied from DJGPP 2.03's src/libc/compat/mntent/mntent.c: + * + * There may be a maximum of 32 block devices. Novell Netware indeed + * allows for 32 disks (A-Z plus 6 more characters from '[' to '\'') + */ +static blksize_t cache_blksize[32]; +static int cache_blksize_count = -1; + +blksize_t +_get_cached_blksize (const char *path) +{ + struct statfs sbuf; + int d; /* index into drive cache = drive_num - 1 */ + static int overmax_d = sizeof(cache_blksize) / sizeof(cache_blksize[0]); + + /* Force initialization in restarted programs (emacs). */ + if (cache_blksize_count != __bss_count) + { + cache_blksize_count = __bss_count; + memset(cache_blksize, 0, sizeof(cache_blksize)); + + /* Default floppy drives to 512B block size. */ + cache_blksize[0] = cache_blksize[1] = 512; + } + + /* Get the drive number. The fixed filename will begin with a lowercase + * letter or a symbol. The symbols for drives > 'z:' occur straight + * after 'Z' in ASCII. + */ + if ((path[0] >= 'a') && (path[0] <= 'z')) + d = path[0] - 'a'; + else + d = path[0] - 'A'; + + if ((d < 0) || (d >= overmax_d)) + { + errno = ENODEV; + return -1; + } + + if (!cache_blksize[d]) + { + if (_is_remote_drive(d + 1)) + { + /* Default remote drives to 32K block size. */ + cache_blksize[d] = 32768; + } + else + { + /* No entry => retrieve cluster size */ + if (statfs(path, &sbuf) != 0) + { + /* Failed, pass error through */ + return -1; + } + + cache_blksize[d] = sbuf.f_bsize; + } + } + + return cache_blksize[d]; } /* Invent an inode number for those files which don't have valid DOS Index: src/libc/posix/sys/stat/stat.c =================================================================== RCS file: /cvs/djgpp/djgpp/src/libc/posix/sys/stat/stat.c,v retrieving revision 1.10 diff -p -u -3 -r1.10 stat.c --- src/libc/posix/sys/stat/stat.c 2000/08/22 18:45:07 1.10 +++ src/libc/posix/sys/stat/stat.c 2001/11/18 21:48:06 @@ -31,9 +31,11 @@ stat(const char *path, struct stat *stat #ifdef TEST +#include + unsigned short _djstat_flags = 0; -void +int main(int argc, char *argv[]) { struct stat stat_buf; @@ -42,7 +44,7 @@ main(int argc, char *argv[]) if (argc < 2) { fprintf (stderr, "Usage: %s <_djstat_flags> \n", argv[0]); - exit(0); + return (EXIT_FAILURE); } if (stat(*argv, &stat_buf) != 0) @@ -67,6 +69,8 @@ main(int argc, char *argv[]) (long)stat_buf.st_size, (unsigned long)stat_buf.st_mtime, ctime(&stat_buf.st_mtime)); + fprintf(stderr, "\t\t\tBlock size: %d\n", + stat_buf.st_blksize); _djstat_describe_lossage(stderr); } else @@ -79,7 +83,7 @@ main(int argc, char *argv[]) ++argv; } - exit (0); + return (EXIT_SUCCESS); } #endif Index: src/libc/posix/sys/stat/xstat.h =================================================================== RCS file: /cvs/djgpp/djgpp/src/libc/posix/sys/stat/xstat.h,v retrieving revision 1.4 diff -p -u -3 -r1.4 xstat.h --- src/libc/posix/sys/stat/xstat.h 2000/08/05 16:53:46 1.4 +++ src/libc/posix/sys/stat/xstat.h 2001/11/18 21:48:14 @@ -68,5 +68,6 @@ extern long __filelength(int extern int _is_remote_handle(int); extern void _djstat_describe_lossage(FILE *); extern int _getftime(int, unsigned int *); +extern blksize_t _get_cached_blksize (const char *path); #endif /* __XSTAT_H */ Index: src/libc/posix/sys/stat/lstat.txh =================================================================== RCS file: /cvs/djgpp/djgpp/src/libc/posix/sys/stat/lstat.txh,v retrieving revision 1.3 diff -p -u -3 -r1.3 lstat.txh --- src/libc/posix/sys/stat/lstat.txh 2001/08/01 10:31:02 1.3 +++ src/libc/posix/sys/stat/lstat.txh 2001/11/18 21:48:25 @@ -14,17 +14,18 @@ it in @var{sbuf}, which has this structu @smallexample struct stat @{ - time_t st_atime; /* time of last access */ - time_t st_ctime; /* time of file's creation */ - dev_t st_dev; /* The drive number (0 = a:) */ - gid_t st_gid; /* what getgid() returns */ - ino_t st_ino; /* starting cluster or unique identifier */ - mode_t st_mode; /* file mode - S_IF* and S_IRUSR/S_IWUSR */ - time_t st_mtime; /* time that the file was last written */ - nlink_t st_nlink; /* 2 + number of subdirs, or 1 for files */ - off_t st_size; /* size of file in bytes */ - off_t st_blksize; /* the size of transfer buffer */ - uid_t st_uid; /* what getuid() returns */ + time_t st_atime; /* time of last access */ + time_t st_ctime; /* time of file's creation */ + dev_t st_dev; /* The drive number (0 = a:) */ + gid_t st_gid; /* what getgid() returns */ + ino_t st_ino; /* starting cluster or unique identifier */ + mode_t st_mode; /* file mode - S_IF* and S_IRUSR/S_IWUSR */ + time_t st_mtime; /* time that the file was last written */ + nlink_t st_nlink; /* 2 + number of subdirs, or 1 for files */ + off_t st_size; /* size of file in bytes */ + blksize_t st_blksize; /* block size in bytes*/ + uid_t st_uid; /* what getuid() returns */ + dev_t st_rdev; /* The drive number (0 = a:) */ @}; @end smallexample Index: src/libc/posix/sys/stat/stat.txh =================================================================== RCS file: /cvs/djgpp/djgpp/src/libc/posix/sys/stat/stat.txh,v retrieving revision 1.8 diff -p -u -3 -r1.8 stat.txh --- src/libc/posix/sys/stat/stat.txh 2001/08/01 10:31:02 1.8 +++ src/libc/posix/sys/stat/stat.txh 2001/11/18 21:48:30 @@ -14,17 +14,18 @@ it in @var{sbuf}, which has this structu @smallexample struct stat @{ - time_t st_atime; /* time of last access */ - time_t st_ctime; /* time of file's creation */ - dev_t st_dev; /* The drive number (0 = a:) */ - gid_t st_gid; /* what getgid() returns */ - ino_t st_ino; /* starting cluster or unique identifier */ - mode_t st_mode; /* file mode - S_IF* and S_IRUSR/S_IWUSR */ - time_t st_mtime; /* time that the file was last written */ - nlink_t st_nlink; /* 2 + number of subdirs, or 1 for files */ - off_t st_size; /* size of file in bytes */ - off_t st_blksize; /* the size of transfer buffer */ - uid_t st_uid; /* what getuid() returns */ + time_t st_atime; /* time of last access */ + time_t st_ctime; /* time of file's creation */ + dev_t st_dev; /* The drive number (0 = a:) */ + gid_t st_gid; /* what getgid() returns */ + ino_t st_ino; /* starting cluster or unique identifier */ + mode_t st_mode; /* file mode - S_IF* and S_IRUSR/S_IWUSR */ + time_t st_mtime; /* time that the file was last written */ + nlink_t st_nlink; /* 2 + number of subdirs, or 1 for files */ + off_t st_size; /* size of file in bytes */ + blksize_t st_blksize; /* block size in bytes*/ + uid_t st_uid; /* what getuid() returns */ + dev_t st_rdev; /* The drive number (0 = a:) */ @}; @end smallexample Index: src/docs/kb/develop.txi =================================================================== RCS file: /cvs/djgpp/djgpp/src/docs/kb/develop.txi,v retrieving revision 1.6 diff -p -u -3 -r1.6 develop.txi --- src/docs/kb/develop.txi 2001/11/02 18:48:50 1.6 +++ src/docs/kb/develop.txi 2001/11/18 21:48:36 @@ -77,6 +77,13 @@ functions, it should include @file{libc/ @sc{gs} register instead of @sc{fs}, to avoid clobbering @sc{fs} which might be used by the application. +@subsection Filename manipulation + +When manipulating filenames, don't use the ctype functions from +@file{ctype.h}, because they are locale sensitive. For example, +instead of using @code{tolower} (@pxref{tolower, , tolower, libc}), +convert the case with explicit code. + @subsection Assertions @cindex Assertions Index: src/docs/kb/wc204.txi =================================================================== RCS file: /cvs/djgpp/djgpp/src/docs/kb/wc204.txi,v retrieving revision 1.100 diff -p -u -3 -r1.100 wc204.txi --- src/docs/kb/wc204.txi 2001/10/17 05:19:49 1.100 +++ src/docs/kb/wc204.txi 2001/11/18 21:48:47 @@ -675,3 +675,10 @@ case lowering. This replaces the functi which is hopelessly buggy on Windows 2000 and XP. New function used in @file{srchpath.c}, @file{readdir.c}, @file{glob.c}, @file{fixpath.c}, @file{lstat.c} and @file{getcwd.c}. + +@findex stat AT r{, and block size} +@findex lstat AT r{, and block size} +@findex fstat AT r{, and block size} +The functions @code{stat}, @code{lstat} and @code{fstat} now fill +the @code{st_blksize} member of @code{struct stat} with the correct block +size for the device where the file is located.