truncate() file function and EOF problem

D

Davy

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
 
A

Alan Curry

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

Kaz Kylheku

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.
 
Joined
Jan 8, 2010
Messages
1
Reaction score
0
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!
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,989
Messages
2,570,207
Members
46,783
Latest member
RickeyDort

Latest Threads

Top