github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/images/basic/integrationtest/test_copy_up.c (about)

     1  #include <err.h>
     2  #include <fcntl.h>
     3  #include <stdio.h>
     4  #include <string.h>
     5  #include <sys/mman.h>
     6  #include <unistd.h>
     7  
     8  int main(int argc, char** argv) {
     9    const char kTestFilePath[] = "copy_up_testfile.txt";
    10    const char kOldFileData[] = "old data\n";
    11    const char kNewFileData[] = "new data\n";
    12    const size_t kPageSize = sysconf(_SC_PAGE_SIZE);
    13  
    14    // Open a file that already exists in a host overlayfs lower layer.
    15    const int fd_rdonly = open(kTestFilePath, O_RDONLY);
    16    if (fd_rdonly < 0) {
    17      err(1, "open(%s, O_RDONLY)", kTestFilePath);
    18    }
    19  
    20    // Check that the file's initial contents are what we expect when read via
    21    // syscall.
    22    char oldbuf[sizeof(kOldFileData)] = {};
    23    ssize_t n = pread(fd_rdonly, oldbuf, sizeof(oldbuf), 0);
    24    if (n < 0) {
    25      err(1, "initial pread");
    26    }
    27    if (n != strlen(kOldFileData)) {
    28      errx(1, "short initial pread (%ld/%lu bytes)", n, strlen(kOldFileData));
    29    }
    30    if (strcmp(oldbuf, kOldFileData) != 0) {
    31      errx(1, "initial pread returned wrong data: %s", oldbuf);
    32    }
    33  
    34    // Check that the file's initial contents are what we expect when read via
    35    // memory mapping.
    36    void* page = mmap(NULL, kPageSize, PROT_READ, MAP_SHARED, fd_rdonly, 0);
    37    if (page == MAP_FAILED) {
    38      err(1, "mmap");
    39    }
    40    if (strcmp(page, kOldFileData) != 0) {
    41      errx(1, "mapping contains wrong initial data: %s", (const char*)page);
    42    }
    43  
    44    // Open the same file writably, causing host overlayfs to copy it up, and
    45    // replace its contents.
    46    const int fd_rdwr = open(kTestFilePath, O_RDWR);
    47    if (fd_rdwr < 0) {
    48      err(1, "open(%s, O_RDWR)", kTestFilePath);
    49    }
    50    n = write(fd_rdwr, kNewFileData, strlen(kNewFileData));
    51    if (n < 0) {
    52      err(1, "write");
    53    }
    54    if (n != strlen(kNewFileData)) {
    55      errx(1, "short write (%ld/%lu bytes)", n, strlen(kNewFileData));
    56    }
    57    if (ftruncate(fd_rdwr, strlen(kNewFileData)) < 0) {
    58      err(1, "truncate");
    59    }
    60  
    61    int failed = 0;
    62  
    63    // Check that syscalls on the old FD return updated contents. (Before Linux
    64    // 4.18, this requires that runsc use a post-copy-up FD to service the read.)
    65    char newbuf[sizeof(kNewFileData)] = {};
    66    n = pread(fd_rdonly, newbuf, sizeof(newbuf), 0);
    67    if (n < 0) {
    68      err(1, "final pread");
    69    }
    70    if (n != strlen(kNewFileData)) {
    71      warnx("short final pread (%ld/%lu bytes)", n, strlen(kNewFileData));
    72      failed = 1;
    73    } else if (strcmp(newbuf, kNewFileData) != 0) {
    74      warnx("final pread returned wrong data: %s", newbuf);
    75      failed = 1;
    76    }
    77  
    78    // Check that the memory mapping of the old FD has been updated. (Linux
    79    // overlayfs does not do this, so regardless of kernel version this requires
    80    // that runsc replace existing memory mappings with mappings of a
    81    // post-copy-up FD.)
    82    if (strcmp(page, kNewFileData) != 0) {
    83      warnx("mapping contains wrong final data: %s", (const char*)page);
    84      failed = 1;
    85    }
    86  
    87    return failed;
    88  }