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 }