make "echo hello > x" truncate file x.

This commit is contained in:
Robert Morris 2020-07-16 11:38:08 -04:00
parent c98e1afe79
commit f3979b7212
6 changed files with 148 additions and 8 deletions

View file

@ -52,6 +52,7 @@ struct inode* nameiparent(char*, char*);
int readi(struct inode*, int, uint64, uint, uint); int readi(struct inode*, int, uint64, uint, uint);
void stati(struct inode*, struct stat*); void stati(struct inode*, struct stat*);
int writei(struct inode*, int, uint64, uint, uint); int writei(struct inode*, int, uint64, uint, uint);
void itrunc(struct inode*);
// ramdisk.c // ramdisk.c
void ramdiskinit(void); void ramdiskinit(void);

View file

@ -2,3 +2,4 @@
#define O_WRONLY 0x001 #define O_WRONLY 0x001
#define O_RDWR 0x002 #define O_RDWR 0x002
#define O_CREATE 0x200 #define O_CREATE 0x200
#define O_TRUNC 0x400

View file

@ -22,7 +22,6 @@
#include "file.h" #include "file.h"
#define min(a, b) ((a) < (b) ? (a) : (b)) #define min(a, b) ((a) < (b) ? (a) : (b))
static void itrunc(struct inode*);
// there should be one superblock per disk device, but we run with // there should be one superblock per disk device, but we run with
// only one device // only one device
struct superblock sb; struct superblock sb;
@ -406,11 +405,8 @@ bmap(struct inode *ip, uint bn)
} }
// Truncate inode (discard contents). // Truncate inode (discard contents).
// Only called when the inode has no links // Caller must hold ip->lock.
// to it (no directory entries referring to it) void
// and has no in-memory reference to it (is
// not an open file or current directory).
static void
itrunc(struct inode *ip) itrunc(struct inode *ip)
{ {
int i, j; int i, j;
@ -463,7 +459,7 @@ readi(struct inode *ip, int user_dst, uint64 dst, uint off, uint n)
struct buf *bp; struct buf *bp;
if(off > ip->size || off + n < off) if(off > ip->size || off + n < off)
return -1; return 0;
if(off + n > ip->size) if(off + n > ip->size)
n = ip->size - off; n = ip->size - off;

View file

@ -341,6 +341,10 @@ sys_open(void)
f->readable = !(omode & O_WRONLY); f->readable = !(omode & O_WRONLY);
f->writable = (omode & O_WRONLY) || (omode & O_RDWR); f->writable = (omode & O_WRONLY) || (omode & O_RDWR);
if((omode & O_TRUNC) && ip->type == T_FILE){
itrunc(ip);
}
iunlock(ip); iunlock(ip);
end_op(); end_op();

View file

@ -386,7 +386,7 @@ parseredirs(struct cmd *cmd, char **ps, char *es)
cmd = redircmd(cmd, q, eq, O_RDONLY, 0); cmd = redircmd(cmd, q, eq, O_RDONLY, 0);
break; break;
case '>': case '>':
cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE, 1); cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE|O_TRUNC, 1);
break; break;
case '+': // >> case '+': // >>
cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE, 1); cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE, 1);

View file

@ -22,6 +22,141 @@
char buf[BUFSZ]; char buf[BUFSZ];
char name[3]; char name[3];
// test O_TRUNC.
void
truncate1(char *s)
{
char buf[32];
unlink("truncfile");
int fd1 = open("truncfile", O_CREATE|O_WRONLY|O_TRUNC);
write(fd1, "abcd", 4);
close(fd1);
int fd2 = open("truncfile", O_RDONLY);
int n = read(fd2, buf, sizeof(buf));
if(n != 4){
printf("%s: read %d bytes, wanted 4\n", s, n);
exit(1);
}
fd1 = open("truncfile", O_WRONLY|O_TRUNC);
int fd3 = open("truncfile", O_RDONLY);
n = read(fd3, buf, sizeof(buf));
if(n != 0){
printf("aaa fd3=%d\n", fd3);
printf("%s: read %d bytes, wanted 0\n", s, n);
exit(1);
}
n = read(fd2, buf, sizeof(buf));
if(n != 0){
printf("bbb fd2=%d\n", fd2);
printf("%s: read %d bytes, wanted 0\n", s, n);
exit(1);
}
write(fd1, "abcdef", 6);
n = read(fd3, buf, sizeof(buf));
if(n != 6){
printf("%s: read %d bytes, wanted 6\n", s, n);
exit(1);
}
n = read(fd2, buf, sizeof(buf));
if(n != 2){
printf("%s: read %d bytes, wanted 2\n", s, n);
exit(1);
}
unlink("truncfile");
close(fd1);
close(fd2);
close(fd3);
}
// write to an open FD whose file has just been truncated.
// this causes a write at an offset beyond the end of the file.
// such writes fail on xv6 (unlike POSIX) but at least
// they don't crash.
void
truncate2(char *s)
{
unlink("truncfile");
int fd1 = open("truncfile", O_CREATE|O_TRUNC|O_WRONLY);
write(fd1, "abcd", 4);
int fd2 = open("truncfile", O_TRUNC|O_WRONLY);
int n = write(fd1, "x", 1);
if(n != -1){
printf("%s: write returned %d, expected -1\n", s, n);
exit(1);
}
unlink("truncfile");
close(fd1);
close(fd2);
}
void
truncate3(char *s)
{
int pid, xstatus;
close(open("truncfile", O_CREATE|O_TRUNC|O_WRONLY));
pid = fork();
if(pid < 0){
printf("%s: fork failed\n", s);
exit(1);
}
if(pid == 0){
for(int i = 0; i < 100; i++){
char buf[32];
int fd = open("truncfile", O_WRONLY);
if(fd < 0){
printf("%s: open failed\n", s);
exit(1);
}
int n = write(fd, "1234567890", 10);
if(n != 10){
printf("%s: write got %d, expected 10\n", s, n);
exit(1);
}
close(fd);
fd = open("truncfile", O_RDONLY);
read(fd, buf, sizeof(buf));
close(fd);
}
exit(0);
}
for(int i = 0; i < 150; i++){
int fd = open("truncfile", O_CREATE|O_WRONLY|O_TRUNC);
if(fd < 0){
printf("%s: open failed\n", s);
exit(1);
}
int n = write(fd, "xxx", 3);
if(n != 3){
printf("%s: write got %d, expected 3\n", s, n);
exit(1);
}
close(fd);
}
wait(&xstatus);
unlink("truncfile");
exit(xstatus);
}
// does chdir() call iput(p->cwd) in a transaction? // does chdir() call iput(p->cwd) in a transaction?
void void
iputtest(char *s) iputtest(char *s)
@ -2169,6 +2304,9 @@ main(int argc, char *argv[])
void (*f)(char *); void (*f)(char *);
char *s; char *s;
} tests[] = { } tests[] = {
{truncate1, "truncate1"},
{truncate2, "truncate2"},
{truncate3, "truncate3"},
{reparent2, "reparent2"}, {reparent2, "reparent2"},
{pgbug, "pgbug" }, {pgbug, "pgbug" },
{sbrkbugs, "sbrkbugs" }, {sbrkbugs, "sbrkbugs" },