truncate() file function and EOF problem

Discussion in 'C Programming' started by Davy, Dec 24, 2009.

  1. Davy

    Davy Guest

    truncate() file function and EOF problem

    Hi all,

    I am trying to do some C programming on Linux (exercise in Linux
    Programming by example)and encounter a problem of write EOF to file
    (the exercise is write a truncate() function).

    For example, I have a file with length 20, and I want to truncate it
    to 16, my method is use write() to write to offset 16 a EOF char. But
    "cat
    file" shows the method is wrong. I guess my understanding of EOF maybe
    wrong, because EOF is a status signal provided by some function like
    read(), but
    how to do it?

    my wrong code:
    //-----------------------
    else if (newendpos < endpos) {
    /* remove content */
    lseek(fd, newendpos, SEEK_SET);
    char eof = EOF;
    write(fd, &eof, sizeof(char));
    }
    //-----------------------

    Best regards,
    Davy
    Davy, Dec 24, 2009
    #1
    1. Advertising

  2. Davy

    Alan Curry Guest

    In article <>,
    Davy <> wrote:
    >
    >Hi all,
    >
    >I am trying to do some C programming on Linux (exercise in Linux
    >Programming by example)and encounter a problem of write EOF to file
    >(the exercise is write a truncate() function).


    The exercise is misconceived. The only sensible way to do file truncation
    (other than "truncate to 0 size") is with the truncate() and ftruncate()
    POSIX functions. They have no equivalents in stdio, and there's no way to
    build them up from operations that do exist in stdio.

    >
    >For example, I have a file with length 20, and I want to truncate it
    >to 16, my method is use write() to write to offset 16 a EOF char. But


    There is no such thing as an EOF character. EOF is a value that indicates the
    absence of any character.

    >file" shows the method is wrong. I guess my understanding of EOF maybe
    >wrong, because EOF is a status signal provided by some function like
    >read(), but


    Not read(), since read isn't a stdio function. The macro EOF is associated
    mainly with stdio functions.

    >how to do it?


    If you want to shorten a file witout losing the beginning part, you have
    truncate() and ftruncate() from <unistd.h>, or you have a disgusting hack:
    make a copy of the data you want to keep in the beginning, then open the file
    destructively (fopen "w") and rewrite it all.

    The other kind of "truncation" (making a file bigger without explicitly
    writing all the data between the current end and the new end) may be
    accomplished with seek and write, but you will have to write at least 1 byte
    at the end to make it happen. Even here "just use the POSIX truncate
    function" is still the best answer.

    Here's a solution that'll work on almost any Linux system and quite a few
    others. It doesn't call any functions that aren't in the C standard.

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>

    void truncate(const char *filename, size_t size)
    {
    char buf[strlen(filename)+100];
    sprintf(buf, "perl -e 'truncate \"%s\", %zu'", filename, size);
    system(buf);
    }

    Have we learned anything from this "exercise" in avoiding the right tool for
    the job?

    Sensible questions about the POSIX standard truncate() and ftruncate() may be
    posted to comp.unix.programmer (although there's really not much to know
    about them)

    --
    Alan Curry
    Alan Curry, Dec 24, 2009
    #2
    1. Advertising

  3. Davy

    Kaz Kylheku Guest

    On 2009-12-24, Davy <> wrote:
    > truncate() file function and EOF problem
    >
    > Hi all,
    >
    > I am trying to do some C programming on Linux (exercise in Linux
    > Programming by example)and encounter a problem of write EOF to file
    > (the exercise is write a truncate() function).


    This function cannot be written. Truncating an existing function
    is a function that can only be done in the operating system.

    The standard C language has no function for doing this.

    truncate is a POSIX extension to C.

    You cannot write truncate using any combination of functions in C, or
    other POSIX functions (not including alternative API's like ftruncate of
    course).

    Of course, what you can do is copy the contents of the 20 byte file to
    another file, retaining only the first 16 bytes. Then you can rename
    that file to the original name (rename is even a standard C function).
    You may have to remove the original with remove (remove is also a
    standard C function). Not every operating system allows a rename to
    an existing file.

    Even if you take this approach, it's not maximally portable. C
    imlementations can add null padding bytes to binary files. So what will
    happen is that your truncate-by-copy program might not accurately
    truncate files with byte precision.

    See, the C standard I/O library can be implemented on operating systems
    that don't track the exact length of binary files, but, say, only the
    number of disk blocks occupied. So for instance if the block size is
    512 bytes, then the creation of a 40 byte binary file actually results
    in a 512 byte file; bytes 0-39 are the ones you write, and 40 through
    511 are null padding bytes.

    On such an implementation, it's likely that text files are either
    a different kind of object at the filesystem level, so that they
    can have a precise length, or they are given a precise length by
    means of an end-of-text sentinel byte (but that has nothing to do with
    the EOF number in ISO C; the text stream implementation in C will hide
    the existence of such a byte from you).

    > For example, I have a file with length 20, and I want to truncate it
    > to 16, my method is use write() to write to offset 16 a EOF char.


    Writing a byte at offset 16 will not shorten the file.

    There is no EOF character; this is just the name of an integer constant
    in ISO C, whose value is returned as an error indicator from several
    functions.

    How the length of a file is represented in ANSI C is up to the
    implementation. Text files may in fact use a special character.
    This is not possible in binary files, but note that binary files in C
    are not required to have a precise length. As mentioned before,
    implementations are allowed to add null padding bytes to binary files.

    In the POSIX world files (binary or text; there is no representational
    difference in this regard) have a length accurate down to the byte.
    There is no EOF character. A 17 byte file consists of 17 bytes.
    Of course, the filesystem allocates this in some larger block.
    But the file object has a length field which reads 17.

    Also note that, in POSIX, if you write a byte to offset 16 of an empty
    file, you get a 17 byte file, not a 16 byte file. You can prove this by
    induction. The base case is this: if you write a byte at position 0 (the
    first position) of a file, you get a one byte file---true by inspection.
    Inductively, if writing a byte at position k results in a k+1 length
    file, it must be the case that writing another byte next to that byte at
    position k+1 results in a k+2 length file. :)

    > "cat
    > file" shows the method is wrong.


    Note that in your OS, you can check the length of the file without
    dumping its contents by listing it with ls -l.

    > wrong, because EOF is a status signal provided by some function like
    > read(), but


    The POSIX function read does not use EOF as a signal. It returns 0 when
    a file (or other device) does not have any more bytes that can be read,
    or a value smaller than the requested size, if the file or device has
    fewer remaining bytes than the requested size.

    The ISO C fread function also does not use EOF as a signal; it returns
    size_t, which is an unsigned type that cannot represent EOF.
    Kaz Kylheku, Dec 24, 2009
    #3
  4. Davy

    jmeisell

    Joined:
    Jan 8, 2010
    Messages:
    1
    So, there is NO way to make a file smaller in place?

    Issue is this: your logfiles have filled up your storage space. You want to delete the old entries and retain the new ones. You have no working space in which to copy a portion of the logfile and then delete the big one. So either the file start or end pointer needs to be moved (depending on how the logfile is formatted). Maybe the source code for truncate () and/or logrotate have some ideas!
    jmeisell, Jan 8, 2010
    #4
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Kobu
    Replies:
    10
    Views:
    624
    Keith Thompson
    Mar 4, 2005
  2. SpreadTooThin

    ifstream eof not reporting eof?

    SpreadTooThin, Jun 13, 2007, in forum: C++
    Replies:
    10
    Views:
    694
    James Kanze
    Jun 15, 2007
  3. Timothy Madden
    Replies:
    3
    Views:
    320
    jameskuyper
    Nov 10, 2008
  4. Leslie Viljoen

    File#truncate fills file with zeros

    Leslie Viljoen, Nov 16, 2010, in forum: Ruby
    Replies:
    1
    Views:
    137
    Leslie Viljoen
    Nov 16, 2010
  5. Jan Burse
    Replies:
    67
    Views:
    1,058
    Jan Burse
    Mar 14, 2012
Loading...

Share This Page