| /* Copyright (c) 2011 The Chromium OS Authors. All rights reserved. |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| #define _GNU_SOURCE |
| |
| #include <sys/stat.h> |
| #include <sys/types.h> |
| #include <sys/user.h> |
| #include <errno.h> |
| #include <fcntl.h> |
| #include <stdlib.h> |
| |
| #include <debug.h> |
| |
| #include "fcalls.h" |
| #include "main.h" |
| #include "util.h" |
| |
| /* ARM does not define PAGE_SIZE */ |
| #ifndef PAGE_SHIFT |
| #undef PAGE_SIZE |
| #define PAGE_SHIFT 12 |
| #define PAGE_SIZE (1UL << PAGE_SHIFT) |
| #endif |
| |
| void OpenTest (void) |
| { |
| int i; |
| void *b; |
| char buf[Local_option.block_size]; |
| char *name = RndName(); |
| CrFile(name, 1377); |
| |
| /* Open file twice */ |
| int fd1 = open(name, O_RDONLY, 0600); |
| int fd2 = open(name, O_RDONLY, 0600); |
| close(fd1); |
| close(fd2); |
| |
| /* Try to create and existing file */ |
| openErr(EEXIST, name, O_CREAT | O_EXCL | O_TRUNC | O_WRONLY, 0600); |
| |
| /* Append mode on file, !(O_APPEND -> O_WRONLY) */ |
| char msg1[] = "Now is the time"; |
| char msg2[] = " for things to happen."; |
| char msg3[] = " Well it happened"; |
| fd1 = open(name, O_TRUNC | O_APPEND | O_RDWR, 0); |
| fd2 = open(name, O_APPEND | O_RDWR, 0); |
| write(fd1, msg1, sizeof(msg1)); |
| write(fd2, msg2, sizeof(msg2)); |
| write(fd1, msg3, sizeof(msg3)); |
| pread(fd2, buf, sizeof(msg1), 0); |
| CheckEq(buf, msg1, sizeof(msg1)); |
| pread(fd1, buf, sizeof(msg2), sizeof(msg1)); |
| CheckEq(buf, msg2, sizeof(msg2)); |
| pread(fd2, buf, sizeof(msg3), sizeof(msg1) + sizeof(msg2)); |
| CheckEq(buf, msg3, sizeof(msg3)); |
| close(fd1); |
| close(fd2); |
| |
| /* Append mode requires write mode, but read mode works */ |
| fd1 = open(name, O_APPEND, 0); |
| read(fd1, buf, sizeof(msg1)); |
| CheckEq(buf, msg1, sizeof(msg1)); |
| writeErr(EBADF, fd1, msg1, sizeof(msg1)); |
| close(fd1); |
| |
| fd1 = open(name, O_RDONLY, 0); |
| read(fd1, buf, sizeof(msg1)); |
| CheckEq(buf, msg1, sizeof(msg1)); |
| writeErr(EBADF, fd1, msg1, sizeof(msg1)); |
| close(fd1); |
| |
| /* Check appended files after closing */ |
| fd1 = open(name, O_RDONLY, 0); |
| fd2 = open(name, O_RDONLY, 0); |
| pread(fd2, buf, sizeof(msg1), 0); |
| CheckEq(buf, msg1, sizeof(msg1)); |
| pread(fd1, buf, sizeof(msg2), sizeof(msg1)); |
| CheckEq(buf, msg2, sizeof(msg2)); |
| pread(fd2, buf, sizeof(msg3), sizeof(msg1) + sizeof(msg2)); |
| CheckEq(buf, msg3, sizeof(msg3)); |
| close(fd1); |
| close(fd2); |
| |
| /* O_DIRECT */ |
| int rc = posix_memalign(&b, PAGE_SIZE, PAGE_SIZE); |
| if (rc) PrError("posix_memalign:"); |
| #if __linux__ |
| if (Local_option.test_direct) { |
| fd1 = open(name, O_TRUNC | O_RDWR | O_DIRECT, 0); |
| for (i = 0; i < 4; i++) { |
| /* Fill buffer with data based on the offset in the file */ |
| Fill(b, PAGE_SIZE, i * PAGE_SIZE); |
| write(fd1, b, PAGE_SIZE); |
| } |
| lseek(fd1, 0, SEEK_SET); |
| for (i = 0; i < 4; i++) { |
| read(fd1, b, PAGE_SIZE); |
| CheckFill(b, PAGE_SIZE, i * PAGE_SIZE); |
| } |
| lseek(fd1, 0, SEEK_SET); |
| writeErr(EINVAL, fd1, ((char *)b + 1), PAGE_SIZE); |
| writeErr(EINVAL, fd1, b, PAGE_SIZE - 1); |
| readErr(EINVAL, fd1, ((char *)b + 1), PAGE_SIZE); |
| readErr(EINVAL, fd1, b, PAGE_SIZE - 1); |
| close(fd1); |
| |
| /* O_DIRECT, backward seeks */ |
| fd1 = open(name, O_TRUNC | O_RDWR | O_DIRECT, 0); |
| for (i = 3; i >= 0; i--) { |
| Fill(b, PAGE_SIZE, i * PAGE_SIZE); |
| pwrite(fd1, b, PAGE_SIZE, i * PAGE_SIZE); |
| } |
| lseek(fd1, 0, SEEK_SET); |
| for (i = 3; i >= 0; i--) { |
| pread(fd1, b, PAGE_SIZE, i * PAGE_SIZE); |
| CheckFill(b, PAGE_SIZE, i * PAGE_SIZE); |
| } |
| close(fd1); |
| } |
| #endif |
| |
| /* O_SYNC */ |
| fd1 = open(name, O_TRUNC | O_RDWR | O_SYNC, 0); |
| for (i = 0; i < 4; i++) { |
| Fill(b, PAGE_SIZE, i * PAGE_SIZE); |
| write(fd1, b, PAGE_SIZE); |
| } |
| lseek(fd1, 0, SEEK_SET); |
| for (i = 0; i < 4; i++) { |
| read(fd1, b, PAGE_SIZE); |
| CheckFill(b, PAGE_SIZE, i * PAGE_SIZE); |
| } |
| close(fd1); |
| |
| #if __APPLE__ |
| /* O_SHLOCK file locking */ |
| fd1 = open(name, O_RDWR | O_SHLOCK, 0); |
| fd2 = open(name, O_RDWR | O_SHLOCK, 0); |
| openErr(EWOULDBLOCK, name, O_RDWR | O_NONBLOCK | O_EXLOCK, 0); |
| close(fd1); |
| close(fd2); |
| |
| /* O_EXLOCK */ |
| fd1 = open(name, O_RDWR | O_EXLOCK, 0); |
| openErr(EWOULDBLOCK, name, O_RDWR | O_NONBLOCK | O_SHLOCK, 0); |
| close(fd1); |
| #endif |
| |
| free(b); |
| unlink(name); |
| free(name); |
| } |
| |
| #if __linux__ |
| /* OpenatTest does all the same tests as OpenTest but uses openat */ |
| void OpenatTest (void) |
| { |
| int i; |
| void *b; |
| char buf[Local_option.block_size]; |
| char *dirname = RndName(); |
| char *name = RndName(); |
| mkdir(dirname, 0700); |
| chdir(dirname); |
| CrFile(name, 1377); |
| chdir(".."); |
| int dirfd = open(dirname, O_RDONLY, 0); |
| |
| /* Open file twice */ |
| int fd1 = openat(dirfd, name, O_RDONLY, 0600); |
| int fd2 = openat(dirfd, name, O_RDONLY, 0600); |
| close(fd1); |
| close(fd2); |
| |
| /* Try to create and existing file */ |
| openatErr(EEXIST, dirfd, name, O_CREAT | O_EXCL | O_TRUNC | O_WRONLY, 0600); |
| |
| /* Append mode on file, !(O_APPEND -> O_WRONLY) */ |
| char msg1[] = "Now is the time"; |
| char msg2[] = " for things to happen."; |
| char msg3[] = " Well it happened"; |
| fd1 = openat(dirfd, name, O_TRUNC | O_APPEND | O_RDWR, 0); |
| fd2 = openat(dirfd, name, O_APPEND | O_RDWR, 0); |
| write(fd1, msg1, sizeof(msg1)); |
| write(fd2, msg2, sizeof(msg2)); |
| write(fd1, msg3, sizeof(msg3)); |
| pread(fd2, buf, sizeof(msg1), 0); |
| CheckEq(buf, msg1, sizeof(msg1)); |
| pread(fd1, buf, sizeof(msg2), sizeof(msg1)); |
| CheckEq(buf, msg2, sizeof(msg2)); |
| pread(fd2, buf, sizeof(msg3), sizeof(msg1) + sizeof(msg2)); |
| CheckEq(buf, msg3, sizeof(msg3)); |
| close(fd1); |
| close(fd2); |
| |
| /* Append mode requires write mode, but read mode works */ |
| fd1 = openat(dirfd, name, O_APPEND, 0); |
| read(fd1, buf, sizeof(msg1)); |
| CheckEq(buf, msg1, sizeof(msg1)); |
| writeErr(EBADF, fd1, msg1, sizeof(msg1)); |
| close(fd1); |
| |
| /* No mode allows read but not writes, because 0 is O_RDONLY */ |
| fd1 = openat(dirfd, name, 0, 0); |
| read(fd1, buf, sizeof(msg1)); |
| CheckEq(buf, msg1, sizeof(msg1)); |
| writeErr(EBADF, fd1, msg1, sizeof(msg1)); |
| close(fd1); |
| |
| /* Check appended files after closing */ |
| fd1 = openat(dirfd, name, O_RDONLY, 0); |
| fd2 = openat(dirfd, name, O_RDONLY, 0); |
| pread(fd2, buf, sizeof(msg1), 0); |
| CheckEq(buf, msg1, sizeof(msg1)); |
| pread(fd1, buf, sizeof(msg2), sizeof(msg1)); |
| CheckEq(buf, msg2, sizeof(msg2)); |
| pread(fd2, buf, sizeof(msg3), sizeof(msg1) + sizeof(msg2)); |
| CheckEq(buf, msg3, sizeof(msg3)); |
| close(fd1); |
| close(fd2); |
| |
| /* O_DIRECT */ |
| int rc = posix_memalign(&b, PAGE_SIZE, PAGE_SIZE); |
| if (rc) PrError("posix_memalign:"); |
| #if __linux__ |
| fd1 = openat(dirfd, name, O_TRUNC | O_RDWR | O_DIRECT, 0); |
| for (i = 0; i < 4; i++) { |
| Fill(b, PAGE_SIZE, i * PAGE_SIZE); |
| write(fd1, b, PAGE_SIZE); |
| } |
| lseek(fd1, 0, SEEK_SET); |
| for (i = 0; i < 4; i++) { |
| read(fd1, b, PAGE_SIZE); |
| CheckFill(b, PAGE_SIZE, i * PAGE_SIZE); |
| } |
| lseek(fd1, 0, SEEK_SET); |
| writeErr(EINVAL, fd1, ((char *)b + 1), PAGE_SIZE); |
| writeErr(EINVAL, fd1, b, PAGE_SIZE - 1); |
| readErr(EINVAL, fd1, ((char *)b + 1), PAGE_SIZE); |
| readErr(EINVAL, fd1, b, PAGE_SIZE - 1); |
| close(fd1); |
| |
| /* O_DIRECT, backward seeks */ |
| fd1 = openat(dirfd, name, O_TRUNC | O_RDWR | O_DIRECT, 0); |
| for (i = 3; i >= 0; i--) { |
| Fill(b, PAGE_SIZE, i * PAGE_SIZE); |
| pwrite(fd1, b, PAGE_SIZE, i * PAGE_SIZE); |
| } |
| lseek(fd1, 0, SEEK_SET); |
| for (i = 3; i >= 0; i--) { |
| pread(fd1, b, PAGE_SIZE, i * PAGE_SIZE); |
| CheckFill(b, PAGE_SIZE, i * PAGE_SIZE); |
| } |
| close(fd1); |
| #endif |
| |
| /* O_SYNC */ |
| fd1 = openat(dirfd, name, O_TRUNC | O_RDWR | O_SYNC, 0); |
| for (i = 0; i < 4; i++) { |
| Fill(b, PAGE_SIZE, i * PAGE_SIZE); |
| write(fd1, b, PAGE_SIZE); |
| } |
| lseek(fd1, 0, SEEK_SET); |
| for (i = 0; i < 4; i++) { |
| read(fd1, b, PAGE_SIZE); |
| CheckFill(b, PAGE_SIZE, i * PAGE_SIZE); |
| } |
| close(fd1); |
| |
| free(b); |
| chdir(dirname); |
| unlink(name); |
| chdir(".."); |
| rmdir(dirname); |
| free(name); |
| free(dirname); |
| } |
| #endif |