Verified Commit aac5b4ae authored by Ramon Nou's avatar Ramon Nou Committed by Marc Vef
Browse files

rename plus unlink

md typo

Format
parent a83f8926
Loading
Loading
Loading
Loading
+57 −0
Original line number Diff line number Diff line
@@ -224,6 +224,39 @@ gkfs_open(const std::string& path, mode_t mode, int flags, bool rename) {
        LOG(DEBUG, "File '{}' is renamed __", path);
        errno = ENOENT;
        return -1;
    } else {
        if(md.target_path() != "") {
            auto md_ = gkfs::utils::get_metadata(md.target_path());
            new_path = md.target_path();
            while(md_.value().target_path() != "") {
                new_path = md_.value().target_path();
                md_ = gkfs::utils::get_metadata(md_.value().target_path(),
                                                false);
                if(!md_) {
                    return -1;
                }
            }
            md = *md_;
            // Code is replicated, to avoid changing the const std::string path
            // to a non-const
            if(S_ISDIR(md.mode())) {
                return gkfs_opendir(new_path);
            }


            /*** Regular file exists ***/
            assert(S_ISREG(md.mode()));

            if((flags & O_TRUNC) && ((flags & O_RDWR) || (flags & O_WRONLY))) {
                if(gkfs_truncate(new_path, md.size(), 0)) {
                    LOG(ERROR, "Error truncating file");
                    return -1;
                }
            }

            return CTX->file_map()->add(
                    std::make_shared<gkfs::filemap::OpenFile>(new_path, flags));
        }
    }
