2

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

    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.

6
  • you need to be more specific - and to try before to ask Commented Jun 6, 2010 at 17:58
  • What part are you having trouble implementing? Commented Jun 6, 2010 at 18:01
  • Please add the homework tag, and explain what you have tried so far, otherwise your question will probably closed. Commented Jun 6, 2010 at 18:02
  • 3
    "I am unable to implement it" is a monumentally unhelpful explanation of where you are stuck. What are you doing, and how does the result differ from what you expect? Commented Jun 6, 2010 at 19:04
  • 2
    I would imagine that stat(".", &buf) is incorrect and you would prefer something more like stat(dirp->d_name, &buf). Commented Jun 6, 2010 at 19:38

5 Answers 5

5

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.

Sign up to request clarification or add additional context in comments.

1 Comment

If you are relying on uint64_t then you need C99; in which case you have unsigned long long, with the %llu format specifier, so you might as well use that (which is at least as big as uint64_t).
1

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.

Comments

1

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;

2 Comments

The ls command does not open files - nor should its replacement.
The user's original post talked about just "like ls -s", not specifying he wanted a clone of ls, but just that he needed the info "returned". He could use fstat if he's already opened the file for whatever reason. If you prefer read my words like: Open the file and fstat or stat it... Btw, between opendir, readdir and closedir I should've put stat, otherwise here one can think I believe that opendir-readdir is enough to get files' struct stat... Later he posted the code, I am going to take a look at it now
1

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.

Comments

0

To avoid the warning, change the %d to %ld in the line: printf("%d ", buf.st_blksize);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.