blob: 951cc531cd44559adab6b503e29e3adaccf191bf [file] [log] [blame]
/* 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