开发者

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);

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