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 := k210
# platform := qemu
K=kernel K=kernel
U=xv6-user U=xv6-user
T=target T=target
@ -179,14 +180,14 @@ UPROGS=\
$U/_init\ $U/_init\
$U/_sh\ $U/_sh\
$U/_cat\ $U/_cat\
$U/_echo\
$U/_grep\
$U/_ls\
$U/_test $U/_test
# $U/_echo\
# $U/_forktest\ # $U/_forktest\
# $U/_grep\
# $U/_kill\ # $U/_kill\
# $U/_ln\ # $U/_ln\
# $U/_ls\
# $U/_mkdir\ # $U/_mkdir\
# $U/_rm\ # $U/_rm\
# $U/_stressfs\ # $U/_stressfs\

View File

@ -62,7 +62,7 @@ Besides, file system and uesr programs are available on qemu. More details [here
```bash ```bash
$ dd if=/dev/zero of=fs.img bs=512k count=2048 $ dd if=/dev/zero of=fs.img bs=512k count=2048
$ mkfs.vfat -F 32 fs.img $ mkfs.vfat -F 32 fs.img
$ make fs $ make build
$ (sudo)mount fs.img /mnt $ (sudo)mount fs.img /mnt
$ (sudo)cp xv6-user/_init /mnt/init $ (sudo)cp xv6-user/_init /mnt/init
$ (sudo)cp xv6-user/_sh /mnt $ (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. 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 ## Progress
- [x] Multicore boot - [x] Multicore boot

View File

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

View File

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

View File

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

View File

@ -72,12 +72,17 @@ int fat32_init()
initlock(&ecache.lock, "ecache"); initlock(&ecache.lock, "ecache");
memset(&root, 0, sizeof(root)); memset(&root, 0, sizeof(root));
initsleeplock(&root.lock, "entry"); initsleeplock(&root.lock, "entry");
root.attribute = ATTR_DIRECTORY; root.attribute = (ATTR_DIRECTORY | ATTR_SYSTEM);
root.first_clus = fat.bpb.root_clus; root.first_clus = root.cur_clus = fat.bpb.root_clus;
root.valid = 1;
root.prev = &root; root.prev = &root;
root.next = &root; root.next = &root;
for(struct dirent *de = ecache.entries; de < ecache.entries + ENTRY_CACHE_NUM; de++) { for(struct dirent *de = ecache.entries; de < ecache.entries + ENTRY_CACHE_NUM; de++) {
de->dev = 0;
de->valid = 0; de->valid = 0;
de->ref = 0;
de->dirty = 0;
de->parent = 0;
de->next = root.next; de->next = root.next;
de->prev = &root; de->prev = &root;
initsleeplock(&de->lock, "entry"); 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. // should we keep a free cluster list? instead of searching fat every time.
struct buf *b; struct buf *b;
uint32 sec = fat.bpb.rsvd_sec_cnt; uint32 sec = fat.bpb.rsvd_sec_cnt;
uint32 const ent_per_sec = fat.bpb.byts_per_sec / sizeof(uint32); uint32 const ent_per_sec = fat.bpb.byts_per_sec / sizeof(uint32);
for (uint32 i = 0; i < fat.bpb.fat_sz; i++, sec++) { 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++) { for (uint32 j = 0; j < ent_per_sec; j++) {
if (((uint32 *)(b->data))[j] == 0) { if (((uint32 *)(b->data))[j] == 0) {
((uint32 *)(b->data))[j] = FAT32_EOC + 7; ((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; 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" */ /* 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) 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; return 0;
} }
if (off + n > entry->file_size) { if (off + n > entry->file_size) {
n = entry->file_size - off; 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; 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; m = fat.byts_per_clus - off % fat.byts_per_clus;
if (n - tot < m) { if (n - tot < m) {
m = n - tot; 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; break;
} }
cluster = read_fat(cluster);
} }
return tot; 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. // Caller must hold entry->lock.
int ewrite(struct dirent *entry, int user_src, uint64 src, uint off, uint n) 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; return -1;
} }
int clus_num = off / fat.byts_per_clus; if (entry->first_clus == 0) { // so file_size if 0 too, which requests off == 0
off = off % fat.byts_per_clus; entry->cur_clus = entry->first_clus = alloc_clus(entry->dev);
if (entry->first_clus == 0) { entry->clus_cnt = 0;
entry->first_clus = alloc_clus(); entry->dirty = 1;
eupdate(entry);
}
uint32 cluster = entry->first_clus;
while (clus_num-- > 0) {
cluster = read_fat(cluster);
} }
uint tot, m; uint tot, m;
for (tot = 0; tot < n; tot += m, off += m, src += 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); 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; m = fat.byts_per_clus - off % fat.byts_per_clus;
if (n - tot < m) { if (n - tot < m) {
m = n - tot; 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; break;
} }
cluster = read_fat(cluster);
} }
if(n > 0) { if(n > 0) {
if(off > entry->file_size) { if(off > entry->file_size) {
entry->file_size = off; entry->file_size = off;
entry->dirty = 1;
eupdate(entry); 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 // 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; struct dirent *ep;
acquire(&ecache.lock); acquire(&ecache.lock);
for (ep = root.next; ep != &root; ep = ep->next) { if (name) {
if (ep->dev == dev && ep->parent == parent for (ep = root.next; ep != &root; ep = ep->next) {
&& strncmp(ep->filename, name, FAT32_MAX_FILENAME) == 0) { if (ep->parent == parent && strncmp(ep->filename, name, FAT32_MAX_FILENAME) == 0) {
ep->ref++; ep->ref++;
ep->valid = 1; ep->valid = 1;
release(&ecache.lock); release(&ecache.lock);
return ep; edup(ep->parent);
return ep;
}
} }
} }
for (ep = root.prev; ep != &root; ep = ep->prev) { for (ep = root.prev; ep != &root; ep = ep->prev) {
if (ep->ref == 0) { if (ep->ref == 0) {
ep->ref = 1; ep->ref = 1;
ep->dev = dev; ep->dev = parent->dev;
ep->off = 0; ep->off = 0;
ep->valid = 0; ep->valid = 0;
release(&ecache.lock); 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) 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; struct dirent *ep;
uint off = 0; uint off = 0;
ep = dirlookup(dp, name, &off); ep = dirlookup(dp, name, &off);
if (ep != 0) { // entry exists if (ep != 0) { // entry exists
eput(ep);
return 0; return 0;
} }
ep = eget(dp->dev, dp->parent, name); ep = eget(dp, name);
if (ep->valid) { // shouldn't be valid if (ep->valid) { // shouldn't be valid
panic("ealloc"); panic("ealloc");
} }
@ -349,39 +372,36 @@ struct dirent *ealloc(struct dirent *dp, char *name, int dir)
ep->attribute = 0; ep->attribute = 0;
ep->file_size = 0; ep->file_size = 0;
ep->first_clus = 0; ep->first_clus = 0;
ep->parent = dp->first_clus; ep->parent = edup(dp);
ep->off = off; ep->off = off;
ep->clus_cnt = 0;
ep->cur_clus = 0;
strncpy(ep->filename, name, FAT32_MAX_FILENAME); strncpy(ep->filename, name, FAT32_MAX_FILENAME);
int len = strlen(name); int len = strlen(name);
int entcnt = (len + CHAR_LONG_NAME - 1) / CHAR_LONG_NAME; // count of l-n-entries, rounds up 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}; uint8 ebuf[32] = {0};
if(dir){ // generate "." and ".." for ep if(dir){ // generate "." and ".." for ep
ep->attribute |= ATTR_DIRECTORY; ep->attribute |= ATTR_DIRECTORY;
ep->first_clus = alloc_clus(); ep->cur_clus = ep->first_clus = alloc_clus(dp->dev);
strncpy((char *)ebuf, ".", 11); strncpy((char *)ebuf, ".", 11);
ebuf[11] = ATTR_DIRECTORY; ebuf[11] = ATTR_DIRECTORY;
*(uint16 *)(ebuf + 20) = (uint16)(ep->first_clus >> 16); *(uint16 *)(ebuf + 20) = (uint16)(ep->first_clus >> 16);
*(uint16 *)(ebuf + 26) = (uint16)(ep->first_clus & 0xff); *(uint16 *)(ebuf + 26) = (uint16)(ep->first_clus & 0xff);
*(uint32 *)(ebuf + 28) = 0; *(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); strncpy((char *)ebuf, "..", 11);
ebuf[11] = ATTR_DIRECTORY; ebuf[11] = ATTR_DIRECTORY;
*(uint16 *)(ebuf + 20) = (uint16)(dp->first_clus >> 16); *(uint16 *)(ebuf + 20) = (uint16)(dp->first_clus >> 16);
*(uint16 *)(ebuf + 26) = (uint16)(dp->first_clus & 0xff); *(uint16 *)(ebuf + 26) = (uint16)(dp->first_clus & 0xff);
*(uint32 *)(ebuf + 28) = 0; *(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 { } else {
ep->attribute |= ATTR_ARCHIVE; ep->attribute |= ATTR_ARCHIVE;
} }
memset(ebuf, 0, sizeof(ebuf)); memset(ebuf, 0, sizeof(ebuf));
off = reloc_clus(dp, off);
for (uint8 i = entcnt; i > 0; i--) { // ignore checksum for (uint8 i = entcnt; i > 0; i--) { // ignore checksum
ebuf[0] = i; ebuf[0] = i;
if (i == entcnt) { 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 + 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 + 14), ep->filename + i * CHAR_LONG_NAME + 5, 6);
wnstr_lazy((wchar *) (ebuf + 28), ep->filename + i * CHAR_LONG_NAME + 11, 2); wnstr_lazy((wchar *) (ebuf + 28), ep->filename + i * CHAR_LONG_NAME + 11, 2);
rw_clus(clus, 1, 0, (uint64)ebuf, off, sizeof(ebuf)); rw_clus(dp->cur_clus, 1, 0, (uint64)ebuf, off, sizeof(ebuf));
off += 32; off = reloc_clus(dp, off + 32);
if (off >= fat.byts_per_clus) {
clus = read_fat(clus);
off -= fat.byts_per_clus;
}
} }
ep->dirty = 1;
eupdate(ep); eupdate(ep);
ep->valid = 1; ep->valid = 1;
eunlock(ep); eunlock(ep);
@ -409,17 +426,20 @@ struct dirent *ealloc(struct dirent *dp, char *name, int dir)
struct dirent *edup(struct dirent *entry) struct dirent *edup(struct dirent *entry)
{ {
acquire(&ecache.lock); if (entry != 0) {
entry->ref++; acquire(&ecache.lock);
release(&ecache.lock); entry->ref++;
release(&ecache.lock);
}
return entry; return entry;
} }
// only update file size
void eupdate(struct dirent *entry) void eupdate(struct dirent *entry)
{ {
if (!entry->dirty) { return; }
printf("[eupdate] %s\n", entry->filename);
uint entcnt; uint entcnt;
uint32 clus = entry->parent; uint32 clus = entry->parent->first_clus;
uint32 off = entry->off % fat.byts_per_clus; uint32 off = entry->off % fat.byts_per_clus;
for (uint clus_cnt = entry->off / fat.byts_per_clus; clus_cnt > 0; clus_cnt--) { for (uint clus_cnt = entry->off / fat.byts_per_clus; clus_cnt > 0; clus_cnt--) {
clus = read_fat(clus); 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_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) &clus_low, off + 26, sizeof(clus_low));
rw_clus(clus, 1, 0, (uint64) &entry->file_size, off + 28, sizeof(entry->file_size)); rw_clus(clus, 1, 0, (uint64) &entry->file_size, off + 28, sizeof(entry->file_size));
entry->dirty = 0;
} }
void etrunc(struct dirent *entry) void etrunc(struct dirent *entry)
{ {
uint entcnt; uint entcnt;
uint32 clus = entry->parent; uint32 clus = entry->parent->first_clus;
uint32 off = entry->off % fat.byts_per_clus; uint32 off = entry->off % fat.byts_per_clus;
for (uint clus_cnt = entry->off / fat.byts_per_clus; clus_cnt > 0; clus_cnt--) { for (uint clus_cnt = entry->off / fat.byts_per_clus; clus_cnt > 0; clus_cnt--) {
clus = read_fat(clus); clus = read_fat(clus);
@ -496,6 +517,7 @@ void eput(struct dirent *entry)
root.next->prev = entry; root.next->prev = entry;
root.next = entry; root.next = entry;
eupdate(entry); eupdate(entry);
eput(entry->parent);
} }
releasesleep(&entry->lock); releasesleep(&entry->lock);
acquire(&ecache.lock); acquire(&ecache.lock);
@ -506,7 +528,8 @@ void eput(struct dirent *entry)
void estat(struct dirent *entry, struct stat *st) 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->dev = entry->dev;
st->size = entry->file_size; 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 = ((uint32) *(uint16 *)(raw_entry + 20)) << 16;
entry->first_clus += *(uint16 *)(raw_entry + 26); entry->first_clus += *(uint16 *)(raw_entry + 26);
entry->file_size = *(uint32 *)(raw_entry + 28); 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) struct dirent *dirlookup(struct dirent *entry, char *filename, uint *poff)
{ {
if (entry->attribute != ATTR_DIRECTORY) if (!(entry->attribute & ATTR_DIRECTORY))
panic("dirlookup not DIR"); panic("dirlookup not DIR");
if (strncmp(filename, ".", FAT32_MAX_FILENAME) == 0) {
struct dirent *de = eget(entry->dev, entry->first_clus, filename); 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 if (de->valid) { return de; } // ecache hits
uint8 ebuf[32];
char name[CHAR_LONG_NAME];
int len = strlen(filename); int len = strlen(filename);
int entcnt = (len + CHAR_LONG_NAME - 1) / CHAR_LONG_NAME; // count of l-n-entries, rounds up int entcnt = (len + CHAR_LONG_NAME - 1) / CHAR_LONG_NAME + 1; // count of l-n-entries, rounds up
uint32 cluster = entry->first_clus; int count = 0;
uint clus_cnt = 0; int type;
uint off = 0; uint off = reloc_clus(entry, 0);
int match = 0;
int first = 1; while ((type = enext(entry, de, off, &count) != -1)) {
int empty_cnt = entcnt; if (type == 0) {
if (poff && count >= entcnt) {
while (cluster < FAT32_EOC) { *poff = off;
while (off < fat.byts_per_clus) { poff = 0;
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;
} }
} 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; off = reloc_clus(entry, off + count * 32);
cluster = read_fat(cluster);
clus_cnt++;
} }
miss:
if (poff) { if (poff) {
*poff = clus_cnt * fat.byts_per_clus + off; *poff = off;
} }
eput(de); eput(de);
return 0; return 0;
@ -683,7 +710,7 @@ static struct dirent *lookup_path(char *path, int parent, char *name)
} }
while ((path = skipelem(path, name)) != 0) { while ((path = skipelem(path, name)) != 0) {
elock(entry); elock(entry);
if (entry->attribute != ATTR_DIRECTORY) { if (!(entry->attribute & ATTR_DIRECTORY)) {
eunlock(entry); eunlock(entry);
eput(entry); eput(entry);
return 0; return 0;

View File

@ -77,8 +77,10 @@ fileclose(struct file *f)
if(ff.type == FD_PIPE){ if(ff.type == FD_PIPE){
pipeclose(ff.pipe, ff.writable); pipeclose(ff.pipe, ff.writable);
} else if(ff.type == FD_ENTRY || ff.type == FD_DEVICE){ } else if(ff.type == FD_ENTRY){
eput(ff.ep); eput(ff.ep);
} else if (ff.type == FD_DEVICE) {
} }
} }
@ -90,7 +92,7 @@ filestat(struct file *f, uint64 addr)
struct proc *p = myproc(); struct proc *p = myproc();
struct stat st; struct stat st;
if(f->type == FD_ENTRY || f->type == FD_DEVICE){ if(f->type == FD_ENTRY){
elock(f->ep); elock(f->ep);
estat(f->ep, &st); estat(f->ep, &st);
eunlock(f->ep); eunlock(f->ep);
@ -111,19 +113,23 @@ fileread(struct file *f, uint64 addr, int n)
if(f->readable == 0) if(f->readable == 0)
return -1; return -1;
if(f->type == FD_PIPE){ switch (f->type) {
r = piperead(f->pipe, addr, n); case FD_PIPE:
} else if(f->type == FD_DEVICE){ r = piperead(f->pipe, addr, n);
if(f->major < 0 || f->major >= NDEV || !devsw[f->major].read) break;
return -1; case FD_DEVICE:
r = devsw[f->major].read(1, addr, n); if(f->major < 0 || f->major >= NDEV || !devsw[f->major].read)
} else if(f->type == FD_ENTRY){ return -1;
elock(f->ep); r = devsw[f->major].read(1, addr, n);
if((r = eread(f->ep, 1, addr, f->off, n)) > 0) break;
f->off += r; case FD_ENTRY:
eunlock(f->ep); elock(f->ep);
} else { if((r = eread(f->ep, 1, addr, f->off, n)) > 0)
panic("fileread"); f->off += r;
eunlock(f->ep);
break;
default:
panic("fileread");
} }
return r; return r;
@ -161,3 +167,33 @@ filewrite(struct file *f, uint64 addr, int n)
return ret; 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 estat(struct dirent *ep, struct stat *st);
void elock(struct dirent *entry); void elock(struct dirent *entry);
void eunlock(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* ename(char *path);
struct dirent* enameparent(char *path, char *name); struct dirent* enameparent(char *path, char *name);
int eread(struct dirent *entry, int user_dst, uint64 dst, uint off, uint n); 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 fileread(struct file*, uint64, int n);
int filestat(struct file*, uint64 addr); int filestat(struct file*, uint64 addr);
int filewrite(struct file*, uint64, int n); int filewrite(struct file*, uint64, int n);
int dirnext(struct file *f, uint64 addr);
// fs.c // fs.c
// void fsinit(int); // void fsinit(int);

View File

@ -28,12 +28,16 @@ struct dirent {
// uint16 last_write_date; // uint16 last_write_date;
uint32 file_size; uint32 file_size;
uint32 cur_clus;
uint clus_cnt;
/* for OS */ /* for OS */
uint dev; uint8 dev;
int valid; uint8 dirty;
uint8 valid;
int ref; 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 *next;
struct dirent *prev; struct dirent *prev;
struct sleeplock lock; struct sleeplock lock;

View File

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

View File

@ -22,3 +22,5 @@
#define SYS_close 21 #define SYS_close 21
#define SYS_test_proc 22 #define SYS_test_proc 22
#define SYS_dev 23 #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); eput(p->cwd);
// end_op();
p->cwd = 0; p->cwd = 0;
// we might re-parent a child to init. we can't be precise about // 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); *dst++ = (uchar)(*src & 0xff);
src ++; src ++;
} }
while(len-- > 0)
*dst = 0; *dst++ = 0;
} }
int wcsncmp(wchar const *s1, wchar const *s2, int len) { 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_uptime(void);
extern uint64 sys_test_proc(void); extern uint64 sys_test_proc(void);
extern uint64 sys_dev(void); extern uint64 sys_dev(void);
extern uint64 sys_dir(void);
extern uint64 sys_getcwd(void);
static uint64 (*syscalls[])(void) = { static uint64 (*syscalls[])(void) = {
[SYS_fork] sys_fork, [SYS_fork] sys_fork,
@ -133,6 +135,8 @@ static uint64 (*syscalls[])(void) = {
[SYS_close] sys_close, [SYS_close] sys_close,
[SYS_test_proc] sys_test_proc, [SYS_test_proc] sys_test_proc,
[SYS_dev] sys_dev, [SYS_dev] sys_dev,
[SYS_dir] sys_dir,
[SYS_getcwd] sys_getcwd,
}; };
void void

View File

@ -144,16 +144,8 @@ create(char *path, short type)
return 0; return 0;
elock(dp); 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) if((ep = ealloc(dp, name, type == T_DIR)) == 0)
panic("create: ialloc"); return 0;
elock(ep); elock(ep);
@ -186,7 +178,7 @@ sys_open(void)
return -1; return -1;
} }
elock(ep); elock(ep);
if(ep->attribute == ATTR_DIRECTORY && omode != O_RDONLY){ if((ep->attribute & ATTR_DIRECTORY) && omode != O_RDONLY){
eunlock(ep); eunlock(ep);
eput(ep); eput(ep);
return -1; return -1;
@ -265,7 +257,7 @@ sys_chdir(void)
return -1; return -1;
} }
elock(ep); elock(ep);
if(ep->attribute != ATTR_DIRECTORY){ if(!(ep->attribute & ATTR_DIRECTORY)){
eunlock(ep); eunlock(ep);
eput(ep); eput(ep);
return -1; return -1;
@ -349,6 +341,7 @@ sys_pipe(void)
return 0; return 0;
} }
// To open console device.
uint64 uint64
sys_dev(void) sys_dev(void)
{ {
@ -381,4 +374,52 @@ sys_dev(void)
f->writable = (omode & O_WRONLY) || (omode & O_RDWR); f->writable = (omode & O_WRONLY) || (omode & O_RDWR);
return fd; 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/types.h"
#include "kernel/include/stat.h" #include "kernel/include/stat.h"
#include "xv6-user/user.h" #include "xv6-user/user.h"
// #include "kernel/include/fs.h"
#include "kernel/include/fat32.h"
#define FILENAME_LENGTH 32
char* char*
fmtname(char *path) fmtname(char *name)
{ {
static char buf[FILENAME_LENGTH+1]; static char buf[STAT_MAX_NAME+1];
char *p; int len = strlen(name);
// Find first character after last slash.
for(p=path+strlen(path); p >= path && *p != '/'; p--)
;
p++;
// Return blank-padded name. // Return blank-padded name.
if(strlen(p) >= FILENAME_LENGTH) if(len >= STAT_MAX_NAME)
return p; return name;
memmove(buf, p, strlen(p)); memmove(buf, name, len);
memset(buf+strlen(p), ' ', FILENAME_LENGTH-strlen(p)); memset(buf + len, ' ', STAT_MAX_NAME - len);
buf[STAT_MAX_NAME] = '\0';
return buf; return buf;
} }
void void
ls(char *path) ls(char *path)
{ {
char buf[512], *p;
int fd; int fd;
// struct dirent de;
struct stat st; struct stat st;
char *types[] = {
[T_DIR] "DIR ",
[T_FILE] "FILE",
};
if((fd = open(path, 0)) < 0){ if((fd = open(path, 0)) < 0){
fprintf(2, "ls: cannot open %s\n", path); fprintf(2, "ls: cannot open %s\n", path);
@ -44,30 +38,12 @@ ls(char *path)
return; return;
} }
if (st.attribute == ATTR_DIRECTORY){ if (st.type == T_DIR){
while(dir(fd, &st) == 1){
if(strlen(path) + 1 + FILENAME_LENGTH + 1 > sizeof buf){ printf("%s %s\t%d\n", fmtname(st.name), types[st.type], st.size);
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);
} }
} else { } 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); close(fd);
} }

View File

@ -133,7 +133,14 @@ runcmd(struct cmd *cmd)
int int
getcmd(char *buf, int nbuf) 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); memset(buf, 0, nbuf);
gets(buf, nbuf); gets(buf, nbuf);
if(buf[0] == 0) // EOF if(buf[0] == 0) // EOF
@ -148,7 +155,7 @@ main(void)
int fd; int fd;
// Ensure that three file descriptors are open. // 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){ if(fd >= 3){
close(fd); close(fd);
break; break;

View File

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

View File

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