How to implement unix ls -s command in C?
I have to write a program in C which returns file size in blocks just like ls -s command. Please help.
I tried using stat() function (st_blksize)...And I am unable to implement it.
My code looks like this
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <dirent.h>
void main(int argc, char **argv)
{
DIR *dp;
struct dirent *dirp;
struct stat buf;
if(argc < 2)
{
dp = opendir(".");
}
if(dp == NULL)
{
perror("Cannot open directory ");
exit(2);
}
while ((dirp = readdir(dp)) != NULL)
{
printf("%s\n", dirp->d_name);
if (stat(".", &buf))
printf("%d ", buf.st_blksize);
}
开发者_如何学C closedir(dp);
exit(0);
}
It is giving error buf size is not declared. Don't know what is the problem.
Addition
Thanks for the correction. I included the <sys/stat.h>
header file. Now it is giving a warning:
warning: format ‘%d’ expects type ‘int’, but argument 2 has type ‘__blksize_t’
I am new to C so can't make out what should be the possible solution.
You need to include the correct header:
#incude <sys/stat.h>
That declares the structure and associated functions.
Note that stat()
returns zero on success, so your test needs changing (and, as @jsmchmier pointed out in a comment, the call to stat should probably use dirp->d_name
rather than the string literal "."
). Also, st_blksize
is the size of the disk blocks, not the size of the file - that is st_size
(measured in bytes).
POSIX says:
off_t st_size
For regular files, the file size in bytes. For symbolic links, the length in bytes of the pathname contained in the symbolic link.
blksize_t st_blksize
A file system-specific preferred I/O block size for this object. In some file system types, this may vary from file to file.
blkcnt_t st_blocks
Number of blocks allocated for this object.
Note that old (very old) versions of Unix did not support st_blksize
or st_blocks
. I expect most current versions do.
Now it is giving a warning..warning: format ‘%d’ expects type ‘int’, but argument 2 has type ‘__blksize_t’
The chances are that __blksize_t
is an unisgned integer type similar to size_t
. I'd probably use a simple cast:
printf("Block size = %d\n", (int)buf.st_blksize);
Alternatively, if you have C99 available, you could use the facilities from <inttypes.h>
to use a bigger size:
printf("Block size = %" PRIu64 "\n", (uint64_t)buf.st_blksize);
In practice, this is overkill; the block size is unlikely to exceed 2 GB this decade, so int
is likely to be sufficient for the foreseeable future.
From man 2 stat
on my Mac OS X box:
NAME
fstat, fstat64, lstat, lstat64, stat, stat64 -- get file status
SYNOPSIS
#include <sys/stat.h>
int
fstat(int fildes, struct stat *buf);
Note the #include <sys/stat.h>
which you have not done. No doubt the actual layout of struct stat
is defined in there, which is what your compiler is complaining about.
This is one aspect of the man pages which is not always discussed with beginners but is very useful indeed: the whole unix API is documented in them. Oh, it is not always the easiest place to find a function when you know what it should do but don't know what it is called, but all the answers are there.
Open the file, and stat/fstat it. The struct field st_blocks should contain the information you want. If you're dealing with a directory, use opendir, readdir, closedir (posix)... Just pointers to start your work.
EDIT
Add unistd.h and sys/stat.h. Then remember that stat return 0 on success, so
if (stat(dirp->d_name, &buf) == 0)
and I've changed "." to the name of the "element", which is what you wanted, I suppose. Another change is to use st_blocks
and not st_blksize, which says how big is each block (e.g. 1024 or 4096 or...), and -s returns the size in number of blocks, not the size of a block.
The fragment of code is of course incomplete: if you pass an argument, dp is not initialized and even dp == NULL
can fail, you shoud have nullified it before:
DIR *dp = NULL; struct dirent *dirp = NULL;
Careful, one bug in your code is that dp
points to garbage and is only initialised if argc
is less than 2, but you still try to use it in your while
loop and you also try to closedir
it. If you invoke your application with any arguments at all, it will probably crash.
To avoid the warning, change the %d to %ld in the line: printf("%d ", buf.st_blksize);
精彩评论