#endif
    if(S_ISDIR(md.mode())) {
@@ -306,6 +339,30 @@ gkfs_remove(const std::string& path) {
        return -1;
    }

#ifdef HAS_RENAME
    if(md.value().blocks() == -1) {
        errno = ENOENT;
        return -1;
    } else {
        if(md.value().target_path() != "") {
            auto md_ = gkfs::utils::get_metadata(md.value().target_path());
            std::string new_path = md.value().target_path();
            while(md.value().target_path() != "") {
                new_path = md.value().target_path();
                md = gkfs::utils::get_metadata(md.value().target_path(), false);
                if(!md) {
                    return -1;
                }
            }
            auto err = gkfs::rpc::forward_remove(new_path);
            if(err) {
                errno = err;
                return -1;
            }
            return 0;
        }
    }
#endif
    auto err = gkfs::rpc::forward_remove(path);
    if(err) {
        errno = err;
+1 −0
Original line number Diff line number Diff line
@@ -68,6 +68,7 @@ add_executable(gkfs.io
    gkfs.io/dup_validate.cpp
    gkfs.io/syscall_coverage.cpp
    gkfs.io/rename.cpp
    gkfs.io/unlink.cpp
)

include(FetchContent)
+1 −0
Original line number Diff line number Diff line
@@ -68,6 +68,7 @@ init_commands(CLI::App& app) {
    dup_validate_init(app);
    syscall_coverage_init(app);
    rename_init(app);
    unlink_init(app);
}


+10 −1
Original line number Diff line number Diff line
@@ -466,7 +466,7 @@ class FileCompareOutputSchema(Schema):
        return namedtuple('FileCompareReturn', ['retval', 'errno'])(**data)

class RenameOutputSchema(Schema):
    """Schema to deserialize the results of an lrename() execution"""
    """Schema to deserialize the results of an rename() execution"""
    retval = fields.Integer(required=True)
    errno = Errno(data_key='errnum', required=True)

@@ -474,6 +474,14 @@ class RenameOutputSchema(Schema):
    def make_object(self, data, **kwargs):
        return namedtuple('RenameReturn', ['retval', 'errno'])(**data)

class UnlinkOutputSchema(Schema):
    """Schema to deserialize the results of an unlink() execution"""
    retval = fields.Integer(required=True)
    errno = Errno(data_key='errnum', required=True)

    @post_load
    def make_object(self, data, **kwargs):
        return namedtuple('UnlinkReturn', ['retval', 'errno'])(**data)

class IOParser:

@@ -509,6 +517,7 @@ class IOParser:
        'dup_validate' : DupValidateOutputSchema(),
        'syscall_coverage' : SyscallCoverageOutputSchema(),
        'rename' : RenameOutputSchema(),
        'unlink' : UnlinkOutputSchema(),
    }

    def parse(self, command, output):
+248 −0
Original line number Diff line number Diff line
@@ -133,3 +133,251 @@ def test_rename_inverse(gkfs_daemon, gkfs_client):

    # It should work but the data should be on file 2 really

def test_chain_rename(gkfs_daemon, gkfs_client):

    filea = gkfs_daemon.mountdir / "filea"
    fileb = gkfs_daemon.mountdir / "fileb"
    filec = gkfs_daemon.mountdir / "filec"
    filed = gkfs_daemon.mountdir / "filed"
    filee = gkfs_daemon.mountdir / "filee"

    # create a file in gekkofs
    ret = gkfs_client.open(filea,
                           os.O_CREAT | os.O_WRONLY,
                           stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)

    assert ret.retval == 10000

    # write a buffer we know
    buf = b'42'
    ret = gkfs_client.write(filea, buf, len(buf))

    assert ret.retval == len(buf) # Return the number of written bytes

    ret = gkfs_client.stat(filea)
    assert ret.retval != 1

    ret = gkfs_client.stat(fileb)
    assert ret.retval == -1

    ret = gkfs_client.rename(filea, fileb)

    assert ret.retval == 0

    ret = gkfs_client.stat(filea)
    assert ret.retval == -1

    ret = gkfs_client.stat(fileb)
    assert ret.retval != 1

    # File is renamed, and innacesible

    # Read contents of file2
    ret = gkfs_client.open(fileb, os.O_RDONLY)
    assert ret.retval == 10000

    ret = gkfs_client.read(fileb, len(buf))
    assert ret.retval == len(buf)
    assert ret.buf == buf

    ret = gkfs_client.rename(filea, filec)

    #filea should be gone
    assert ret.retval == -1

    ret = gkfs_client.rename(fileb, filec)
    assert ret.retval == 0

    ret = gkfs_client.read(filec, len(buf))
    assert ret.retval == len(buf)
    assert ret.buf == buf

    ret = gkfs_client.rename(filec, filed)
    assert ret.retval == 0

    ret = gkfs_client.read(filed, len(buf))
    assert ret.retval == len(buf)
    assert ret.buf == buf


    ret = gkfs_client.rename(filed, filee)
    assert ret.retval == 0

    ret = gkfs_client.read(filee, len(buf))
    assert ret.retval == len(buf)
    assert ret.buf == buf


    # check the stat of old files
    ret = gkfs_client.stat(fileb)
    assert ret.retval == -1

    ret = gkfs_client.stat(filec)
    assert ret.retval == -1

    ret = gkfs_client.stat(filed)
    assert ret.retval == -1

    ret = gkfs_client.stat(filee)
    assert ret.retval == 0
  
def test_cyclic_rename(gkfs_daemon, gkfs_client):

    fileold = gkfs_daemon.mountdir / "fileold"
    filenew = gkfs_daemon.mountdir / "filenew"
    

    # create a file in gekkofs
    ret = gkfs_client.open(fileold,
                           os.O_CREAT | os.O_WRONLY,
                           stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)

    assert ret.retval == 10000

    # write a buffer we know
    buf = b'42'
    ret = gkfs_client.write(fileold, buf, len(buf))

    assert ret.retval == len(buf) # Return the number of written bytes

    ret = gkfs_client.stat(fileold)
    assert ret.retval != 1

    ret = gkfs_client.stat(filenew)
    assert ret.retval == -1

    ret = gkfs_client.rename(fileold, filenew)

    assert ret.retval == 0

    ret = gkfs_client.stat(fileold)
    assert ret.retval == -1

    ret = gkfs_client.stat(filenew)
    assert ret.retval != 1

    
    #Cyclic rename
    ret = gkfs_client.rename(filenew, fileold)

    ret = gkfs_client.stat(fileold)
    assert ret.retval != -1

    ret = gkfs_client.stat(filenew)
    assert ret.retval == -1
    # Read contents of filee
    ret = gkfs_client.open(fileold, os.O_RDONLY)
    assert ret.retval == 10000

    ret = gkfs_client.read(fileold, len(buf))
    assert ret.retval == len(buf)
    assert ret.buf == buf

def test_rename_plus_trunc(gkfs_daemon, gkfs_client):

    fileold = gkfs_daemon.mountdir / "fileoldtr"
    filenew = gkfs_daemon.mountdir / "filenewtr"
    

    # create a file in gekkofs
    ret = gkfs_client.open(fileold,
                           os.O_CREAT | os.O_WRONLY,
                           stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)

    assert ret.retval == 10000

    # write a buffer we know
    buf = b'42'
    ret = gkfs_client.write(fileold, buf, len(buf))

    assert ret.retval == len(buf) # Return the number of written bytes

    # rename file
    ret = gkfs_client.rename(fileold, filenew)
    assert ret.retval == 0

    ret = gkfs_client.stat(filenew)
    assert ret.retval != -1
    assert ret.statbuf.st_size == len(buf)

    # truncate file
    ret = gkfs_client.truncate(filenew, 1)
    assert ret.retval == 0
    
    ret = gkfs_client.read(filenew, len(buf))
    assert ret.retval == 1
    assert ret.buf == b'4\x00'  # buf includes the null byte

    ret = gkfs_client.stat(filenew)
    assert ret.retval != -1
    assert ret.statbuf.st_size == 1

def test_rename_plus_lseek(gkfs_daemon, gkfs_client):

    fileold = gkfs_daemon.mountdir / "fileoldlseek"
    filenew = gkfs_daemon.mountdir / "filenewlseek"
    

    # create a file in gekkofs
    ret = gkfs_client.open(fileold,
                           os.O_CREAT | os.O_WRONLY,
                           stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)

    assert ret.retval == 10000

    # write a buffer we know
    buf = b'42'
    ret = gkfs_client.write(fileold, buf, len(buf))

    assert ret.retval == len(buf) # Return the number of written bytes

    # rename file
    ret = gkfs_client.rename(fileold, filenew)
    assert ret.retval == 0

    ret = gkfs_client.stat(filenew)
    assert ret.retval != -1
    assert ret.statbuf.st_size == len(buf)

    ret = gkfs_client.lseek(filenew, 0, os.SEEK_END)
    assert ret.retval == 2                      #Two bytes written
    


def test_rename_delete(gkfs_daemon, gkfs_client):

    fileold = gkfs_daemon.mountdir / "fileoldrename"
    filenew = gkfs_daemon.mountdir / "filenewrename"
    

    # create a file in gekkofs
    ret = gkfs_client.open(fileold,
                           os.O_CREAT | os.O_WRONLY,
                           stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)

    assert ret.retval == 10000

    # write a buffer we know
    buf = b'42'
    ret = gkfs_client.write(fileold, buf, len(buf))
    assert ret.retval == len(buf) # Return the number of written bytes

    # rename file
    ret = gkfs_client.rename(fileold, filenew)
    assert ret.retval == 0

    ret = gkfs_client.stat(filenew)
    assert ret.retval != -1
    assert ret.statbuf.st_size == len(buf)

    ret = gkfs_client.unlink(fileold) # Remove original file (error)
    assert ret.retval != 0

    ret = gkfs_client.unlink(filenew) # Remove renamed file (success)
    assert ret.retval == 0        

    ret = gkfs_client.stat(filenew)
    assert ret.retval == -1