support the "ls" command
This commit is contained in:
parent
ee2ee8469e
commit
c8ad18ca00
7
Makefile
7
Makefile
|
@ -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\
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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] 多核启动
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
289
kernel/fat32.c
289
kernel/fat32.c
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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*);
|
||||
|
|
|
@ -38,3 +38,5 @@ entry("sleep");
|
|||
entry("uptime");
|
||||
entry("test_proc");
|
||||
entry("dev");
|
||||
entry("dir");
|
||||
entry("getcwd");
|
||||
|
|
Loading…
Reference in New Issue