support the "ls" command
This commit is contained in:
parent
ee2ee8469e
commit
c8ad18ca00
7
Makefile
7
Makefile
|
@ -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\
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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] 多核启动
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
265
kernel/fat32.c
265
kernel/fat32.c
|
@ -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);
|
||||||
|
if (name) {
|
||||||
for (ep = root.next; ep != &root; ep = ep->next) {
|
for (ep = root.next; ep != &root; ep = ep->next) {
|
||||||
if (ep->dev == dev && ep->parent == parent
|
if (ep->parent == parent && strncmp(ep->filename, name, FAT32_MAX_FILENAME) == 0) {
|
||||||
&& strncmp(ep->filename, name, FAT32_MAX_FILENAME) == 0) {
|
|
||||||
ep->ref++;
|
ep->ref++;
|
||||||
ep->valid = 1;
|
ep->valid = 1;
|
||||||
release(&ecache.lock);
|
release(&ecache.lock);
|
||||||
|
edup(ep->parent);
|
||||||
return ep;
|
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)
|
||||||
{
|
{
|
||||||
|
if (entry != 0) {
|
||||||
acquire(&ecache.lock);
|
acquire(&ecache.lock);
|
||||||
entry->ref++;
|
entry->ref++;
|
||||||
release(&ecache.lock);
|
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;
|
|
||||||
int empty_cnt = entcnt;
|
|
||||||
|
|
||||||
while (cluster < FAT32_EOC) {
|
while ((type = enext(entry, de, off, &count) != -1)) {
|
||||||
while (off < fat.byts_per_clus) {
|
if (type == 0) {
|
||||||
if (rw_clus(cluster, 0, 0, (uint64)ebuf, off, 32) != 32 || ebuf[0] == END_OF_ENTRY) {
|
if (poff && count >= entcnt) {
|
||||||
goto miss;
|
*poff = off;
|
||||||
}
|
|
||||||
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;
|
poff = 0;
|
||||||
}
|
}
|
||||||
}
|
} else if (strncmp(filename, de->filename, FAT32_MAX_FILENAME) == 0) {
|
||||||
off += 32;
|
de->parent = edup(entry);
|
||||||
continue;
|
de->off = off;
|
||||||
} 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;
|
de->valid = 1;
|
||||||
return de;
|
return de;
|
||||||
}
|
}
|
||||||
|
off = reloc_clus(entry, off + count * 32);
|
||||||
}
|
}
|
||||||
off -= fat.byts_per_clus;
|
|
||||||
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;
|
||||||
|
|
|
@ -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,18 +113,22 @@ 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) {
|
||||||
|
case FD_PIPE:
|
||||||
r = piperead(f->pipe, addr, n);
|
r = piperead(f->pipe, addr, n);
|
||||||
} else if(f->type == FD_DEVICE){
|
break;
|
||||||
|
case FD_DEVICE:
|
||||||
if(f->major < 0 || f->major >= NDEV || !devsw[f->major].read)
|
if(f->major < 0 || f->major >= NDEV || !devsw[f->major].read)
|
||||||
return -1;
|
return -1;
|
||||||
r = devsw[f->major].read(1, addr, n);
|
r = devsw[f->major].read(1, addr, n);
|
||||||
} else if(f->type == FD_ENTRY){
|
break;
|
||||||
|
case FD_ENTRY:
|
||||||
elock(f->ep);
|
elock(f->ep);
|
||||||
if((r = eread(f->ep, 1, addr, f->off, n)) > 0)
|
if((r = eread(f->ep, 1, addr, f->off, n)) > 0)
|
||||||
f->off += r;
|
f->off += r;
|
||||||
eunlock(f->ep);
|
eunlock(f->ep);
|
||||||
} else {
|
break;
|
||||||
|
default:
|
||||||
panic("fileread");
|
panic("fileread");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
}
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -382,3 +375,51 @@ sys_dev(void)
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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*);
|
||||||
|
|
|
@ -38,3 +38,5 @@ entry("sleep");
|
||||||
entry("uptime");
|
entry("uptime");
|
||||||
entry("test_proc");
|
entry("test_proc");
|
||||||
entry("dev");
|
entry("dev");
|
||||||
|
entry("dir");
|
||||||
|
entry("getcwd");
|
||||||
|
|
Loading…
Reference in New Issue