Bug 129026

Summary: rename(2) system function does not work properly
Product: [Fedora] Fedora Reporter: Evgeny Baskakov <ebaskakov>
Component: kernelAssignee: Dave Jones <davej>
Status: CLOSED NEXTRELEASE QA Contact: Brian Brock <bbrock>
Severity: medium Docs Contact:
Priority: medium    
Version: 2CC: pfrields
Target Milestone: ---   
Target Release: ---   
Hardware: i386   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2005-04-16 04:17:52 UTC Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:

Description Evgeny Baskakov 2004-08-03 06:34:46 UTC
From Bugzilla Helper:
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7)
Gecko/20040616

Description of problem:
Sometimes when I need to rename a lot of files, a few files are unable
to be renamed. I.e., the destination file appears, but the source does
not.

Below is a simple program reproducing the behavior:

// tree_create.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

int main(int argc, char **argv) {
    FILE *list, *out;
    char buffer1[1024];
    char buffer2[1024];
    char *part, *c0;
    char *mem;
    char ch;
    unsigned long count = 0;
    long size;
    int len;
    
    if(argc != 2) {
        printf("usage: tree_creat <list>\n");
        return 0;
    }

    if((list = fopen(argv[1], "r")) == NULL) {
        perror("Bad input file");
        return 1;
    }

    if(fseek(list, 0, SEEK_SET) != 0) {
        perror("Unable to fseek");
        return 1;
    }

    while(fgets(buffer1, sizeof(buffer1)-1, list) &&
          fgets(buffer2, sizeof(buffer2)-1, list) &&
          strlen(buffer1) > 0 &&
          (len = strlen(buffer2)) > 0) 
    {
        size = atol(buffer1);

        if(size < 0) {
            printf("Bad size\n");
            return 1;
        }

        while(len-- && (buffer2[len] == '\n' || buffer2[len] == '\r'))
            buffer2[len] = '\0';

        if(len == 0) {
            printf("Bad fname reached\n");
            return 1;
        }
        
        c0 = buffer2;

        while(*c0 && ((part = strchr(c0, '/')) != NULL)) {
            if(*(part+1) != '/') { // avoid '//' cases
                *part = '\0';

                if(access(buffer2, F_OK) != 0) {
                    if(mkdir(buffer2, 0755) != 0) {
                        printf("Unable to create directory '%s':
%s\n", buffer2, strerror(errno));
                        return 1;
                    }
                }

                *part = '/';
            }

            c0 = part+1;
        }        

        if(*c0 == '\0') {
            printf("Bad fname reached - not a regular file: '%s'\n",
buffer2);
            return 1;
        }
             
        ch = *c0;
        *c0 = '\0';

        sprintf(buffer1, "%sxtmp_my.%d", buffer2, count++);
        
        *c0 = ch;

        if((out = fopen(buffer1, "w")) == NULL) {
            printf("Cannot create file %s: %s\n", buffer1,
strerror(errno));
            return 1;
        }

        if((mem = (char *)malloc(size)) == NULL) {
            perror("Cannot create memory buffer");
            return 1;
        }

        if(fwrite(mem, size, 1, out) < 0) {
            perror("fwrite");
            return 1;
        }

        if(fclose(out) != 0) {
            perror("fclose");
            return 1;
        }

        free(mem);

        if(rename(buffer1, buffer2) != 0) {
            printf("Rename(%s, %s) failed: %s\n", buffer1, buffer2,
strerror(errno));
            return 1;
        }
    }
        
    return 0;
}


Version-Release number of selected component (if applicable):


How reproducible:
Always

Steps to Reproduce:
1. Compile the program: gcc tree_creat.c -o tree_creat
2. Download the following file:
http://www.excelsior-usa.com/download/tmp/file_list.zip
3. Unzip it: unzip file_list.zip. The file 'file_list.txt' shall appear.
5. Place the files 'tree_creat' and 'file_list.txt' to an empty dir.
4. Run the following command: ./tree_creat file_list.txt from that dir.

    

Actual Results:  The file/directory tree appears, and there is a few
files with names like 'xtmp_my.XXX' deeply in the directory tree.
These are temporaly files had to be renamed in the proper names. But
they are NOT renamed. The image of the tree is given in the file
'file_list.txt', there is no such files.


Expected Results:  The directory/file tree must appear. There must be
no additional files.


Additional info:

BTW, after the test, some file system errors may appear.

Comment 1 Jakub Jelinek 2004-08-12 08:40:50 UTC
rename goes straight to the kernel, so I don't see how this could be
a glibc bug.

Comment 2 Alexander Viro 2004-08-12 10:22:05 UTC
which filesystem, what kind of fs errors and BTW, could you post the
strace of actual execution on your box?

Comment 3 Evgeny Baskakov 2004-09-03 08:48:33 UTC
The fs type is ext3. Here is a sample output of the e2fsck program
(command line is 'e2fsck -ycfv /dev/hda11'):

Inode 218081 ref count is 2, should be 1
Inode 231585 ref count is 2, should be 1
Unattached inode 247918
Connect to /lost+found? <YES>
Inode 264534 ref count is 2, should be 1
Inode 278235 ref count is 2, should be 1



Comment 4 Evgeny Baskakov 2004-09-03 09:20:01 UTC
The strace log is quite large (22 Mb).
There is nothing unusal about rename calls: grepped list shows that
all rename() calls return zero.

Comment 5 Dave Jones 2005-04-16 04:17:52 UTC
Fedora Core 2 has now reached end of life, and no further updates will be
provided by Red Hat.  The Fedora legacy project will be producing further kernel
updates for security problems only.

If this bug has not been fixed in the latest Fedora Core 2 update kernel, please
try to reproduce it under Fedora Core 3, and reopen if necessary, changing the
product version accordingly.

Thank you.