make "echo hello > x" truncate file x.
This commit is contained in:
parent
c98e1afe79
commit
f3979b7212
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
10
kernel/fs.c
10
kernel/fs.c
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
138
user/usertests.c
138
user/usertests.c
|
@ -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" },
|
||||||
|
|
Loading…
Reference in a new issue