[Yaffs] Renaming an open file causes it to be truncated on r…

Top Page
Attachments:
Message as email
+ (text/plain)
+ renametest.c (text/x-csrc)
Delete this message
Reply to this message
Author: Laurence Withers
Date:  
To: yaffs
Subject: [Yaffs] Renaming an open file causes it to be truncated on reboot
Hi,

Recently, I uncovered a problem on a yaffs1 filesystem where calling rename()
on an open file and then closing the file would cause the contents to be lost
on a reboot (or presumably on remounting the filesystem).

I've attached a testcase which consistently shows the problem.

The userspace workaround is to close the file before renaming it.

Bye for now,
-- 
Laurence Withers                              http://www.lwithers.me.uk/
mailto:l@lwithers.me.uk   tel:+447753988197  jabber:

#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <string.h>

/* problem occurs when rename occurs before close, but not after */
#define RENAME_BEFORE_CLOSE

const char* tmp = "/etc/foo.bar.baz.quux";
const char* target = "/etc/dssserver.cfg";

int main(void)
{
    int fd;
    char tmpbuf[4096];
    ssize_t rd;


    fd = open(tmp, O_WRONLY | O_CREAT | O_EXCL, 0644);
    if(fd == -1) {
        perror("open");
        return -1;
    }


    if(write(fd, "fob", 3) != 3) {
        perror("write");
        return -1;
    }


#ifdef RENAME_BEFORE_CLOSE
    if(rename(tmp, target)) {
        perror("rename");
        return -1;
    }
#endif


    fsync(fd);
    if(close(fd)) {
        perror("close");
        return -1;
    }


#ifndef RENAME_BEFORE_CLOSE
    if(rename(tmp, target)) {
        perror("rename");
        return -1;
    }
#endif


    fd = open(target, O_RDONLY);
    if(fd == -1) {
        perror("open");
        return -1;
    }


    while(1) {
        rd = read(fd, tmpbuf, sizeof(tmpbuf));
        switch(rd) {
        case -1:
            perror("read");
            return -1;


        case 0:
            printf("\nEOF\n");
            close(fd);
            return 0;


        default:
            printf("%.*s", rd, tmpbuf);
            break;
        }
    }
}