static ssize_t NaClDescIoDescWrite(struct NaClDesc *vself, void const *buf, size_t len) { struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself; return NaClHostDescWrite(self->hd, buf, len); }
/* * Write out kNumFileBytes (a multiple of 64K) bytes of data. */ int CreateTestData(struct NaClHostDesc *d) { size_t nbytes; size_t written = 0; ssize_t result; static char buffer[4096]; memset(buffer, 0, sizeof buffer); while (written < kNumFileBytes) { nbytes = kNumFileBytes - written; if (nbytes > sizeof buffer) { nbytes = sizeof buffer; } result = NaClHostDescWrite(d, buffer, nbytes); if (result < 0) { return (int) result; } written += result; } return 0; }
int SeekPastEndAndWriteTest(struct NaClHostDesc *test_file, struct NaClHostDesc *ro_view, void const *test_params) { nacl_host_stat_t stbuf; nacl_off64_t new_size; ssize_t io_err; int err; nacl_off64_t seek_result; UNREFERENCED_PARAMETER(test_params); err = NaClHostDescFstat(test_file, &stbuf); if (0 != err) { fprintf(stderr, "SeekPastEndAndWriteTest: fstat failed\n"); return 0; } new_size = stbuf.st_size + (2 << 16); seek_result = NaClHostDescSeek(test_file, new_size, 0); if (seek_result != new_size) { fprintf(stderr, "SeekPastEndAndWriteTest: seek failed\n"); return 0; } io_err = NaClHostDescWrite(test_file, "1", 1); if (1 != io_err) { fprintf(stderr, "SeekPastEndAndWriteTest: write failed: %"NACL_PRIdS"\n", io_err); } err = NaClHostDescFstat(test_file, &stbuf); if (0 != err) { fprintf(stderr, "SeekPastEndAndWriteTest: post-write fstat failed\n"); return 0; } ASSERT_EQ(stbuf.st_size, new_size + 1); err = NaClHostDescFstat(ro_view, &stbuf); if (0 != err) { fprintf(stderr, "SeekPastEndAndWriteTest: post-write ro_view fstat failed\n"); return 0; } ASSERT_EQ(stbuf.st_size, new_size + 1); return 1; }
/* * Write to |d| |file_bytes| of data from |buffer|, which contains * |buffer_size| bytes. The contents of buffer will be repeated as * needed so that the target |file_bytes| is reached. */ int WriteData(struct NaClHostDesc *d, size_t file_bytes, char const *buffer, size_t buffer_size) { size_t nbytes; size_t written = 0; ssize_t result; while (written < file_bytes) { nbytes = file_bytes - written; if (nbytes > buffer_size) { nbytes = buffer_size; } result = NaClHostDescWrite(d, buffer, nbytes); if (result < 0) { return (int) result; } written += result; } return 0; }
void CreateTestFile(struct NaClHostDesc *d_out, char const *pathname, struct TestParams *param) { struct NaClHostDesc hd; int err; nacl_off64_t off; size_t desired_write; ssize_t bytes_written; printf("pathname = %s, perms 0%o\n", pathname, param->file_perms); if (0 != (err = NaClHostDescOpen(&hd, pathname, NACL_ABI_O_WRONLY | NACL_ABI_O_CREAT | NACL_ABI_O_TRUNC, param->file_perms))) { fprintf(stderr, "Could not open test scratch file: NaCl errno %d\n", -err); exit(1); } if (0 != (err = CreateTestData(&hd))) { fprintf(stderr, "Could not write test data into test scratch file: NaCl errno %d\n", -err); exit(1); } if (NULL != param->test_data_start) { off = NaClHostDescSeek(&hd, 0, 0); if (off < 0) { fprintf(stderr, "Could not seek to create test data: NaCl errno %d\n", (int) -off); exit(1); } desired_write = param->test_data_size; bytes_written = NaClHostDescWrite(&hd, param->test_data_start, desired_write); if (bytes_written < 0) { fprintf(stderr, "Could not write specialized test data: NaCl errno %d\n", (int) -bytes_written); exit(1); } if ((size_t) bytes_written != desired_write) { fprintf(stderr, "Error while writing specialized test data:" " tried to write %d, actual %d\n", (int) desired_write, (int) bytes_written); exit(1); } } if (0 != (err = NaClHostDescClose(&hd))) { fprintf(stderr, "Error while closing test data file, errno %d\n", -err); exit(1); } if (0 != (err = NaClHostDescOpen(d_out, pathname, param->open_flags, param->file_perms))) { fprintf(stderr, "Could not open test scratch file: NaCl errno %d\n", -err); exit(1); } }
/* * mmap MAP_PRIVATE test * * Make sure that a MAP_PRIVATE view initially sees the changes made * in a MAP_SHARED view, but after touching the private view further * changes become invisible. */ int map_private_test(struct NaClHostDesc *d, void *test_specifics) { struct MapPrivateSpecifics *params = (struct MapPrivateSpecifics *) test_specifics; struct NaClDescEffector *null_eff = NaClDescEffectorTrustedMem(); uintptr_t view1; uintptr_t view2; nacl_off64_t off; ssize_t bytes_written; char *v1ptr; char *v2ptr; if ((uintptr_t) -4095 < (view1 = NaClHostDescMap(d, null_eff, NULL, kNumFileBytes, NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE, NACL_ABI_MAP_SHARED, /* offset */ 0))) { fprintf(stderr, "map_private_test: view1 map failed, errno %d\n", -(int) view1); return 1; } NaClLog(2, "map_private_test: view1 = 0x%"NACL_PRIxPTR"\n", view1); if ((uintptr_t) -4095 < (view2 = NaClHostDescMap(d, null_eff, NULL, kNumFileBytes, NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE, NACL_ABI_MAP_PRIVATE, /* offset */ 0))) { fprintf(stderr, "map_private_test: view2 map failed, errno %d\n", -(int) view2); return 1; } NaClLog(2, "map_private_test: view2 = 0x%"NACL_PRIxPTR"\n", view2); v1ptr = (char *) view1; v2ptr = (char *) view2; CHECK(v1ptr[0] == '\0'); CHECK(v2ptr[0] == '\0'); if (params->shm_not_write) { NaClLog(2, "map_private_test: changing via shm view\n"); v1ptr[0] = 'x'; /* write through shared view */ } else { NaClLog(2, "map_private_test: changing via write interface\n"); off = NaClHostDescSeek(d, 0, 0); if (off < 0) { fprintf(stderr, "Could not seek: NaCl errno %d\n", (int) -off); return 1; } bytes_written = NaClHostDescWrite(d, "x", 1); if (1 != bytes_written) { fprintf(stderr, "Could not write: NaCl errno %d\n", (int) -bytes_written); return 1; } } #if NACL_LINUX || NACL_WINDOWS /* * Most OSes have this behavior: a PRIVATE mapping is copy-on-write, * but the COW occurs when the fault occurs on that mapping, not * other mappings; otherwise, the page tables just point the system * to the buffer cache (or, if evicted, a stub entry that permits * faulting in the page). So, a write through a writable file * descriptor or a SHARED mapping would modify the buffer cache, and * the PRIVATE mapping would see such changes until a fault occurs. */ CHECK(v2ptr[0] == 'x'); /* visible! */ #elif NACL_OSX /* * On OSX, however, the underlying Mach primitives provide * bidirectional COW. */ CHECK(v2ptr[0] == '\0'); /* NOT visible! */ #else # error "Unsupported OS" #endif v2ptr[0] = 'z'; /* COW fault */ v1ptr[0] = 'y'; CHECK(v2ptr[0] == 'z'); /* private! */ CHECK(v1ptr[0x400] == '\0'); v2ptr[0x400] = 'y'; CHECK(v1ptr[0x400] == '\0'); CHECK(0 == NaClHostDescUnmapUnsafe((void *) view1, kNumFileBytes)); CHECK(0 == NaClHostDescUnmapUnsafe((void *) view2, kNumFileBytes)); return 0; }