support the "ls" command

This commit is contained in:
Lu Sitong 2021-01-16 22:49:36 +08:00
parent ee2ee8469e
commit c8ad18ca00
19 changed files with 332 additions and 228 deletions

View File

@ -1,4 +1,5 @@
platform := k210
# platform := qemu
K=kernel
U=xv6-user
T=target
@ -179,14 +180,14 @@ UPROGS=\
$U/_init\
$U/_sh\
$U/_cat\
$U/_echo\
$U/_grep\
$U/_ls\
$U/_test
# $U/_echo\
# $U/_forktest\
# $U/_grep\
# $U/_kill\
# $U/_ln\
# $U/_ls\
# $U/_mkdir\
# $U/_rm\
# $U/_stressfs\

View File

@ -62,7 +62,7 @@ Besides, file system and uesr programs are available on qemu. More details [here
```bash
$ dd if=/dev/zero of=fs.img bs=512k count=2048
$ mkfs.vfat -F 32 fs.img
$ make fs
$ make build
$ (sudo)mount fs.img /mnt
$ (sudo)cp xv6-user/_init /mnt/init
$ (sudo)cp xv6-user/_sh /mnt
@ -73,7 +73,12 @@ $ make run platform=qemu
```
After entering `qemu`, type `_cat init.c`, and it will read the contents of `init.c` in `fs.img`, output to the terminal.
The `init.c` can be any text file.
The `init.c` can be any text file. In addition, `shell` supports some shortcut keys as below:
- Ctrl-H -- backspace
- Ctrl-U -- kill a line
- Ctrl-D -- end of file (EOF)
- Ctrl-P -- print process list
## Progress
- [x] Multicore boot

View File

@ -62,7 +62,7 @@ Ps: 按 `Ctrl + A` 然后 `X` 退出 `qemu`。
```bash
$ dd if=/dev/zero of=fs.img bs=512k count=2048
$ mkfs.vfat -F 32 fs.img
$ make fs
$ make build
$ (sudo)mount fs.img /mnt
$ (sudo)cp xv6-user/_init /mnt/init
$ (sudo)cp xv6-user/_sh /mnt
@ -73,7 +73,11 @@ $ make run platform=qemu
```
进入 `qemu` 后输入命令 `_cat init.c`,将会读取 `fs.img` 中的 `init.c` 文件内容并输出到终端。
这里的 `init.c` 文件可以是任意文本文件。
这里的 `init.c` 文件可以是任意文本文件。此外,`shell`支持下列快捷键:
- Ctrl-H -- 退格
- Ctrl-U -- 删除行
- Ctrl-D -- 文件尾EOF
- Ctrl-P -- 打印进程列表
## 进度
- [x] 多核启动

View File

@ -18,7 +18,6 @@
+ 目前只实现了文件读,文件写有初步实现但不完善,主要有新建文件无法生成时间戳、文件名校验和等问题;
+ 由于FAT32目录结构与xv6目录结构的不同还未实现相关的接口为`ls`等程序提供支持;
+ 对`"."`和`".."`两个特殊文件的支持还不完善尤其是在根目录下因为FAT32的根目录中没有这两个文件
+ FAT32的文件属性不支持设备类型而原xv6文件系统中有`mknod`系统调用新建一个设备,并可以使用`open`打开。控制台输入输出就是这样打开的。为打开控制台标准输入输出,我们改用了另一种实现。
## 如何在qemu上挂载文件镜像
@ -35,10 +34,10 @@ $ mkfs.vfat -F 32 fs.img
首先通过`mount`命令,将镜像挂载到你指定的目录(这里以/mnt为例然后将build之后xv6-user目录下文件名以"\_"为前缀的用户程序拷贝至镜像中,再取消挂载以保存写入结果即可。也可以在镜像中建立一些文本文件进行读测试。
注意必须将xv6-user目录下的"\_init"拷贝至镜像中,并且重命名为"init"这是xv6原本的设定目前我们暂未更改还需拷贝"\_sh"至镜像中才能启动shell。编写的用户程序也需要放在xv6-user目录下同时需要添加至Makefile的`UPROGS`目标中,才能连同内核一起编译链接。
注意必须将xv6-user目录下的"\_init"拷贝至镜像根目录中,并且重命名为"init"这是xv6原本的设定目前我们暂未更改还需拷贝"\_sh"至镜像中才能启动shell。编写的用户程序也需要放在xv6-user目录下同时需要添加至Makefile的`UPROGS`目标中,才能连同内核一起编译链接。
```bash
$ make fs
$ make build
$ (sudo)mount fs.img /mnt
$ (sudo)cp xv6-user/_init /mnt/init
$ (sudo)cp xv6-user/_sh /mnt

View File

@ -50,12 +50,8 @@ int exec(char *path, char **argv)
pagetable_t pagetable = 0, oldpagetable;
struct proc *p = myproc();
// begin_op();
if((ep = ename(path)) == 0){
// printf("exec: can't find %s\n", path);
// end_op();
if((ep = ename(path)) == 0)
return -1;
}
elock(ep);
// Check ELF header
@ -88,7 +84,6 @@ int exec(char *path, char **argv)
}
eunlock(ep);
eput(ep);
// end_op();
ep = 0;
p = myproc();
@ -154,8 +149,6 @@ int exec(char *path, char **argv)
if(ep){
eunlock(ep);
eput(ep);
// end_op();
}
// printf("[exec]bad, pid = %d\n", p->pid);
return -1;
}

View File

@ -72,12 +72,17 @@ int fat32_init()
initlock(&ecache.lock, "ecache");
memset(&root, 0, sizeof(root));
initsleeplock(&root.lock, "entry");
root.attribute = ATTR_DIRECTORY;
root.first_clus = fat.bpb.root_clus;
root.attribute = (ATTR_DIRECTORY | ATTR_SYSTEM);
root.first_clus = root.cur_clus = fat.bpb.root_clus;
root.valid = 1;
root.prev = &root;
root.next = &root;
for(struct dirent *de = ecache.entries; de < ecache.entries + ENTRY_CACHE_NUM; de++) {
de->dev = 0;
de->valid = 0;
de->ref = 0;
de->dirty = 0;
de->parent = 0;
de->next = root.next;
de->prev = &root;
initsleeplock(&de->lock, "entry");
@ -166,14 +171,14 @@ static void zero_clus(uint32 cluster)
}
}
static uint32 alloc_clus()
static uint32 alloc_clus(uint8 dev)
{
// should we keep a free cluster list? instead of searching fat every time.
struct buf *b;
uint32 sec = fat.bpb.rsvd_sec_cnt;
uint32 const ent_per_sec = fat.bpb.byts_per_sec / sizeof(uint32);
for (uint32 i = 0; i < fat.bpb.fat_sz; i++, sec++) {
b = bread(0, sec);
b = bread(dev, sec);
for (uint32 j = 0; j < ent_per_sec; j++) {
if (((uint32 *)(b->data))[j] == 0) {
((uint32 *)(b->data))[j] = FAT32_EOC + 7;
@ -225,32 +230,51 @@ static uint rw_clus(uint32 cluster, int write, int user, uint64 data, uint off,
return tot;
}
/**
* for the given entry, relocate the cur_clus field based on the off
* @param entry modify its cur_clus field
* @param off the offset from the beginning of the relative file
* @return the offset from the new cur_clus
*/
static uint reloc_clus(struct dirent *entry, uint off)
{
int clus_num = off / fat.byts_per_clus;
while (clus_num > entry->clus_cnt) {
entry->cur_clus = read_fat(entry->cur_clus);
entry->clus_cnt++;
}
if (clus_num < entry->clus_cnt) {
entry->cur_clus = entry->first_clus;
entry->clus_cnt = 0;
while (entry->clus_cnt < clus_num) {
entry->cur_clus = read_fat(entry->cur_clus);
entry->clus_cnt++;
}
}
return off % fat.byts_per_clus;
}
/* like the original readi, but "reade" is odd, let alone "writee" */
// Caller must hold entry->lock.
int eread(struct dirent *entry, int user_dst, uint64 dst, uint off, uint n)
{
if (off > entry->file_size || off + n < off) {
if (off > entry->file_size || off + n < off || (entry->attribute & ATTR_DIRECTORY)) {
return 0;
}
if (off + n > entry->file_size) {
n = entry->file_size - off;
}
int clus_num = off / fat.byts_per_clus;
off = off % fat.byts_per_clus;
uint32 cluster = entry->first_clus;
while (clus_num-- > 0 && cluster < FAT32_EOC) {
cluster = read_fat(cluster);
}
uint tot, m;
for (tot = 0; cluster < FAT32_EOC && tot < n; tot += m, off += m, dst += m) {
for (tot = 0; entry->cur_clus < FAT32_EOC && tot < n; tot += m, off += m, dst += m) {
reloc_clus(entry, off);
m = fat.byts_per_clus - off % fat.byts_per_clus;
if (n - tot < m) {
m = n - tot;
}
if (rw_clus(cluster, 0, user_dst, dst, off % fat.byts_per_clus, m) != m) {
if (rw_clus(entry->cur_clus, 0, user_dst, dst, off % fat.byts_per_clus, m) != m) {
break;
}
cluster = read_fat(cluster);
}
return tot;
}
@ -258,38 +282,34 @@ int eread(struct dirent *entry, int user_dst, uint64 dst, uint off, uint n)
// Caller must hold entry->lock.
int ewrite(struct dirent *entry, int user_src, uint64 src, uint off, uint n)
{
if (off > entry->file_size || off + n < off) {
if (off > entry->file_size || off + n < off || (entry->attribute & ATTR_READ_ONLY)) {
return -1;
}
int clus_num = off / fat.byts_per_clus;
off = off % fat.byts_per_clus;
if (entry->first_clus == 0) {
entry->first_clus = alloc_clus();
eupdate(entry);
}
uint32 cluster = entry->first_clus;
while (clus_num-- > 0) {
cluster = read_fat(cluster);
if (entry->first_clus == 0) { // so file_size if 0 too, which requests off == 0
entry->cur_clus = entry->first_clus = alloc_clus(entry->dev);
entry->clus_cnt = 0;
entry->dirty = 1;
}
uint tot, m;
for (tot = 0; tot < n; tot += m, off += m, src += m) {
if (cluster >= FAT32_EOC) {
reloc_clus(entry, off);
if (entry->cur_clus >= FAT32_EOC) {
uint32 new_clus = alloc_clus(entry->dev);
write_fat(cluster, new_clus);
write_fat(entry->cur_clus, new_clus);
}
m = fat.byts_per_clus - off % fat.byts_per_clus;
if (n - tot < m) {
m = n - tot;
}
if (rw_clus(cluster, 1, user_src, src, off % fat.byts_per_clus, m) != m) {
if (rw_clus(entry->cur_clus, 1, user_src, src, off % fat.byts_per_clus, m) != m) {
break;
}
cluster = read_fat(cluster);
}
if(n > 0) {
if(off > entry->file_size) {
entry->file_size = off;
entry->dirty = 1;
eupdate(entry);
}
}
@ -297,23 +317,25 @@ int ewrite(struct dirent *entry, int user_src, uint64 src, uint off, uint n)
}
// should never get root by eget
static struct dirent *eget(uint dev, uint32 parent, char *name)
static struct dirent *eget(struct dirent *parent, char *name)
{
struct dirent *ep;
acquire(&ecache.lock);
for (ep = root.next; ep != &root; ep = ep->next) {
if (ep->dev == dev && ep->parent == parent
&& strncmp(ep->filename, name, FAT32_MAX_FILENAME) == 0) {
ep->ref++;
ep->valid = 1;
release(&ecache.lock);
return ep;
if (name) {
for (ep = root.next; ep != &root; ep = ep->next) {
if (ep->parent == parent && strncmp(ep->filename, name, FAT32_MAX_FILENAME) == 0) {
ep->ref++;
ep->valid = 1;
release(&ecache.lock);
edup(ep->parent);
return ep;
}
}
}
for (ep = root.prev; ep != &root; ep = ep->prev) {
if (ep->ref == 0) {
ep->ref = 1;
ep->dev = dev;
ep->dev = parent->dev;
ep->off = 0;
ep->valid = 0;
release(&ecache.lock);
@ -333,14 +355,15 @@ static void wnstr_lazy(wchar *dst, char const *src, int len) {
struct dirent *ealloc(struct dirent *dp, char *name, int dir)
{
if (dp->attribute != ATTR_DIRECTORY) { return 0; }
if (!(dp->attribute & ATTR_DIRECTORY)) { return 0; }
struct dirent *ep;
uint off = 0;
ep = dirlookup(dp, name, &off);
if (ep != 0) { // entry exists
eput(ep);
return 0;
}
ep = eget(dp->dev, dp->parent, name);
ep = eget(dp, name);
if (ep->valid) { // shouldn't be valid
panic("ealloc");
}
@ -349,39 +372,36 @@ struct dirent *ealloc(struct dirent *dp, char *name, int dir)
ep->attribute = 0;
ep->file_size = 0;
ep->first_clus = 0;
ep->parent = dp->first_clus;
ep->parent = edup(dp);
ep->off = off;
ep->clus_cnt = 0;
ep->cur_clus = 0;
strncpy(ep->filename, name, FAT32_MAX_FILENAME);
int len = strlen(name);
int entcnt = (len + CHAR_LONG_NAME - 1) / CHAR_LONG_NAME; // count of l-n-entries, rounds up
uint clus = dp->first_clus;
int clus_cnt = off / fat.byts_per_clus;
off %= fat.byts_per_clus;
while (clus_cnt-- != 0) {
clus = read_fat(clus);
}
uint8 ebuf[32] = {0};
if(dir){ // generate "." and ".." for ep
ep->attribute |= ATTR_DIRECTORY;
ep->first_clus = alloc_clus();
ep->cur_clus = ep->first_clus = alloc_clus(dp->dev);
strncpy((char *)ebuf, ".", 11);
ebuf[11] = ATTR_DIRECTORY;
*(uint16 *)(ebuf + 20) = (uint16)(ep->first_clus >> 16);
*(uint16 *)(ebuf + 26) = (uint16)(ep->first_clus & 0xff);
*(uint32 *)(ebuf + 28) = 0;
rw_clus(clus, 1, 0, (uint64)ebuf, 0, sizeof(ebuf));
rw_clus(ep->cur_clus, 1, 0, (uint64)ebuf, 0, sizeof(ebuf));
strncpy((char *)ebuf, "..", 11);
ebuf[11] = ATTR_DIRECTORY;
*(uint16 *)(ebuf + 20) = (uint16)(dp->first_clus >> 16);
*(uint16 *)(ebuf + 26) = (uint16)(dp->first_clus & 0xff);
*(uint32 *)(ebuf + 28) = 0;
rw_clus(clus, 1, 0, (uint64)ebuf, 32, sizeof(ebuf));
rw_clus(ep->cur_clus, 1, 0, (uint64)ebuf, 32, sizeof(ebuf));
} else {
ep->attribute |= ATTR_ARCHIVE;
}
memset(ebuf, 0, sizeof(ebuf));
off = reloc_clus(dp, off);
for (uint8 i = entcnt; i > 0; i--) { // ignore checksum
ebuf[0] = i;
if (i == entcnt) {
@ -394,13 +414,10 @@ struct dirent *ealloc(struct dirent *dp, char *name, int dir)
wnstr_lazy((wchar *) (ebuf + 1), ep->filename + i * CHAR_LONG_NAME, 5);
wnstr_lazy((wchar *) (ebuf + 14), ep->filename + i * CHAR_LONG_NAME + 5, 6);
wnstr_lazy((wchar *) (ebuf + 28), ep->filename + i * CHAR_LONG_NAME + 11, 2);
rw_clus(clus, 1, 0, (uint64)ebuf, off, sizeof(ebuf));
off += 32;
if (off >= fat.byts_per_clus) {
clus = read_fat(clus);
off -= fat.byts_per_clus;
}
rw_clus(dp->cur_clus, 1, 0, (uint64)ebuf, off, sizeof(ebuf));
off = reloc_clus(dp, off + 32);
}
ep->dirty = 1;
eupdate(ep);
ep->valid = 1;
eunlock(ep);
@ -409,17 +426,20 @@ struct dirent *ealloc(struct dirent *dp, char *name, int dir)
struct dirent *edup(struct dirent *entry)
{
acquire(&ecache.lock);
entry->ref++;
release(&ecache.lock);
if (entry != 0) {
acquire(&ecache.lock);
entry->ref++;
release(&ecache.lock);
}
return entry;
}
// only update file size
void eupdate(struct dirent *entry)
{
if (!entry->dirty) { return; }
printf("[eupdate] %s\n", entry->filename);
uint entcnt;
uint32 clus = entry->parent;
uint32 clus = entry->parent->first_clus;
uint32 off = entry->off % fat.byts_per_clus;
for (uint clus_cnt = entry->off / fat.byts_per_clus; clus_cnt > 0; clus_cnt--) {
clus = read_fat(clus);
@ -437,12 +457,13 @@ void eupdate(struct dirent *entry)
rw_clus(clus, 1, 0, (uint64) &clus_high, off + 20, sizeof(clus_high));
rw_clus(clus, 1, 0, (uint64) &clus_low, off + 26, sizeof(clus_low));
rw_clus(clus, 1, 0, (uint64) &entry->file_size, off + 28, sizeof(entry->file_size));
entry->dirty = 0;
}
void etrunc(struct dirent *entry)
{
uint entcnt;
uint32 clus = entry->parent;
uint32 clus = entry->parent->first_clus;
uint32 off = entry->off % fat.byts_per_clus;
for (uint clus_cnt = entry->off / fat.byts_per_clus; clus_cnt > 0; clus_cnt--) {
clus = read_fat(clus);
@ -496,6 +517,7 @@ void eput(struct dirent *entry)
root.next->prev = entry;
root.next = entry;
eupdate(entry);
eput(entry->parent);
}
releasesleep(&entry->lock);
acquire(&ecache.lock);
@ -506,7 +528,8 @@ void eput(struct dirent *entry)
void estat(struct dirent *entry, struct stat *st)
{
st->attribute = entry->attribute;
strncpy(st->name, entry->filename, STAT_MAX_NAME);
st->type = (entry->attribute & ATTR_DIRECTORY) ? T_DIR : T_FILE;
st->dev = entry->dev;
st->size = entry->file_size;
}
@ -558,6 +581,54 @@ static void read_entry_info(struct dirent *entry, uint8 *raw_entry)
entry->first_clus = ((uint32) *(uint16 *)(raw_entry + 20)) << 16;
entry->first_clus += *(uint16 *)(raw_entry + 26);
entry->file_size = *(uint32 *)(raw_entry + 28);
entry->cur_clus = entry->first_clus;
entry->clus_cnt = 0;
}
/**
* Read a directory from off
*
*
*/
int enext(struct dirent *dp, struct dirent *ep, uint off, int *count)
{
if (!(dp->attribute & ATTR_DIRECTORY))
panic("enext not dir");
if (ep->valid)
panic("enext ep valid");
if (off % 32)
panic("enext not align");
uint8 ebuf[32];
int cnt = 0;
for (uint off2 = reloc_clus(dp, off); dp->cur_clus < FAT32_EOC; off2 = reloc_clus(dp, off2 + 32)) {
if (rw_clus(dp->cur_clus, 0, 0, (uint64)ebuf, off2, 32) != 32 || ebuf[0] == END_OF_ENTRY) {
return -1;
}
if (ebuf[0] == EMPTY_ENTRY) {
cnt++;
continue;
} else if (cnt) {
*count = cnt;
return 0;
}
if (ebuf[11] == ATTR_LONG_NAME) {
int lcnt = ebuf[0] & ~LAST_LONG_ENTRY;
if (ebuf[0] & LAST_LONG_ENTRY) {
*count = lcnt + 1; // plus the s-n-e;
count = 0;
*(ep->filename + lcnt * CHAR_LONG_NAME) = '\0'; // if filename aligns CHAR_LONG_NAME, then no '\0' is stored in the raw entry.
}
read_entry_name(ep->filename + (lcnt - 1) * CHAR_LONG_NAME, ebuf, 1);
} else {
if (count) {
*count = 1;
read_entry_name(ep->filename, ebuf, 0);
}
read_entry_info(ep, ebuf);
return 1;
}
}
return -1;
}
/**
@ -568,82 +639,38 @@ static void read_entry_info(struct dirent *entry, uint8 *raw_entry)
*/
struct dirent *dirlookup(struct dirent *entry, char *filename, uint *poff)
{
if (entry->attribute != ATTR_DIRECTORY)
if (!(entry->attribute & ATTR_DIRECTORY))
panic("dirlookup not DIR");
struct dirent *de = eget(entry->dev, entry->first_clus, filename);
if (strncmp(filename, ".", FAT32_MAX_FILENAME) == 0) {
return edup(entry);
} else if (strncmp(filename, "..", FAT32_MAX_FILENAME) == 0) {
return edup(entry->parent);
}
struct dirent *de = eget(entry, filename);
if (de->valid) { return de; } // ecache hits
uint8 ebuf[32];
char name[CHAR_LONG_NAME];
int len = strlen(filename);
int entcnt = (len + CHAR_LONG_NAME - 1) / CHAR_LONG_NAME; // count of l-n-entries, rounds up
uint32 cluster = entry->first_clus;
uint clus_cnt = 0;
uint off = 0;
int match = 0;
int first = 1;
int empty_cnt = entcnt;
while (cluster < FAT32_EOC) {
while (off < fat.byts_per_clus) {
if (rw_clus(cluster, 0, 0, (uint64)ebuf, off, 32) != 32 || ebuf[0] == END_OF_ENTRY) {
goto miss;
}
if (ebuf[0] == EMPTY_ENTRY) {
if (poff) {
if (first) {
empty_cnt = entcnt;
first = 0;
} else if (--empty_cnt == 0) {
*poff = clus_cnt * fat.byts_per_clus + off - (entcnt << 5);
poff = 0;
}
}
off += 32;
continue;
} else if (poff) {
first = 1;
}
if (ebuf[11] == ATTR_LONG_NAME) {
int count = ebuf[0] & ~LAST_LONG_ENTRY;
if ((ebuf[0] & LAST_LONG_ENTRY) && count != entcnt) { // meet first l-n-e, and if count is unequal
off += (count + 1) << 5; // skip over, plus corresponding s-n-e
continue;
}
read_entry_name(name, ebuf, 1);
int offset = (count - 1) * CHAR_LONG_NAME;
if (strncmp(name, filename + offset, CHAR_LONG_NAME) != 0) {
off += (count + 1) << 5;
continue;
}
if (count == 1) {
match = 1;
}
off += 32;
} else {
if (!match) {
read_entry_name(name, ebuf, 0);
if (strncmp(name, filename, 11) != 0) {
off += 32;
continue;
}
}
strncpy(de->filename, filename, len);
read_entry_info(de, ebuf);
de->parent = entry->first_clus;
de->off = clus_cnt * fat.byts_per_clus + off - (entcnt << 5);
de->valid = 1;
return de;
int entcnt = (len + CHAR_LONG_NAME - 1) / CHAR_LONG_NAME + 1; // count of l-n-entries, rounds up
int count = 0;
int type;
uint off = reloc_clus(entry, 0);
while ((type = enext(entry, de, off, &count) != -1)) {
if (type == 0) {
if (poff && count >= entcnt) {
*poff = off;
poff = 0;
}
} else if (strncmp(filename, de->filename, FAT32_MAX_FILENAME) == 0) {
de->parent = edup(entry);
de->off = off;
de->valid = 1;
return de;
}
off -= fat.byts_per_clus;
cluster = read_fat(cluster);
clus_cnt++;
off = reloc_clus(entry, off + count * 32);
}
miss:
if (poff) {
*poff = clus_cnt * fat.byts_per_clus + off;
*poff = off;
}
eput(de);
return 0;
@ -683,7 +710,7 @@ static struct dirent *lookup_path(char *path, int parent, char *name)
}
while ((path = skipelem(path, name)) != 0) {
elock(entry);
if (entry->attribute != ATTR_DIRECTORY) {
if (!(entry->attribute & ATTR_DIRECTORY)) {
eunlock(entry);
eput(entry);
return 0;

View File

@ -77,8 +77,10 @@ fileclose(struct file *f)
if(ff.type == FD_PIPE){
pipeclose(ff.pipe, ff.writable);
} else if(ff.type == FD_ENTRY || ff.type == FD_DEVICE){
} else if(ff.type == FD_ENTRY){
eput(ff.ep);
} else if (ff.type == FD_DEVICE) {
}
}
@ -90,7 +92,7 @@ filestat(struct file *f, uint64 addr)
struct proc *p = myproc();
struct stat st;
if(f->type == FD_ENTRY || f->type == FD_DEVICE){
if(f->type == FD_ENTRY){
elock(f->ep);
estat(f->ep, &st);
eunlock(f->ep);
@ -111,19 +113,23 @@ fileread(struct file *f, uint64 addr, int n)
if(f->readable == 0)
return -1;
if(f->type == FD_PIPE){
r = piperead(f->pipe, addr, n);
} else if(f->type == FD_DEVICE){
if(f->major < 0 || f->major >= NDEV || !devsw[f->major].read)
return -1;
r = devsw[f->major].read(1, addr, n);
} else if(f->type == FD_ENTRY){
elock(f->ep);
if((r = eread(f->ep, 1, addr, f->off, n)) > 0)
f->off += r;
eunlock(f->ep);
} else {
panic("fileread");
switch (f->type) {
case FD_PIPE:
r = piperead(f->pipe, addr, n);
break;
case FD_DEVICE:
if(f->major < 0 || f->major >= NDEV || !devsw[f->major].read)
return -1;
r = devsw[f->major].read(1, addr, n);
break;
case FD_ENTRY:
elock(f->ep);
if((r = eread(f->ep, 1, addr, f->off, n)) > 0)
f->off += r;
eunlock(f->ep);
break;
default:
panic("fileread");
}
return r;
@ -161,3 +167,33 @@ filewrite(struct file *f, uint64 addr, int n)
return ret;
}
// Read from dir f.
// addr is a user virtual address.
int
dirnext(struct file *f, uint64 addr)
{
struct proc *p = myproc();
if(f->readable == 0 || !(f->ep->attribute & ATTR_DIRECTORY))
return -1;
struct dirent de;
struct stat st;
int count = 0;
int ret;
memset(&de, 0, sizeof(de));
elock(f->ep);
while ((ret = enext(f->ep, &de, f->off, &count)) == 0) { // skip empty entry
f->off += count * 32;
}
eunlock(f->ep);
if (ret == -1)
return 0;
f->off += count * 32;
estat(&de, &st);
if(copyout(p->pagetable, addr, (char *)&st, sizeof(st)) < 0)
return -1;
return 1;
}

View File

@ -50,6 +50,7 @@ void eput(struct dirent *entry);
void estat(struct dirent *ep, struct stat *st);
void elock(struct dirent *entry);
void eunlock(struct dirent *entry);
int enext(struct dirent *dp, struct dirent *ep, uint off, int *count);
struct dirent* ename(char *path);
struct dirent* enameparent(char *path, char *name);
int eread(struct dirent *entry, int user_dst, uint64 dst, uint off, uint n);
@ -63,6 +64,7 @@ void fileinit(void);
int fileread(struct file*, uint64, int n);
int filestat(struct file*, uint64 addr);
int filewrite(struct file*, uint64, int n);
int dirnext(struct file *f, uint64 addr);
// fs.c
// void fsinit(int);

View File

@ -28,12 +28,16 @@ struct dirent {
// uint16 last_write_date;
uint32 file_size;
uint32 cur_clus;
uint clus_cnt;
/* for OS */
uint dev;
int valid;
uint8 dev;
uint8 dirty;
uint8 valid;
int ref;
uint32 parent; // because FAT32 doesn't have such thing like inum, use this for cache trick
uint32 off; // offset in the parent dir entry, for writing convenience
uint32 off; // offset in the parent dir entry, for writing convenience
struct dirent *parent; // because FAT32 doesn't have such thing like inum, use this for cache trick
struct dirent *next;
struct dirent *prev;
struct sleeplock lock;

View File

@ -2,11 +2,12 @@
#define T_FILE 2 // File
#define T_DEVICE 3 // Device
#define STAT_MAX_NAME 32
struct stat {
char name[STAT_MAX_NAME + 1];
int dev; // File system's disk device
uint8 attribute;
// short type; // Type of file
// short nlink; // Number of links to file
short type; // Type of file
uint64 size; // Size of file in bytes
};

View File

@ -22,3 +22,5 @@
#define SYS_close 21
#define SYS_test_proc 22
#define SYS_dev 23
#define SYS_dir 24
#define SYS_getcwd 25

View File

@ -402,9 +402,7 @@ exit(int status)
}
}
// begin_op();
eput(p->cwd);
// end_op();
p->cwd = 0;
// we might re-parent a child to init. we can't be precise about

View File

@ -118,8 +118,8 @@ void snstr(char *dst, wchar const *src, int len) {
*dst++ = (uchar)(*src & 0xff);
src ++;
}
*dst = 0;
while(len-- > 0)
*dst++ = 0;
}
int wcsncmp(wchar const *s1, wchar const *s2, int len) {

View File

@ -108,6 +108,8 @@ extern uint64 sys_write(void);
extern uint64 sys_uptime(void);
extern uint64 sys_test_proc(void);
extern uint64 sys_dev(void);
extern uint64 sys_dir(void);
extern uint64 sys_getcwd(void);
static uint64 (*syscalls[])(void) = {
[SYS_fork] sys_fork,
@ -133,6 +135,8 @@ static uint64 (*syscalls[])(void) = {
[SYS_close] sys_close,
[SYS_test_proc] sys_test_proc,
[SYS_dev] sys_dev,
[SYS_dir] sys_dir,
[SYS_getcwd] sys_getcwd,
};
void

View File

@ -144,16 +144,8 @@ create(char *path, short type)
return 0;
elock(dp);
if((ep = dirlookup(dp, name, 0)) != 0){
eunlock(dp);
eput(dp);
elock(ep);
return ep;
}
if((ep = ealloc(dp, name, type == T_DIR)) == 0)
panic("create: ialloc");
return 0;
elock(ep);
@ -186,7 +178,7 @@ sys_open(void)
return -1;
}
elock(ep);
if(ep->attribute == ATTR_DIRECTORY && omode != O_RDONLY){
if((ep->attribute & ATTR_DIRECTORY) && omode != O_RDONLY){
eunlock(ep);
eput(ep);
return -1;
@ -265,7 +257,7 @@ sys_chdir(void)
return -1;
}
elock(ep);
if(ep->attribute != ATTR_DIRECTORY){
if(!(ep->attribute & ATTR_DIRECTORY)){
eunlock(ep);
eput(ep);
return -1;
@ -349,6 +341,7 @@ sys_pipe(void)
return 0;
}
// To open console device.
uint64
sys_dev(void)
{
@ -381,4 +374,52 @@ sys_dev(void)
f->writable = (omode & O_WRONLY) || (omode & O_RDWR);
return fd;
}
// To support ls command
uint64
sys_dir(void)
{
struct file *f;
uint64 p;
if(argfd(0, 0, &f) < 0 || argaddr(1, &p) < 0)
return -1;
return dirnext(f, p);
}
// get absolute cwd string
uint64
sys_getcwd(void)
{
uint64 addr;
if (argaddr(0, &addr) < 0)
return -1;
struct dirent *de = myproc()->cwd;
char path[MAXPATH];
char *s;
int len;
if (de->parent == 0) {
s = "/";
} else {
s = path + MAXPATH - 1;
*s-- = '\0';
while (de->parent) {
len = strlen(de->filename);
s -= len;
if (s <= path) // can't reach root "/"
return -1;
strncpy(s, de->filename, len);
*--s = '/';
de = de->parent;
}
}
if (copyout(myproc()->pagetable, addr, s, strlen(s) + 1) < 0)
return -1;
return 0;
}

View File

@ -1,37 +1,31 @@
#include "kernel/include/types.h"
#include "kernel/include/stat.h"
#include "xv6-user/user.h"
// #include "kernel/include/fs.h"
#include "kernel/include/fat32.h"
#define FILENAME_LENGTH 32
char*
fmtname(char *path)
fmtname(char *name)
{
static char buf[FILENAME_LENGTH+1];
char *p;
// Find first character after last slash.
for(p=path+strlen(path); p >= path && *p != '/'; p--)
;
p++;
static char buf[STAT_MAX_NAME+1];
int len = strlen(name);
// Return blank-padded name.
if(strlen(p) >= FILENAME_LENGTH)
return p;
memmove(buf, p, strlen(p));
memset(buf+strlen(p), ' ', FILENAME_LENGTH-strlen(p));
if(len >= STAT_MAX_NAME)
return name;
memmove(buf, name, len);
memset(buf + len, ' ', STAT_MAX_NAME - len);
buf[STAT_MAX_NAME] = '\0';
return buf;
}
void
ls(char *path)
{
char buf[512], *p;
int fd;
// struct dirent de;
struct stat st;
char *types[] = {
[T_DIR] "DIR ",
[T_FILE] "FILE",
};
if((fd = open(path, 0)) < 0){
fprintf(2, "ls: cannot open %s\n", path);
@ -44,30 +38,12 @@ ls(char *path)
return;
}
if (st.attribute == ATTR_DIRECTORY){
if(strlen(path) + 1 + FILENAME_LENGTH + 1 > sizeof buf){
printf("ls: path too long\n");
}
strcpy(buf, path);
p = buf+strlen(buf);
*p++ = '/';
// CAN'T WORK NOW
while(read(fd, &de, sizeof(de)) == sizeof(de)){
// if(de.inum == 0)
// continue;
// memmove(p, de.name, FILENAME_LENGTH);
// p[DIRSIZ] = 0;
if(stat(buf, &st) < 0){
printf("ls: cannot stat %s\n", buf);
continue;
}
printf("%s %d %d\n", fmtname(buf), st.attribute, st.size);
if (st.type == T_DIR){
while(dir(fd, &st) == 1){
printf("%s %s\t%d\n", fmtname(st.name), types[st.type], st.size);
}
} else {
printf("%s %d %l\n", fmtname(path), st.attribute, st.size);
printf("%s %s\t%l\n", fmtname(st.name), types[st.type], st.size);
}
close(fd);
}

View File

@ -133,7 +133,14 @@ runcmd(struct cmd *cmd)
int
getcmd(char *buf, int nbuf)
{
fprintf(2, "$ ");
#ifndef QEMU
static char pf[] = "xv6-k210";
#else
static char pf[] = "xv6-qemu";
#endif
char cur[128];
getcwd(cur);
fprintf(2, "%s@%s$ ", pf, cur);
memset(buf, 0, nbuf);
gets(buf, nbuf);
if(buf[0] == 0) // EOF
@ -148,7 +155,7 @@ main(void)
int fd;
// Ensure that three file descriptors are open.
while((fd = open("console", O_RDWR)) >= 0){
while((fd = dev(O_RDWR, 1, 0)) >= 0){
if(fd >= 3){
close(fd);
break;

View File

@ -25,6 +25,8 @@ int sleep(int);
int uptime(void);
int test_proc(void);
int dev(int, short, short);
int dir(int fd, struct stat*);
int getcwd(char *);
// ulib.c
int stat(const char*, struct stat*);

View File

@ -38,3 +38,5 @@ entry("sleep");
entry("uptime");
entry("test_proc");
entry("dev");
entry("dir");
entry("getcwd");