mercredi 25 février 2015

Some 'tricks' about ::ftruncate (for windows & linux)

Hi, as today was an interesting development day, where I (with a good advice of one of my teammate) resolved a weird issue, I think it's the good time to write something on that topic because even after some 'Googling' I didn't find anything.

Let's simplify the context.

We just want to open a file, write some text and close it. Later that file will be open again, we will read the text already present and run some text manipulation and rewrite the file.

As the file size and the amount of data we used were small, we use a real simple implementation that we can summarize with the following code.


#include
#include
#include

#include
#include
using namespace std;

int main() {
int fd = -1;
fd = ::open("sample.txt", O_CREAT | O_RDWR, S_IRWXG | S_IRWXO | S_IRWXU);
char* txt = "a small text to fill the file";
::write(fd, txt, strlen(txt));
::close(fd);

fd = ::open("sample.txt", O_CREAT | O_RDWR , S_IRWXG | S_IRWXO | S_IRWXU);
struct stat data;
bool ret = 0 == ::fstat(fd, &data);
if(ret && data.st_size>0)
{
  char* buf = new char[data.st_size+1]; 

  size_t bytesRead = ::read(fd, &buf[0], data.st_size); 
  delete [] buf; 
}
::ftruncate(fd, 0); 
char* txt2 = "another small text to fill the file"; *
::write(fd, txt2, strlen(txt2));
::close(fd); 
 return 0;

Note the call to 'ftruncate' function, we use it to remove the file content. I know that in a real simple code I could have done that in a several others ways (i.e. ::open with O_TRUNC) but consider the fact that our file is shared across multiple process and that the real implementation is a bit more complex.

But let's continue.... The point is that is didn't work as expected. In fact, if the file type was 'ASCII text' after the 1st write, after the second write the file mode changed to 'data' and it wrote the text 'in-binary'. If we don't perform the 'read' or the 'ftruncate' the file type was still the same 'ASCII text'. The solution came from the following: if we 'read' the whole file the reach the end and it may be possible that the file descriptor is in a strange state where it can find the file mode. So we just added a 'seek' before the call to 'ftruncate' and the issues was gone.

i.e. lseek(fd, 0, SEEK_SET);

Easy, but really weird and I didn't find any question and page mentioning that kind of issue ! but there is one :)

That post is related to the question I asked here