Mail Archives: djgpp-workers/2001/11/02/09:50:44
Hello.
A long time ago in a galaxy very, very close to here, Eli Zaretskii wrote:
> The logical step would be to add code to `stat' that computes the
> st_blocks field (it is not in `struct stat', so you will need to
> change the definition of `struct stat' as well). This could be done
> by computing the cluster size for each drive letter the first time you
> see that drive, and caching that value for future use. Then you can
> round up the file's size using that cluster size.
>
> Once we support st_blocks, the changes to `du' to use it would be
> trivial. Ideally, the `configure' script should detect that and cause
> `du' to use it automagically.
Please find below a patch that adds and calculates st_blocks in struct
stat. Please note that the patch to fd_props.h may report some fuzz, when
applied. I hacked out a small diff, which I had added when I started
trying to add LFS support to DJGPP.
Here's how the patch works:
xstat.c now has a cache for storing the block size on various drive
letters. The first time a file on, say, C: is stat'd, statvfs is called on
the filename. The resulting block size is stored and then returned for all
files on C: in the future. Note that _fixpath is called in the caching
mechanism, so it should cope with joined drives, I think.
I added a function to fd_props.h to return the filename, given a handle.
This is needed in fstat, so that we know which drive the file is on.
One problem I can think of is that there is no aging out in the cache. So
if we map and unmap a network drive during the execution of a program
which has stat'd the original mapping, the program will not notice. Is
this really a problem?
Now to the original motivation: fileutils does detect that we have
st_blocks and then it uses it. Unfortunately du 4.0 rounds file sizes
down, so if you have a big block size (like I seem to on my HD) and you
ask for a size shown in <something>bytes, then the file sizes are bogus
(e.g. 0 for files < 16K on my HD). du 4.1 rounds up file sizes, so it
should be OK.
Same st_blocks values:
My 24GB DOS partition: 16 Kbytes
Mapped network drive (Samba share from Linux box): 32 Kbytes
1.44MB floppy: 512 bytes
Oh yeah, I also fixed the *stat test programs a bit - include needed
headers, return values from main - and made them display block
information.
OK to commit?
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 -c -3 -r1.6 types.h
*** include/sys/types.h 2000/12/05 14:05:53 1.6
--- include/sys/types.h 2001/11/02 14:36:20
*************** extern "C" {
*** 13,19 ****
#ifndef __STRICT_ANSI__
#include <sys/djtypes.h>
!
typedef int dev_t;
typedef int ino_t;
typedef int mode_t;
--- 13,21 ----
#ifndef __STRICT_ANSI__
#include <sys/djtypes.h>
!
! 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 -c -3 -r1.4 stat.h
*** include/sys/stat.h 2000/12/05 14:05:53 1.4
--- include/sys/stat.h 2001/11/02 14:36:24
*************** struct stat {
*** 49,57 ****
time_t st_mtime;
nlink_t st_nlink;
off_t st_size;
! off_t st_blksize;
uid_t st_uid;
dev_t st_rdev; /* unused */
};
int chmod(const char *_path, mode_t _mode);
--- 49,58 ----
time_t st_mtime;
nlink_t st_nlink;
off_t st_size;
! blksize_t st_blksize;
uid_t st_uid;
dev_t st_rdev; /* unused */
+ blkcnt_t st_blocks;
};
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 -c -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/02 14:36:27
*************** extern "C" {
*** 8,13 ****
--- 8,15 ----
#ifndef __dj_ENFORCE_ANSI_FREESTANDING
+ #include <string.h>
+
#ifndef __STRICT_ANSI__
#ifndef _POSIX_SOURCE
*************** static __inline__ void __clear_fd_flags(
*** 63,68 ****
--- 68,78 ----
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 -c -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/02 14:36:34
***************
*** 106,111 ****
--- 106,112 ----
#include <dos.h>
#include <sys/types.h>
#include <sys/stat.h>
+ #include <libc/fd_props.h>
#include <dpmi.h>
#include <go32.h>
*************** fstat_assist(int fhandle, struct stat *s
*** 434,440 ****
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;
#endif
/* If SFT entry for our handle is required and available, we will use
it. */
--- 435,451 ----
stat_buf->st_gid = getgid();
stat_buf->st_nlink = 1;
#ifndef NO_ST_BLKSIZE
! if (__get_fd_name(fhandle))
! {
! const char *filename = __get_fd_name(fhandle);
! stat_buf->st_blksize = _get_cached_blksize(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. */
*************** fstat_assist(int fhandle, struct stat *s
*** 717,722 ****
--- 728,738 ----
/* Additional time info for LFN platforms. */
set_fstat_times (fhandle, stat_buf);
+
+ /* Number of blocks */
+ stat_buf->st_blocks = _get_blkcnt(stat_buf->st_size,
+ stat_buf->st_blksize);
+
return 0;
}
*************** fstat_assist(int fhandle, struct stat *s
*** 856,861 ****
--- 872,881 ----
/* Additional time info for LFN platforms. */
set_fstat_times (fhandle, stat_buf);
+
+ /* Number of blocks */
+ stat_buf->st_blocks = _get_blkcnt(stat_buf->st_size,
+ stat_buf->st_blksize);
}
return 0;
}
*************** int main(int argc, char *argv[])
*** 936,941 ****
--- 956,964 ----
_djstat_describe_lossage(stderr);
}
+ if (!argc)
+ return EXIT_SUCCESS;
+
/* Now call fstat() for each command-line argument. */
while (++argv, --argc)
{
*************** int main(int argc, char *argv[])
*** 956,961 ****
--- 979,987 ----
fprintf (stderr, "\t\t\tTimes: %lu %lu\n",
(unsigned long)stat_buf.st_atime,
(unsigned long)stat_buf.st_ctime);
+ fprintf(stderr, "\t\t\tBlocks: %d %d\n",
+ stat_buf.st_blksize,
+ stat_buf.st_blocks);
_djstat_describe_lossage(stderr);
}
else
*************** int main(int argc, char *argv[])
*** 965,971 ****
_djstat_describe_lossage(stderr);
}
}
! return 0;
}
#endif /* TEST */
--- 991,997 ----
_djstat_describe_lossage(stderr);
}
}
! 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 -c -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/02 14:36:42
*************** stat_assist(const char *path, struct sta
*** 445,451 ****
statbuf->st_gid = getgid();
statbuf->st_nlink = 1;
#ifndef NO_ST_BLKSIZE
! statbuf->st_blksize = _go32_info_block.size_of_transfer_buffer;
#endif
/* Make the path explicit. This makes the rest of our job much
--- 445,451 ----
statbuf->st_gid = getgid();
statbuf->st_nlink = 1;
#ifndef NO_ST_BLKSIZE
! statbuf->st_blksize = _get_cached_blksize(path);
#endif
/* Make the path explicit. This makes the rest of our job much
*************** stat_assist(const char *path, struct sta
*** 868,873 ****
--- 868,876 ----
statbuf->st_size = (nfiles + extra) * sizeof(struct full_dirent);
}
+ /* Number of blocks */
+ statbuf->st_blocks = _get_blkcnt(statbuf->st_size,
statbuf->st_blksize);
+
return 0;
}
*************** lstat(const char *path, struct stat *sta
*** 932,940 ****
#ifdef TEST
unsigned short _djstat_flags = 0;
! void
main(int argc, char *argv[])
{
struct stat stat_buf;
--- 935,945 ----
#ifdef TEST
+ #include <stdlib.h>
+
unsigned short _djstat_flags = 0;
! int
main(int argc, char *argv[])
{
struct stat stat_buf;
*************** main(int argc, char *argv[])
*** 943,949 ****
if (argc < 2)
{
fprintf (stderr, "Usage: %s <_djstat_flags> <file...>\n",
argv[0]);
! exit(0);
}
if (lstat(*argv, &stat_buf) != 0)
--- 948,954 ----
if (argc < 2)
{
fprintf (stderr, "Usage: %s <_djstat_flags> <file...>\n",
argv[0]);
! return (EXIT_FAILURE);
}
if (lstat(*argv, &stat_buf) != 0)
*************** main(int argc, char *argv[])
*** 968,973 ****
--- 973,981 ----
(long)stat_buf.st_size,
(unsigned long)stat_buf.st_mtime,
ctime(&stat_buf.st_mtime));
+ fprintf(stderr, "\t\t\tBlocks: %d %d\n",
+ stat_buf.st_blksize,
+ stat_buf.st_blocks);
_djstat_describe_lossage(stderr);
}
else
*************** main(int argc, char *argv[])
*** 980,986 ****
++argv;
}
! exit (0);
}
#endif
--- 988,994 ----
++argv;
}
! 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 -c -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/02 14:36:50
***************
*** 19,24 ****
--- 19,27 ----
#include <limits.h>
#include <time.h>
#include <errno.h>
+ #include <assert.h>
+ #include <ctype.h>
+ #include <sys/vfs.h>
#include <dos.h>
#include <dpmi.h>
#include <libc/farptrgs.h>
*************** _getftime(int fhandle, unsigned int *dos
*** 116,121 ****
--- 119,176 ----
*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.
+ */
+
+ /* 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)
+ {
+ char fixed_path[PATH_MAX + 1];
+ struct statfs sbuf;
+ int d; /* drive */
+ 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));
+ }
+
+ _fixpath(path, fixed_path);
+ d = tolower(path[0]) - 'a';
+
+ if ((d < 0) || (d >= overmax_d))
+ {
+ errno = ENODEV;
+ return -1;
+ }
+
+ if (!cache_blksize[d])
+ {
+ /* 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 -c -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/02 14:36:53
*************** stat(const char *path, struct stat *stat
*** 31,39 ****
#ifdef TEST
unsigned short _djstat_flags = 0;
! void
main(int argc, char *argv[])
{
struct stat stat_buf;
--- 31,41 ----
#ifdef TEST
+ #include <stdlib.h>
+
unsigned short _djstat_flags = 0;
! int
main(int argc, char *argv[])
{
struct stat stat_buf;
*************** main(int argc, char *argv[])
*** 42,48 ****
if (argc < 2)
{
fprintf (stderr, "Usage: %s <_djstat_flags> <file...>\n",
argv[0]);
! exit(0);
}
if (stat(*argv, &stat_buf) != 0)
--- 44,50 ----
if (argc < 2)
{
fprintf (stderr, "Usage: %s <_djstat_flags> <file...>\n",
argv[0]);
! return (EXIT_FAILURE);
}
if (stat(*argv, &stat_buf) != 0)
*************** main(int argc, char *argv[])
*** 67,72 ****
--- 69,77 ----
(long)stat_buf.st_size,
(unsigned long)stat_buf.st_mtime,
ctime(&stat_buf.st_mtime));
+ fprintf(stderr, "\t\t\tBlocks: %d %d\n",
+ stat_buf.st_blksize,
+ stat_buf.st_blocks);
_djstat_describe_lossage(stderr);
}
else
*************** main(int argc, char *argv[])
*** 79,85 ****
++argv;
}
! exit (0);
}
#endif
--- 84,90 ----
++argv;
}
! 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 -c -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/02 14:36:57
*************** extern unsigned short _djstat_fail_bit
*** 56,61 ****
--- 56,76 ----
extern unsigned short _djstat_flags;
+ static inline blkcnt_t _get_blkcnt (off_t _st_size, blksize_t
_st_blksize)
+ {
+ blkcnt_t _blkcnt;
+
+ if (!_st_size)
+ return 0;
+
+ /* Round up to the nearest block. */
+ _blkcnt = _st_size / _st_blksize;
+ if ((_blkcnt * _st_blksize) < _st_size)
+ _blkcnt++;
+
+ return _blkcnt;
+ }
+
extern time_t _file_time_stamp(unsigned int);
extern ino_t _invent_inode(const char *, unsigned, unsigned
long);
extern unsigned short _get_magic(const char *, int);
*************** extern long __filelength(int
*** 68,72 ****
--- 83,88 ----
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 -c -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/02 14:37:06
*************** it in @var{sbuf}, which has this structu
*** 14,30 ****
@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 */
@};
@end smallexample
--- 14,31 ----
@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 */
! blksize_t st_blksize; /* block size in bytes*/
! uid_t st_uid; /* what getuid() returns */
! blkcnt_t st_blocks; /* blocks used by file */
@};
@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 -c -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/02 14:37:12
*************** it in @var{sbuf}, which has this structu
*** 14,30 ****
@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 */
@};
@end smallexample
--- 14,31 ----
@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 */
! blksize_t st_blksize; /* block size in bytes*/
! uid_t st_uid; /* what getuid() returns */
! blkcnt_t st_blocks; /* blocks used by file */
@};
@end smallexample
Index: src/docs/kb/wc204.txi
===================================================================
RCS file: /cvs/djgpp/djgpp/src/docs/kb/wc204.txi,v
retrieving revision 1.100
diff -p -c -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/02 14:37:42
*************** case lowering. This replaces the functi
*** 675,677 ****
--- 675,686 ----
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{, and block size}
+ @findex lstat{, 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. @code{struct stat} now
+ has a @code{st_blocks} member, which contains the number of blocks
+ occupied by the file.
- Raw text -