Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4368fbf44c | ||
|
|
f187a07854 | ||
|
|
888b75593b | ||
|
|
c084dbbffb | ||
|
|
4b46c0c6eb | ||
|
|
463ae0abc3 | ||
|
|
f5b93ef12f |
8
Makefile
8
Makefile
@ -106,7 +106,7 @@ endif
|
||||
|
||||
ifdef KCSAN
|
||||
CFLAGS += -DKCSAN
|
||||
KCSANFLAG = -fsanitize=thread
|
||||
KCSANFLAG = -fsanitize=thread -fno-inline
|
||||
endif
|
||||
|
||||
# Disable PIE when possible (for Ubuntu 16.10 toolchain)
|
||||
@ -188,11 +188,7 @@ UPROGS=\
|
||||
$U/_grind\
|
||||
$U/_wc\
|
||||
$U/_zombie\
|
||||
$U/_sleep\
|
||||
$U/_pingpong\
|
||||
$U/_primes\
|
||||
$U/_find\
|
||||
$U/_xargs\
|
||||
$U/_symlinktest\
|
||||
|
||||
|
||||
|
||||
|
||||
36
README
36
README
@ -6,7 +6,7 @@ ACKNOWLEDGMENTS
|
||||
|
||||
xv6 is inspired by John Lions's Commentary on UNIX 6th Edition (Peer
|
||||
to Peer Communications; ISBN: 1-57398-013-7; 1st edition (June 14,
|
||||
2000)). See also https://pdos.csail.mit.edu/6.828/, which provides
|
||||
2000)). See also https://pdos.csail.mit.edu/6.1810/, which provides
|
||||
pointers to on-line resources for v6.
|
||||
|
||||
The following people have made contributions: Russ Cox (context switching,
|
||||
@ -14,29 +14,31 @@ locking), Cliff Frey (MP), Xiao Yu (MP), Nickolai Zeldovich, and Austin
|
||||
Clements.
|
||||
|
||||
We are also grateful for the bug reports and patches contributed by
|
||||
Takahiro Aoyagi, Silas Boyd-Wickizer, Anton Burtsev, Ian Chen, Dan
|
||||
Cross, Cody Cutler, Mike CAT, Tej Chajed, Asami Doi, eyalz800, Nelson
|
||||
Elhage, Saar Ettinger, Alice Ferrazzi, Nathaniel Filardo, flespark,
|
||||
Peter Froehlich, Yakir Goaron, Shivam Handa, Matt Harvey, Bryan Henry,
|
||||
jaichenhengjie, Jim Huang, Matúš Jókay, Alexander Kapshuk, Anders
|
||||
Kaseorg, kehao95, Wolfgang Keller, Jungwoo Kim, Jonathan Kimmitt,
|
||||
Eddie Kohler, Vadim Kolontsov, Austin Liew, l0stman, Pavan
|
||||
Maddamsetti, Imbar Marinescu, Yandong Mao, Matan Shabtay, Hitoshi
|
||||
Mitake, Carmi Merimovich, Mark Morrissey, mtasm, Joel Nider,
|
||||
OptimisticSide, Greg Price, Jude Rich, Ayan Shafqat, Eldar Sehayek,
|
||||
Yongming Shen, Fumiya Shigemitsu, Cam Tenny, tyfkda, Warren Toomey,
|
||||
Stephen Tu, Rafael Ubal, Amane Uehara, Pablo Ventura, Xi Wang, Keiichi
|
||||
Watanabe, Nicolas Wolovick, wxdao, Grant Wu, Jindong Zhang, Icenowy
|
||||
Zheng, ZhUyU1997, and Zou Chang Wei.
|
||||
Takahiro Aoyagi, Silas Boyd-Wickizer, Anton Burtsev, carlclone, Ian
|
||||
Chen, Dan Cross, Cody Cutler, Mike CAT, Tej Chajed, Asami Doi,
|
||||
eyalz800, Nelson Elhage, Saar Ettinger, Alice Ferrazzi, Nathaniel
|
||||
Filardo, flespark, Peter Froehlich, Yakir Goaron, Shivam Handa, Matt
|
||||
Harvey, Bryan Henry, jaichenhengjie, Jim Huang, Matúš Jókay, John
|
||||
Jolly, Alexander Kapshuk, Anders Kaseorg, kehao95, Wolfgang Keller,
|
||||
Jungwoo Kim, Jonathan Kimmitt, Eddie Kohler, Vadim Kolontsov, Austin
|
||||
Liew, l0stman, Pavan Maddamsetti, Imbar Marinescu, Yandong Mao, Matan
|
||||
Shabtay, Hitoshi Mitake, Carmi Merimovich, Mark Morrissey, mtasm, Joel
|
||||
Nider, Hayato Ohhashi, OptimisticSide, Harry Porter, Greg Price, Jude
|
||||
Rich, segfault, Ayan Shafqat, Eldar Sehayek, Yongming Shen, Fumiya
|
||||
Shigemitsu, Cam Tenny, tyfkda, Warren Toomey, Stephen Tu, Rafael Ubal,
|
||||
Amane Uehara, Pablo Ventura, Xi Wang, WaheedHafez, Keiichi Watanabe,
|
||||
Nicolas Wolovick, wxdao, Grant Wu, Jindong Zhang, Icenowy Zheng,
|
||||
ZhUyU1997, and Zou Chang Wei.
|
||||
|
||||
|
||||
The code in the files that constitute xv6 is
|
||||
Copyright 2006-2020 Frans Kaashoek, Robert Morris, and Russ Cox.
|
||||
Copyright 2006-2022 Frans Kaashoek, Robert Morris, and Russ Cox.
|
||||
|
||||
ERROR REPORTS
|
||||
|
||||
Please send errors and suggestions to Frans Kaashoek and Robert Morris
|
||||
(kaashoek,rtm@mit.edu). The main purpose of xv6 is as a teaching
|
||||
operating system for MIT's 6.S081, so we are more interested in
|
||||
operating system for MIT's 6.1810, so we are more interested in
|
||||
simplifications and clarifications than new features.
|
||||
|
||||
BUILDING AND RUNNING XV6
|
||||
|
||||
@ -1 +1 @@
|
||||
LAB=util
|
||||
LAB=fs
|
||||
|
||||
41
grade-lab-fs
Executable file
41
grade-lab-fs
Executable file
@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import re
|
||||
from gradelib import *
|
||||
|
||||
r = Runner(save("xv6.out"))
|
||||
|
||||
@test(40, "running bigfile")
|
||||
def test_bigfile():
|
||||
r.run_qemu(shell_script([
|
||||
'bigfile'
|
||||
]), timeout=400)
|
||||
r.match('^wrote 65803 blocks$')
|
||||
r.match('^bigfile done; ok$')
|
||||
|
||||
@test(0, "running symlinktest")
|
||||
def test_symlinktest():
|
||||
r.run_qemu(shell_script([
|
||||
'symlinktest'
|
||||
]), timeout=20)
|
||||
|
||||
@test(20, "symlinktest: symlinks", parent=test_symlinktest)
|
||||
def test_symlinktest_symlinks():
|
||||
r.match("^test symlinks: ok$")
|
||||
|
||||
@test(20, "symlinktest: concurrent symlinks", parent=test_symlinktest)
|
||||
def test_symlinktest_symlinks():
|
||||
r.match("^test concurrent symlinks: ok$")
|
||||
|
||||
@test(19, "usertests")
|
||||
def test_usertests():
|
||||
r.run_qemu(shell_script([
|
||||
'usertests -q'
|
||||
]), timeout=600)
|
||||
r.match('^ALL TESTS PASSED$')
|
||||
|
||||
@test(1, "time")
|
||||
def test_time():
|
||||
check_time()
|
||||
|
||||
run_tests()
|
||||
@ -1,86 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import re
|
||||
from gradelib import *
|
||||
|
||||
r = Runner(save("xv6.out"))
|
||||
|
||||
@test(5, "sleep, no arguments")
|
||||
def test_sleep_no_args():
|
||||
r.run_qemu(shell_script([
|
||||
'sleep'
|
||||
]))
|
||||
r.match(no=["exec .* failed", "$ sleep\n$"])
|
||||
|
||||
@test(5, "sleep, returns")
|
||||
def test_sleep_no_args():
|
||||
r.run_qemu(shell_script([
|
||||
'sleep',
|
||||
'echo OK'
|
||||
]))
|
||||
r.match('^OK$', no=["exec .* failed", "$ sleep\n$"])
|
||||
|
||||
@test(10, "sleep, makes syscall")
|
||||
def test_sleep():
|
||||
r.run_qemu(shell_script([
|
||||
'sleep 10',
|
||||
'echo FAIL'
|
||||
]), stop_breakpoint('sys_sleep'))
|
||||
r.match('\\$ sleep 10', no=['FAIL'])
|
||||
|
||||
@test(20, "pingpong")
|
||||
def test_pingpong():
|
||||
r.run_qemu(shell_script([
|
||||
'pingpong', 'echo OK'
|
||||
]))
|
||||
r.match('^\\d+: received ping$', '^\\d+: received pong$', '^OK$')
|
||||
|
||||
@test(20, "primes")
|
||||
def test_primes():
|
||||
r.run_qemu(shell_script([
|
||||
'primes', 'echo OK'
|
||||
]))
|
||||
args = ['prime %d' % i for i in [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31]]
|
||||
args.append('^OK$')
|
||||
r.match(*args)
|
||||
|
||||
@test(10, "find, in current directory")
|
||||
def test_find_curdir():
|
||||
fn = random_str()
|
||||
r.run_qemu(shell_script([
|
||||
'echo > %s' % fn,
|
||||
'find . %s' % fn
|
||||
]))
|
||||
r.match('./%s' % fn)
|
||||
|
||||
@test(10, "find, recursive")
|
||||
def test_find_recursive():
|
||||
needle = random_str()
|
||||
dirs = [random_str() for _ in range(3)]
|
||||
r.run_qemu(shell_script([
|
||||
'mkdir %s' % dirs[0],
|
||||
'echo > %s/%s' % (dirs[0], needle),
|
||||
'mkdir %s/%s' % (dirs[0], dirs[1]),
|
||||
'echo > %s/%s/%s' % (dirs[0], dirs[1], needle),
|
||||
'mkdir %s' % dirs[2],
|
||||
'echo > %s/%s' % (dirs[2], needle),
|
||||
'find . %s' % needle
|
||||
]))
|
||||
r.match('./%s/%s' % (dirs[0], needle),
|
||||
'./%s/%s/%s' % (dirs[0], dirs[1], needle),
|
||||
'./%s/%s' % (dirs[2], needle))
|
||||
|
||||
@test(19, "xargs")
|
||||
def test_xargs():
|
||||
r.run_qemu(shell_script([
|
||||
'sh < xargstest.sh',
|
||||
'echo DONE',
|
||||
], 'DONE'))
|
||||
matches = re.findall("hello", r.qemu.output)
|
||||
assert_equal(len(matches), 3, "Number of appearances of 'hello'")
|
||||
|
||||
@test(1, "time")
|
||||
def test_time():
|
||||
check_time()
|
||||
|
||||
run_tests()
|
||||
@ -3,3 +3,4 @@
|
||||
#define O_RDWR 0x002
|
||||
#define O_CREATE 0x200
|
||||
#define O_TRUNC 0x400
|
||||
#define O_NOFOLLOW 0x800
|
||||
@ -26,7 +26,7 @@ struct inode {
|
||||
short minor;
|
||||
short nlink;
|
||||
uint size;
|
||||
uint addrs[NDIRECT+1];
|
||||
uint addrs[NDIRECT+2];
|
||||
};
|
||||
|
||||
// map major device number to device functions.
|
||||
|
||||
64
kernel/fs.c
64
kernel/fs.c
@ -416,7 +416,43 @@ bmap(struct inode *ip, uint bn)
|
||||
brelse(bp);
|
||||
return addr;
|
||||
}
|
||||
|
||||
bn -= NINDIRECT;
|
||||
if (bn < NINDIRECT2) {
|
||||
// Load doubly indirect block L1
|
||||
if ((addr = ip->addrs[NDIRECT+1]) == 0){
|
||||
addr = balloc(ip->dev);
|
||||
if(addr == 0)
|
||||
return 0;
|
||||
ip->addrs[NDIRECT+1] = addr;
|
||||
}
|
||||
// load doubly indirect block L2
|
||||
// we have NINDIRECT blocks for per L1 entry
|
||||
bp = bread(ip->dev, addr);
|
||||
a = (uint*)bp->data;
|
||||
if ((addr = a[bn / NINDIRECT]) == 0) {
|
||||
addr = balloc(ip->dev);
|
||||
if (addr == 0) {
|
||||
brelse(bp);
|
||||
return 0;
|
||||
}
|
||||
a[bn / NINDIRECT] = addr;
|
||||
log_write(bp);
|
||||
}
|
||||
brelse(bp);
|
||||
// Load finally the target block
|
||||
bp = bread(ip->dev, addr);
|
||||
a = (uint*)bp->data;
|
||||
if ((addr = a[bn % NINDIRECT]) == 0) {
|
||||
addr = balloc(ip->dev);
|
||||
if (addr) {
|
||||
a[bn % NINDIRECT] = addr;
|
||||
log_write(bp);
|
||||
}
|
||||
}
|
||||
brelse(bp);
|
||||
return addr;
|
||||
}
|
||||
printf("bn=%d\n", bn);
|
||||
panic("bmap: out of range");
|
||||
}
|
||||
|
||||
@ -425,9 +461,9 @@ bmap(struct inode *ip, uint bn)
|
||||
void
|
||||
itrunc(struct inode *ip)
|
||||
{
|
||||
int i, j;
|
||||
struct buf *bp;
|
||||
uint *a;
|
||||
int i, j, k;
|
||||
struct buf *bp, *bp1;
|
||||
uint *a, *a1;
|
||||
|
||||
for(i = 0; i < NDIRECT; i++){
|
||||
if(ip->addrs[i]){
|
||||
@ -448,6 +484,26 @@ itrunc(struct inode *ip)
|
||||
ip->addrs[NDIRECT] = 0;
|
||||
}
|
||||
|
||||
if (ip->addrs[NDIRECT+1]) {
|
||||
bp = bread(ip->dev, ip->addrs[NDIRECT+1]);
|
||||
a = (uint*)bp->data;
|
||||
for(j = 0; j < NINDIRECT; j++){
|
||||
if(a[j]) {
|
||||
bp1 = bread(ip->dev, a[j]);
|
||||
a1 = (uint*)bp1->data;
|
||||
for (k = 0; k < NINDIRECT; ++ k) {
|
||||
if (a1[k]) {
|
||||
bfree(ip->dev, a1[k]);
|
||||
}
|
||||
}
|
||||
brelse(bp1);
|
||||
bfree(ip->dev, a[j]);
|
||||
}
|
||||
}
|
||||
brelse(bp);
|
||||
bfree(ip->dev, ip->addrs[NDIRECT+1]);
|
||||
ip->addrs[NDIRECT+1] = 0;
|
||||
}
|
||||
ip->size = 0;
|
||||
iupdate(ip);
|
||||
}
|
||||
|
||||
@ -24,9 +24,10 @@ struct superblock {
|
||||
|
||||
#define FSMAGIC 0x10203040
|
||||
|
||||
#define NDIRECT 12
|
||||
#define NDIRECT 11
|
||||
#define NINDIRECT (BSIZE / sizeof(uint))
|
||||
#define MAXFILE (NDIRECT + NINDIRECT)
|
||||
#define NINDIRECT2 (NINDIRECT * NINDIRECT)
|
||||
#define MAXFILE (NDIRECT + NINDIRECT + NINDIRECT2)
|
||||
|
||||
// On-disk inode structure
|
||||
struct dinode {
|
||||
@ -35,7 +36,7 @@ struct dinode {
|
||||
short minor; // Minor device number (T_DEVICE only)
|
||||
short nlink; // Number of links to inode in file system
|
||||
uint size; // Size of file (bytes)
|
||||
uint addrs[NDIRECT+1]; // Data block addresses
|
||||
uint addrs[NDIRECT+2]; // Data block addresses
|
||||
};
|
||||
|
||||
// Inodes per block.
|
||||
|
||||
@ -1,4 +1,8 @@
|
||||
#define NPROC 64 // maximum number of processes
|
||||
#ifdef LAB_FS
|
||||
#define NPROC 10 // maximum number of processes
|
||||
#else
|
||||
#define NPROC 64 // maximum number of processes (speedsup bigfile)
|
||||
#endif
|
||||
#define NCPU 8 // maximum number of CPUs
|
||||
#define NOFILE 16 // open files per process
|
||||
#define NFILE 100 // open files per system
|
||||
@ -9,5 +13,15 @@
|
||||
#define MAXOPBLOCKS 10 // max # of blocks any FS op writes
|
||||
#define LOGSIZE (MAXOPBLOCKS*3) // max data blocks in on-disk log
|
||||
#define NBUF (MAXOPBLOCKS*3) // size of disk block cache
|
||||
#define FSSIZE 2000 // size of file system in blocks
|
||||
#ifdef LAB_FS
|
||||
#define FSSIZE 200000 // size of file system in blocks
|
||||
#else
|
||||
#ifdef LAB_LOCK
|
||||
#define FSSIZE 10000 // size of file system in blocks
|
||||
#else
|
||||
#define FSSIZE 2000 // size of file system in blocks
|
||||
#endif
|
||||
#endif
|
||||
#define MAXPATH 128 // maximum file path name
|
||||
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#define T_DIR 1 // Directory
|
||||
#define T_FILE 2 // File
|
||||
#define T_DEVICE 3 // Device
|
||||
|
||||
#define T_SYMLINK 4
|
||||
struct stat {
|
||||
int dev; // File system's disk device
|
||||
uint ino; // Inode number
|
||||
|
||||
@ -101,6 +101,7 @@ extern uint64 sys_unlink(void);
|
||||
extern uint64 sys_link(void);
|
||||
extern uint64 sys_mkdir(void);
|
||||
extern uint64 sys_close(void);
|
||||
extern uint64 sys_symlink(void);
|
||||
|
||||
// An array mapping syscall numbers from syscall.h
|
||||
// to the function that handles the system call.
|
||||
@ -126,6 +127,7 @@ static uint64 (*syscalls[])(void) = {
|
||||
[SYS_link] sys_link,
|
||||
[SYS_mkdir] sys_mkdir,
|
||||
[SYS_close] sys_close,
|
||||
[SYS_symlink] sys_symlink,
|
||||
};
|
||||
|
||||
void
|
||||
|
||||
@ -20,3 +20,4 @@
|
||||
#define SYS_link 19
|
||||
#define SYS_mkdir 20
|
||||
#define SYS_close 21
|
||||
#define SYS_symlink 22
|
||||
@ -335,6 +335,36 @@ sys_open(void)
|
||||
}
|
||||
}
|
||||
|
||||
if (ip->type == T_SYMLINK && !(omode & O_NOFOLLOW)) {
|
||||
int symlink_step = 0;
|
||||
while (ip->type == T_SYMLINK) {
|
||||
if (symlink_step++ > 10) {
|
||||
// printf("\x1b[031mFailed\x1b[0m due to deep symlink\n");
|
||||
iunlockput(ip); // on error, put inode 'cause only success open need to use the file after the syscall
|
||||
end_op();
|
||||
return -1;
|
||||
}
|
||||
int len_target = readi(ip, 0, (uint64)path, 0, MAXPATH);
|
||||
iunlockput(ip); // no more need to use this inode
|
||||
if (len_target == 0) {
|
||||
printf("\x1b[031mFailed\x1b[0m to read symlink %s\n", path);
|
||||
end_op();
|
||||
return -1;
|
||||
}
|
||||
// get target's inode
|
||||
if((ip = namei(path)) == 0){
|
||||
// printf("\x1b[031mFailed\x1b[0m open symlink target %s\n", path);
|
||||
end_op();
|
||||
return -1;
|
||||
}
|
||||
ilock(ip);
|
||||
if(ip->type == T_DIR && omode != O_RDONLY){
|
||||
iunlockput(ip);
|
||||
end_op();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(ip->type == T_DEVICE && (ip->major < 0 || ip->major >= NDEV)){
|
||||
iunlockput(ip);
|
||||
end_op();
|
||||
@ -503,3 +533,32 @@ sys_pipe(void)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64
|
||||
sys_symlink(void)
|
||||
{
|
||||
char target[MAXPATH], path[MAXPATH];
|
||||
int len_target, len_path;
|
||||
struct inode* ip;
|
||||
if ((len_target = argstr(0, target, MAXPATH)) < 0)
|
||||
return -1;
|
||||
if ((len_path = argstr(1, path, MAXPATH)) < 0)
|
||||
return -1;
|
||||
// printf("\x1b[033msys_symlink\x1b[0m %s -> %s\n", path, target);
|
||||
begin_op();
|
||||
ip = create(path, T_SYMLINK, 0, 0);
|
||||
if (ip == 0) {
|
||||
end_op();
|
||||
// printf("\x1b[031mFailed\x1b[0m to create path %s\n", path);
|
||||
return -1;
|
||||
}
|
||||
if (writei(ip, 0, (uint64)target, 0, len_target) != len_target) {
|
||||
iunlockput(ip);
|
||||
end_op();
|
||||
printf("\x1b[031mFailed\x1b[0m to write symlink target %s to %s\n", target, path);
|
||||
return -1;
|
||||
}
|
||||
iunlockput(ip); // no need to keep this inode ref, if not put, in-RAM inode pool will run out
|
||||
end_op();
|
||||
return 0;
|
||||
}
|
||||
@ -55,6 +55,8 @@ sys_sleep(void)
|
||||
uint ticks0;
|
||||
|
||||
argint(0, &n);
|
||||
if(n < 0)
|
||||
n = 0;
|
||||
acquire(&tickslock);
|
||||
ticks0 = ticks;
|
||||
while(ticks - ticks0 < n){
|
||||
|
||||
57
user/bigfile.c
Normal file
57
user/bigfile.c
Normal file
@ -0,0 +1,57 @@
|
||||
#include "kernel/types.h"
|
||||
#include "kernel/stat.h"
|
||||
#include "user/user.h"
|
||||
#include "kernel/fcntl.h"
|
||||
#include "kernel/fs.h"
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
char buf[BSIZE];
|
||||
int fd, i, blocks;
|
||||
|
||||
fd = open("big.file", O_CREATE | O_WRONLY);
|
||||
if(fd < 0){
|
||||
printf("bigfile: cannot open big.file for writing\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
blocks = 0;
|
||||
while(1){
|
||||
*(int*)buf = blocks;
|
||||
int cc = write(fd, buf, sizeof(buf));
|
||||
if(cc <= 0)
|
||||
break;
|
||||
blocks++;
|
||||
if (blocks % 100 == 0)
|
||||
printf(".");
|
||||
}
|
||||
|
||||
printf("\nwrote %d blocks\n", blocks);
|
||||
if(blocks != 65803) {
|
||||
printf("bigfile: file is too small\n");
|
||||
exit(-1);
|
||||
}
|
||||
close(fd);
|
||||
fd = open("big.file", O_RDONLY);
|
||||
if(fd < 0){
|
||||
printf("bigfile: cannot re-open big.file for reading\n");
|
||||
exit(-1);
|
||||
}
|
||||
for(i = 0; i < blocks; i++){
|
||||
int cc = read(fd, buf, sizeof(buf));
|
||||
if(cc <= 0){
|
||||
printf("bigfile: read error at block %d\n", i);
|
||||
exit(-1);
|
||||
}
|
||||
if(*(int*)buf != i){
|
||||
printf("bigfile: read the wrong data (%d) for block %d\n",
|
||||
*(int*)buf, i);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
printf("bigfile done; ok\n");
|
||||
|
||||
exit(0);
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
#include "kernel/types.h"
|
||||
#include "kernel/stat.h"
|
||||
#include "kernel/fcntl.h"
|
||||
#include "user/user.h"
|
||||
|
||||
char buf[512];
|
||||
@ -32,7 +33,7 @@ main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
for(i = 1; i < argc; i++){
|
||||
if((fd = open(argv[i], 0)) < 0){
|
||||
if((fd = open(argv[i], O_RDONLY)) < 0){
|
||||
fprintf(2, "cat: cannot open %s\n", argv[i]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
74
user/find.c
74
user/find.c
@ -1,74 +0,0 @@
|
||||
#include "kernel/types.h"
|
||||
#include "user/user.h"
|
||||
#include "kernel/stat.h"
|
||||
#include "kernel/fs.h"
|
||||
|
||||
int fmtname(const char *path) {
|
||||
int p;
|
||||
for(p=strlen(path); p >= 0 && *(path + p) != '/'; p--);
|
||||
p++;
|
||||
return p;
|
||||
}
|
||||
|
||||
void find(const char *path, const char* target) {
|
||||
char buf[512], *p;
|
||||
int fd;
|
||||
struct dirent de;
|
||||
struct stat st;
|
||||
if((fd = open(path, 0)) < 0){
|
||||
fprintf(2, "find: cannot open %s\n", path);
|
||||
return;
|
||||
}
|
||||
|
||||
if(fstat(fd, &st) < 0){
|
||||
fprintf(2, "find: cannot stat %s\n", path);
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
switch(st.type){
|
||||
case T_DEVICE:
|
||||
case T_FILE:
|
||||
if (strcmp(path + fmtname(path), target) == 0) {
|
||||
printf("%s\n", path);
|
||||
}
|
||||
break;
|
||||
|
||||
case T_DIR:
|
||||
if (strcmp(path + fmtname(path), target) == 0) {
|
||||
printf("%s\n", path);
|
||||
}
|
||||
if(strlen(path) + 1 + DIRSIZ + 1 > sizeof buf){
|
||||
printf("find: path too long\n");
|
||||
break;
|
||||
}
|
||||
strcpy(buf, path);
|
||||
p = buf+strlen(buf);
|
||||
*p++ = '/';
|
||||
while(read(fd, &de, sizeof(de)) == sizeof(de)){
|
||||
if(de.inum == 0)
|
||||
continue;
|
||||
if (strcmp(de.name, ".") == 0 || strcmp(de.name, "..") == 0)
|
||||
continue;
|
||||
memmove(p, de.name, DIRSIZ);
|
||||
p[DIRSIZ] = 0;
|
||||
if(stat(buf, &st) < 0){
|
||||
printf("find: cannot stat %s\n", buf);
|
||||
continue;
|
||||
}
|
||||
find(buf, target);
|
||||
}
|
||||
break;
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc != 3) {
|
||||
printf("\x1b[31mInvalid arguments\x1b[0m\n");
|
||||
printf("\x1b[32musage\x1b[0m: find <base directory> <file name to find>\n");
|
||||
exit(0);
|
||||
}
|
||||
find(argv[1], argv[2]);
|
||||
exit(0);
|
||||
}
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
#include "kernel/types.h"
|
||||
#include "kernel/stat.h"
|
||||
#include "kernel/fcntl.h"
|
||||
#include "user/user.h"
|
||||
|
||||
char buf[1024];
|
||||
@ -51,7 +52,7 @@ main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
for(i = 2; i < argc; i++){
|
||||
if((fd = open(argv[i], 0)) < 0){
|
||||
if((fd = open(argv[i], O_RDONLY)) < 0){
|
||||
printf("grep: cannot open %s\n", argv[i]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
#include "kernel/stat.h"
|
||||
#include "user/user.h"
|
||||
#include "kernel/fs.h"
|
||||
#include "kernel/fcntl.h"
|
||||
|
||||
char*
|
||||
fmtname(char *path)
|
||||
@ -30,7 +31,7 @@ ls(char *path)
|
||||
struct dirent de;
|
||||
struct stat st;
|
||||
|
||||
if((fd = open(path, 0)) < 0){
|
||||
if((fd = open(path, O_RDONLY)) < 0){
|
||||
fprintf(2, "ls: cannot open %s\n", path);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1,27 +0,0 @@
|
||||
#include "kernel/types.h"
|
||||
#include "user/user.h"
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
int p[2]; // hell, read from p[0] and write to p[1] no matter in pa/ch
|
||||
if (pipe(p) == -1) exit(1);
|
||||
uint8 senddata[] = {0xAC};
|
||||
uint8 recvdata[] = {0};
|
||||
int pid = fork();
|
||||
if (pid == 0) {
|
||||
// child
|
||||
if (read(p[0], recvdata, 1) != 1) printf("error child read\n");
|
||||
close(p[0]);
|
||||
printf("%d: received ping\n", getpid());
|
||||
if (write(p[1], senddata, 1) != 1) printf("error child write\n");
|
||||
close(p[1]);
|
||||
exit(0);
|
||||
}
|
||||
else {
|
||||
if (write(p[1], senddata, 1) != 1) printf("error parent write\n");
|
||||
close(p[1]);
|
||||
if (read(p[0], recvdata, 1) != 1) printf("error parent read\n");
|
||||
printf("%d: received pong\n", getpid());
|
||||
close(p[0]);
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
@ -1,51 +0,0 @@
|
||||
#include "kernel/types.h"
|
||||
#include "user/user.h"
|
||||
|
||||
void pipeline(int leftfd) {
|
||||
int pipefd[2];
|
||||
int p; read(leftfd, &p, sizeof(p));
|
||||
printf("prime %d\n", p);
|
||||
int n;
|
||||
int has_right = 0;
|
||||
while (read(leftfd, &n, sizeof(n)) > 0) {
|
||||
if (n % p != 0) {
|
||||
if (!has_right) {
|
||||
has_right = 1;
|
||||
pipe(pipefd);
|
||||
if (fork() == 0) {
|
||||
close(pipefd[1]);
|
||||
pipeline(pipefd[0]);
|
||||
} else {
|
||||
close(pipefd[0]);
|
||||
}
|
||||
}
|
||||
write(pipefd[1], &n, sizeof(n));
|
||||
}
|
||||
}
|
||||
close(leftfd);
|
||||
if (has_right) {
|
||||
close(pipefd[1]);
|
||||
while(wait(0) != -1);
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
int pipefd[2];
|
||||
pipe(pipefd);
|
||||
int pid = fork();
|
||||
if (pid != 0) {
|
||||
close(pipefd[0]); // no need to read in the feeding proc
|
||||
for (int i = 2; i <= 35; ++ i) {
|
||||
write(pipefd[1], &i, sizeof(i));
|
||||
}
|
||||
close(pipefd[1]);
|
||||
while(wait(0) != -1);
|
||||
exit(0);
|
||||
}
|
||||
else {
|
||||
close(pipefd[1]); // pipeline proc will have its own write pipe
|
||||
pipeline(pipefd[0]);
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
17
user/sleep.c
17
user/sleep.c
@ -1,17 +0,0 @@
|
||||
#include "kernel/types.h"
|
||||
#include "user/user.h"
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc != 2) {
|
||||
printf("\x1b[31mUnexpected argument\x1b[0m\n");
|
||||
printf("usage: sleep <ticks>\n");
|
||||
exit(0);
|
||||
}
|
||||
int ticks = atoi(argv[1]);
|
||||
int ret = sleep(ticks);
|
||||
if (ret) {
|
||||
printf("\x1b[31mFailed to sleep\x1b[0m\n");
|
||||
exit(-1);
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
188
user/symlinktest.c
Normal file
188
user/symlinktest.c
Normal file
@ -0,0 +1,188 @@
|
||||
#include "kernel/param.h"
|
||||
#include "kernel/types.h"
|
||||
#include "kernel/stat.h"
|
||||
#include "kernel/riscv.h"
|
||||
#include "kernel/fcntl.h"
|
||||
#include "kernel/spinlock.h"
|
||||
#include "kernel/sleeplock.h"
|
||||
#include "kernel/fs.h"
|
||||
#include "kernel/file.h"
|
||||
#include "user/user.h"
|
||||
|
||||
#define fail(msg) do {printf("FAILURE: " msg "\n"); failed = 1; goto done;} while (0);
|
||||
static int failed = 0;
|
||||
|
||||
static void testsymlink(void);
|
||||
static void concur(void);
|
||||
static void cleanup(void);
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
cleanup();
|
||||
testsymlink();
|
||||
concur();
|
||||
exit(failed);
|
||||
}
|
||||
|
||||
static void
|
||||
cleanup(void)
|
||||
{
|
||||
unlink("/testsymlink/a");
|
||||
unlink("/testsymlink/b");
|
||||
unlink("/testsymlink/c");
|
||||
unlink("/testsymlink/1");
|
||||
unlink("/testsymlink/2");
|
||||
unlink("/testsymlink/3");
|
||||
unlink("/testsymlink/4");
|
||||
unlink("/testsymlink/z");
|
||||
unlink("/testsymlink/y");
|
||||
unlink("/testsymlink");
|
||||
}
|
||||
|
||||
// stat a symbolic link using O_NOFOLLOW
|
||||
static int
|
||||
stat_slink(char *pn, struct stat *st)
|
||||
{
|
||||
int fd = open(pn, O_RDONLY | O_NOFOLLOW);
|
||||
if(fd < 0)
|
||||
return -1;
|
||||
if(fstat(fd, st) != 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
testsymlink(void)
|
||||
{
|
||||
int r, fd1 = -1, fd2 = -1;
|
||||
char buf[4] = {'a', 'b', 'c', 'd'};
|
||||
char c = 0, c2 = 0;
|
||||
struct stat st;
|
||||
|
||||
printf("Start: test symlinks\n");
|
||||
|
||||
mkdir("/testsymlink");
|
||||
|
||||
fd1 = open("/testsymlink/a", O_CREATE | O_RDWR);
|
||||
if(fd1 < 0) fail("failed to open a");
|
||||
|
||||
r = symlink("/testsymlink/a", "/testsymlink/b");
|
||||
if(r < 0)
|
||||
fail("symlink b -> a failed");
|
||||
|
||||
if(write(fd1, buf, sizeof(buf)) != 4)
|
||||
fail("failed to write to a");
|
||||
|
||||
if (stat_slink("/testsymlink/b", &st) != 0)
|
||||
fail("failed to stat b");
|
||||
if(st.type != T_SYMLINK)
|
||||
fail("b isn't a symlink");
|
||||
|
||||
fd2 = open("/testsymlink/b", O_RDWR);
|
||||
if(fd2 < 0)
|
||||
fail("failed to open b");
|
||||
read(fd2, &c, 1);
|
||||
if (c != 'a')
|
||||
fail("failed to read bytes from b");
|
||||
|
||||
unlink("/testsymlink/a");
|
||||
if(open("/testsymlink/b", O_RDWR) >= 0)
|
||||
fail("Should not be able to open b after deleting a");
|
||||
|
||||
r = symlink("/testsymlink/b", "/testsymlink/a");
|
||||
if(r < 0)
|
||||
fail("symlink a -> b failed");
|
||||
|
||||
r = open("/testsymlink/b", O_RDWR);
|
||||
if(r >= 0)
|
||||
fail("Should not be able to open b (cycle b->a->b->..)\n");
|
||||
|
||||
r = symlink("/testsymlink/nonexistent", "/testsymlink/c");
|
||||
if(r != 0)
|
||||
fail("Symlinking to nonexistent file should succeed\n");
|
||||
|
||||
r = symlink("/testsymlink/2", "/testsymlink/1");
|
||||
if(r) fail("Failed to link 1->2");
|
||||
r = symlink("/testsymlink/3", "/testsymlink/2");
|
||||
if(r) fail("Failed to link 2->3");
|
||||
r = symlink("/testsymlink/4", "/testsymlink/3");
|
||||
if(r) fail("Failed to link 3->4");
|
||||
|
||||
close(fd1);
|
||||
close(fd2);
|
||||
|
||||
fd1 = open("/testsymlink/4", O_CREATE | O_RDWR);
|
||||
if(fd1<0) fail("Failed to create 4\n");
|
||||
fd2 = open("/testsymlink/1", O_RDWR);
|
||||
if(fd2<0) fail("Failed to open 1\n");
|
||||
|
||||
c = '#';
|
||||
r = write(fd2, &c, 1);
|
||||
if(r!=1) fail("Failed to write to 1\n");
|
||||
r = read(fd1, &c2, 1);
|
||||
if(r!=1) fail("Failed to read from 4\n");
|
||||
if(c!=c2)
|
||||
fail("Value read from 4 differed from value written to 1\n");
|
||||
|
||||
printf("test symlinks: ok\n");
|
||||
done:
|
||||
close(fd1);
|
||||
close(fd2);
|
||||
}
|
||||
|
||||
static void
|
||||
concur(void)
|
||||
{
|
||||
int pid, i;
|
||||
int fd;
|
||||
struct stat st;
|
||||
int nchild = 2;
|
||||
|
||||
printf("Start: test concurrent symlinks\n");
|
||||
|
||||
fd = open("/testsymlink/z", O_CREATE | O_RDWR);
|
||||
if(fd < 0) {
|
||||
printf("FAILED: open failed");
|
||||
exit(1);
|
||||
}
|
||||
close(fd);
|
||||
|
||||
for(int j = 0; j < nchild; j++) {
|
||||
pid = fork();
|
||||
if(pid < 0){
|
||||
printf("FAILED: fork failed\n");
|
||||
exit(1);
|
||||
}
|
||||
if(pid == 0) {
|
||||
int m = 0;
|
||||
unsigned int x = (pid ? 1 : 97);
|
||||
for(i = 0; i < 100; i++){
|
||||
x = x * 1103515245 + 12345;
|
||||
if((x % 3) == 0) {
|
||||
symlink("/testsymlink/z", "/testsymlink/y");
|
||||
if (stat_slink("/testsymlink/y", &st) == 0) {
|
||||
m++;
|
||||
if(st.type != T_SYMLINK) {
|
||||
printf("FAILED: not a symbolic link\n", st.type);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
unlink("/testsymlink/y");
|
||||
}
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
int r;
|
||||
for(int j = 0; j < nchild; j++) {
|
||||
wait(&r);
|
||||
if(r != 0) {
|
||||
printf("test concurrent symlinks: failed\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
printf("test concurrent symlinks: ok\n");
|
||||
}
|
||||
@ -22,6 +22,7 @@ int getpid(void);
|
||||
char* sbrk(int);
|
||||
int sleep(int);
|
||||
int uptime(void);
|
||||
int symlink(char* target, char* path);
|
||||
|
||||
// ulib.c
|
||||
int stat(const char*, struct stat*);
|
||||
|
||||
@ -36,3 +36,4 @@ entry("getpid");
|
||||
entry("sbrk");
|
||||
entry("sleep");
|
||||
entry("uptime");
|
||||
entry("symlink");
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
#include "kernel/types.h"
|
||||
#include "kernel/stat.h"
|
||||
#include "kernel/fcntl.h"
|
||||
#include "user/user.h"
|
||||
|
||||
char buf[512];
|
||||
@ -43,7 +44,7 @@ main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
for(i = 1; i < argc; i++){
|
||||
if((fd = open(argv[i], 0)) < 0){
|
||||
if((fd = open(argv[i], O_RDONLY)) < 0){
|
||||
printf("wc: cannot open %s\n", argv[i]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
59
user/xargs.c
59
user/xargs.c
@ -1,59 +0,0 @@
|
||||
#include "kernel/param.h"
|
||||
#include "kernel/types.h"
|
||||
#include "user/user.h"
|
||||
|
||||
static inline int is_ws(const char ch) {
|
||||
return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r';
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
int STDIN = 0;
|
||||
char linebuf[1024];
|
||||
char* p = linebuf;
|
||||
char* _argv[MAXARG];
|
||||
while (read(STDIN, p, 1) > 0) {
|
||||
if (*p == '\n') {
|
||||
int i;
|
||||
int in_ws = 1;
|
||||
for (i = 0; i < argc - 1; ++i) {
|
||||
_argv[i] = argv[i + 1];
|
||||
}
|
||||
for (char* p0 = linebuf; p0 <= p; ++p0) {
|
||||
if (is_ws(*p0)) {
|
||||
if (!in_ws) {
|
||||
in_ws = 1;
|
||||
i++;
|
||||
}
|
||||
*p0 = '\0';
|
||||
} else if (in_ws) {
|
||||
in_ws = 0;
|
||||
_argv[i] = p0;
|
||||
}
|
||||
if (i >= MAXARG) {
|
||||
printf("warning: too many arguments");
|
||||
break;
|
||||
}
|
||||
}
|
||||
*p = '\0';
|
||||
_argv[i] = 0;
|
||||
// for (int j = 0; j < i; ++ j) {
|
||||
// printf("%s\n", _argv[j]);
|
||||
// }
|
||||
if (fork() == 0) {
|
||||
exec(_argv[0], _argv);
|
||||
exit(0);
|
||||
} else {
|
||||
p = linebuf;
|
||||
while (wait(0) != -1)
|
||||
;
|
||||
}
|
||||
} else {
|
||||
p++;
|
||||
if (p >= linebuf + sizeof(linebuf)) {
|
||||
printf("line buffer exceeded\n");
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
@ -1,6 +0,0 @@
|
||||
mkdir a
|
||||
echo hello > a/b
|
||||
mkdir c
|
||||
echo hello > c/b
|
||||
echo hello > b
|
||||
find . b | xargs grep hello
|
||||
Loading…
Reference in New Issue
Block a user