diff options
| -rw-r--r-- | kernel/defs.h | 1 | ||||
| -rw-r--r-- | kernel/fcntl.h | 1 | ||||
| -rw-r--r-- | kernel/fs.c | 10 | ||||
| -rw-r--r-- | kernel/sysfile.c | 4 | ||||
| -rw-r--r-- | user/sh.c | 2 | ||||
| -rw-r--r-- | user/usertests.c | 138 | 
6 files changed, 148 insertions, 8 deletions
| diff --git a/kernel/defs.h b/kernel/defs.h index 9c5f643..f33f1f6 100644 --- a/kernel/defs.h +++ b/kernel/defs.h @@ -52,6 +52,7 @@ struct inode*   nameiparent(char*, char*);  int             readi(struct inode*, int, uint64, uint, uint);  void            stati(struct inode*, struct stat*);  int             writei(struct inode*, int, uint64, uint, uint); +void            itrunc(struct inode*);  // ramdisk.c  void            ramdiskinit(void); diff --git a/kernel/fcntl.h b/kernel/fcntl.h index d565483..44861b9 100644 --- a/kernel/fcntl.h +++ b/kernel/fcntl.h @@ -2,3 +2,4 @@  #define O_WRONLY  0x001  #define O_RDWR    0x002  #define O_CREATE  0x200 +#define O_TRUNC   0x400 diff --git a/kernel/fs.c b/kernel/fs.c index 53586d5..e33ec30 100644 --- a/kernel/fs.c +++ b/kernel/fs.c @@ -22,7 +22,6 @@  #include "file.h"  #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  // only one device  struct superblock sb;  @@ -406,11 +405,8 @@ bmap(struct inode *ip, uint bn)  }  // Truncate inode (discard contents). -// Only called when the inode has no links -// to it (no directory entries referring to it) -// and has no in-memory reference to it (is -// not an open file or current directory). -static void +// Caller must hold ip->lock. +void  itrunc(struct inode *ip)  {    int i, j; @@ -463,7 +459,7 @@ readi(struct inode *ip, int user_dst, uint64 dst, uint off, uint n)    struct buf *bp;    if(off > ip->size || off + n < off) -    return -1; +    return 0;    if(off + n > ip->size)      n = ip->size - off; diff --git a/kernel/sysfile.c b/kernel/sysfile.c index 7768d20..015c942 100644 --- a/kernel/sysfile.c +++ b/kernel/sysfile.c @@ -341,6 +341,10 @@ sys_open(void)    f->readable = !(omode & O_WRONLY);    f->writable = (omode & O_WRONLY) || (omode & O_RDWR); +  if((omode & O_TRUNC) && ip->type == T_FILE){ +    itrunc(ip); +  } +    iunlock(ip);    end_op(); @@ -386,7 +386,7 @@ parseredirs(struct cmd *cmd, char **ps, char *es)        cmd = redircmd(cmd, q, eq, O_RDONLY, 0);        break;      case '>': -      cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE, 1); +      cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE|O_TRUNC, 1);        break;      case '+':  // >>        cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE, 1); diff --git a/user/usertests.c b/user/usertests.c index 9aa0ed4..f83a060 100644 --- a/user/usertests.c +++ b/user/usertests.c @@ -22,6 +22,141 @@  char buf[BUFSZ];  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?  void  iputtest(char *s) @@ -2169,6 +2304,9 @@ main(int argc, char *argv[])      void (*f)(char *);      char *s;    } tests[] = { +    {truncate1, "truncate1"}, +    {truncate2, "truncate2"}, +    {truncate3, "truncate3"},      {reparent2, "reparent2"},      {pgbug, "pgbug" },      {sbrkbugs, "sbrkbugs" }, | 
