問題一:我們的系統每次啟動都是「全新」的,上次建立的文件到下一次啟動就不見了。
問題二:每次都會執行一次解開 cmd.tar 的操作。
問題三:再一次解壓縮時,可能已有包含的檔案了
問題二:每次都會執行一次解開 cmd.tar 的操作。
問題三:再一次解壓縮時,可能已有包含的檔案了
讓 mkfs() 只執行一次
fs/main.c
/*************************************************************************//**
*****************************************************************************
* @file main.c
* @brief
* @author Forrest Y. Yu
* @date 2007
*****************************************************************************
*****************************************************************************/
#include "type.h"
#include "config.h"
#include "stdio.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "fs.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "proto.h"
#include "hd.h"
PRIVATE void init_fs();
PRIVATE void mkfs();
PRIVATE void read_super_block(int dev);
PRIVATE int fs_fork();
PRIVATE int fs_exit();
/*****************************************************************************
* task_fs
*****************************************************************************/
/**
* <Ring 1> The main loop of TASK FS.
*
*****************************************************************************/
PUBLIC void task_fs()
{
printl("{FS} Task FS begins.\n");
init_fs();
while (1) {
send_recv(RECEIVE, ANY, &fs_msg);
int msgtype = fs_msg.type;
int src = fs_msg.source;
pcaller = &proc_table[src];
switch (msgtype) {
case OPEN:
fs_msg.FD = do_open();
break;
case CLOSE:
fs_msg.RETVAL = do_close();
break;
case READ:
case WRITE:
fs_msg.CNT = do_rdwt();
break;
case UNLINK:
fs_msg.RETVAL = do_unlink();
break;
case RESUME_PROC:
src = fs_msg.PROC_NR;
break;
case FORK:
fs_msg.RETVAL = fs_fork();
break;
case EXIT:
fs_msg.RETVAL = fs_exit();
break;
case LSEEK:
fs_msg.OFFSET = do_lseek();
break;
case STAT:
fs_msg.RETVAL = do_stat();
break;
default:
dump_msg("FS::unknown message:", &fs_msg);
assert(0);
break;
}
#ifdef ENABLE_DISK_LOG
char * msg_name[128];
msg_name[OPEN] = "OPEN";
msg_name[CLOSE] = "CLOSE";
msg_name[READ] = "READ";
msg_name[WRITE] = "WRITE";
msg_name[LSEEK] = "LSEEK";
msg_name[UNLINK] = "UNLINK";
msg_name[FORK] = "FORK";
msg_name[EXIT] = "EXIT";
msg_name[STAT] = "STAT";
switch (msgtype) {
case UNLINK:
dump_fd_graph("%s just finished. (pid:%d)",
msg_name[msgtype], src);
//panic("");
case OPEN:
case CLOSE:
case READ:
case WRITE:
case FORK:
case EXIT:
case LSEEK:
case STAT:
break;
case RESUME_PROC:
break;
default:
assert(0);
}
#endif
/* reply */
if (fs_msg.type != SUSPEND_PROC) {
fs_msg.type = SYSCALL_RET;
send_recv(SEND, src, &fs_msg);
}
}
}
/*****************************************************************************
* init_fs
*****************************************************************************/
/**
* <Ring 1> Do some preparation.
*
*****************************************************************************/
PRIVATE void init_fs()
{
int i;
/* f_desc_table[] */
for (i = 0; i < NR_FILE_DESC; i++)
memset(&f_desc_table[i], 0, sizeof(struct file_desc));
/* inode_table[] */
for (i = 0; i < NR_INODE; i++)
memset(&inode_table[i], 0, sizeof(struct inode));
/* super_block[] */
struct super_block * sb = super_block;
for (; sb < &super_block[NR_SUPER_BLOCK]; sb++)
sb->sb_dev = NO_DEV;
/* open the device: hard disk */
MESSAGE driver_msg;
driver_msg.type = DEV_OPEN;
driver_msg.DEVICE = MINOR(ROOT_DEV);
assert(dd_map[MAJOR(ROOT_DEV)].driver_nr != INVALID_DRIVER);
send_recv(BOTH, dd_map[MAJOR(ROOT_DEV)].driver_nr, &driver_msg);
/* read the super block of ROOT DEVICE */
RD_SECT(ROOT_DEV, 1);
sb = (struct super_block *)fsbuf;
if (sb->magic != MAGIC_V1) {
printl("{FS} mkfs\n");
mkfs(); /* make FS */
}
/* load super block of ROOT */
read_super_block(ROOT_DEV);
sb = get_super_block(ROOT_DEV);
assert(sb->magic == MAGIC_V1);
root_inode = get_inode(ROOT_DEV, ROOT_INODE);
}
/*****************************************************************************
* mkfs
*****************************************************************************/
/**
* <Ring 1> Make a available Orange'S FS in the disk. It will
* - Write a super block to sector 1.
* - Create three special files: dev_tty0, dev_tty1, dev_tty2
* - Create a file cmd.tar
* - Create the inode map
* - Create the sector map
* - Create the inodes of the files
* - Create `/', the root directory
*****************************************************************************/
PRIVATE void mkfs()
{
MESSAGE driver_msg;
int i, j;
/************************/
/* super block */
/************************/
/* get the geometry of ROOTDEV */
struct part_info geo;
driver_msg.type = DEV_IOCTL;
driver_msg.DEVICE = MINOR(ROOT_DEV);
driver_msg.REQUEST = DIOCTL_GET_GEO;
driver_msg.BUF = &geo;
driver_msg.PROC_NR = TASK_FS;
assert(dd_map[MAJOR(ROOT_DEV)].driver_nr != INVALID_DRIVER);
send_recv(BOTH, dd_map[MAJOR(ROOT_DEV)].driver_nr, &driver_msg);
printl("{FS} dev size: 0x%x sectors\n", geo.size);
int bits_per_sect = SECTOR_SIZE * 8; /* 8 bits per byte */
/* generate a super block */
struct super_block sb;
sb.magic = MAGIC_V1; /* 0x111 */
sb.nr_inodes = bits_per_sect;
sb.nr_inode_sects = sb.nr_inodes * INODE_SIZE / SECTOR_SIZE;
sb.nr_sects = geo.size; /* partition size in sector */
sb.nr_imap_sects = 1;
sb.nr_smap_sects = sb.nr_sects / bits_per_sect + 1;
sb.n_1st_sect = 1 + 1 + /* boot sector & super block */
sb.nr_imap_sects + sb.nr_smap_sects + sb.nr_inode_sects;
sb.root_inode = ROOT_INODE;
sb.inode_size = INODE_SIZE;
struct inode x;
sb.inode_isize_off= (int)&x.i_size - (int)&x;
sb.inode_start_off= (int)&x.i_start_sect - (int)&x;
sb.dir_ent_size = DIR_ENTRY_SIZE;
struct dir_entry de;
sb.dir_ent_inode_off = (int)&de.inode_nr - (int)&de;
sb.dir_ent_fname_off = (int)&de.name - (int)&de;
memset(fsbuf, 0x90, SECTOR_SIZE);
memcpy(fsbuf, &sb, SUPER_BLOCK_SIZE);
/* write the super block */
WR_SECT(ROOT_DEV, 1);
printl("{FS} devbase:0x%x00, sb:0x%x00, imap:0x%x00, smap:0x%x00\n"
" inodes:0x%x00, 1st_sector:0x%x00\n",
geo.base * 2,
(geo.base + 1) * 2,
(geo.base + 1 + 1) * 2,
(geo.base + 1 + 1 + sb.nr_imap_sects) * 2,
(geo.base + 1 + 1 + sb.nr_imap_sects + sb.nr_smap_sects) * 2,
(geo.base + sb.n_1st_sect) * 2);
/************************/
/* inode map */
/************************/
memset(fsbuf, 0, SECTOR_SIZE);
for (i = 0; i < (NR_CONSOLES + 3); i++)
fsbuf[0] |= 1 << i;
assert(fsbuf[0] == 0x3F);/* 0011 1111 :
* || ||||
* || |||`--- bit 0 : reserved
* || ||`---- bit 1 : the first inode,
* || || which indicates `/'
* || |`----- bit 2 : /dev_tty0
* || `------ bit 3 : /dev_tty1
* |`-------- bit 4 : /dev_tty2
* `--------- bit 5 : /cmd.tar
*/
WR_SECT(ROOT_DEV, 2);
/************************/
/* secter map */
/************************/
memset(fsbuf, 0, SECTOR_SIZE);
int nr_sects = NR_DEFAULT_FILE_SECTS + 1;
/* ~~~~~~~~~~~~~~~~~~~|~ |
* | `--- bit 0 is reserved
* `-------- for `/'
*/
for (i = 0; i < nr_sects / 8; i++)
fsbuf[i] = 0xFF;
for (j = 0; j < nr_sects % 8; j++)
fsbuf[i] |= (1 << j);
WR_SECT(ROOT_DEV, 2 + sb.nr_imap_sects);
/* zeromemory the rest sector-map */
memset(fsbuf, 0, SECTOR_SIZE);
for (i = 1; i < sb.nr_smap_sects; i++)
WR_SECT(ROOT_DEV, 2 + sb.nr_imap_sects + i);
/* cmd.tar */
/* make sure it'll not be overwritten by the disk log */
assert(INSTALL_START_SECT + INSTALL_NR_SECTS <
sb.nr_sects - NR_SECTS_FOR_LOG);
int bit_offset = INSTALL_START_SECT -
sb.n_1st_sect + 1; /* sect M <-> bit (M - sb.n_1stsect + 1) */
int bit_off_in_sect = bit_offset % (SECTOR_SIZE * 8);
int bit_left = INSTALL_NR_SECTS;
int cur_sect = bit_offset / (SECTOR_SIZE * 8);
RD_SECT(ROOT_DEV, 2 + sb.nr_imap_sects + cur_sect);
while (bit_left) {
int byte_off = bit_off_in_sect / 8;
/* this line is ineffecient in a loop, but I don't care */
fsbuf[byte_off] |= 1 << (bit_off_in_sect % 8);
bit_left--;
bit_off_in_sect++;
if (bit_off_in_sect == (SECTOR_SIZE * 8)) {
WR_SECT(ROOT_DEV, 2 + sb.nr_imap_sects + cur_sect);
cur_sect++;
RD_SECT(ROOT_DEV, 2 + sb.nr_imap_sects + cur_sect);
bit_off_in_sect = 0;
}
}
WR_SECT(ROOT_DEV, 2 + sb.nr_imap_sects + cur_sect);
/************************/
/* inodes */
/************************/
/* inode of `/' */
memset(fsbuf, 0, SECTOR_SIZE);
struct inode * pi = (struct inode*)fsbuf;
pi->i_mode = I_DIRECTORY;
pi->i_size = DIR_ENTRY_SIZE * 5; /* 5 files:
* `.',
* `dev_tty0', `dev_tty1', `dev_tty2',
* `cmd.tar'
*/
pi->i_start_sect = sb.n_1st_sect;
pi->i_nr_sects = NR_DEFAULT_FILE_SECTS;
/* inode of `/dev_tty0~2' */
for (i = 0; i < NR_CONSOLES; i++) {
pi = (struct inode*)(fsbuf + (INODE_SIZE * (i + 1)));
pi->i_mode = I_CHAR_SPECIAL;
pi->i_size = 0;
pi->i_start_sect = MAKE_DEV(DEV_CHAR_TTY, i);
pi->i_nr_sects = 0;
}
/* inode of `/cmd.tar' */
pi = (struct inode*)(fsbuf + (INODE_SIZE * (NR_CONSOLES + 1)));
pi->i_mode = I_REGULAR;
pi->i_size = INSTALL_NR_SECTS * SECTOR_SIZE;
pi->i_start_sect = INSTALL_START_SECT;
pi->i_nr_sects = INSTALL_NR_SECTS;
WR_SECT(ROOT_DEV, 2 + sb.nr_imap_sects + sb.nr_smap_sects);
/************************/
/* `/' */
/************************/
memset(fsbuf, 0, SECTOR_SIZE);
struct dir_entry * pde = (struct dir_entry *)fsbuf;
pde->inode_nr = 1;
strcpy(pde->name, ".");
/* dir entries of `/dev_tty0~2' */
for (i = 0; i < NR_CONSOLES; i++) {
pde++;
pde->inode_nr = i + 2; /* dev_tty0's inode_nr is 2 */
sprintf(pde->name, "dev_tty%d", i);
}
(++pde)->inode_nr = NR_CONSOLES + 2;
sprintf(pde->name, "cmd.tar", i);
WR_SECT(ROOT_DEV, sb.n_1st_sect);
}
/*****************************************************************************
* rw_sector
*****************************************************************************/
/**
* <Ring 1> R/W a sector via messaging with the corresponding driver.
*
* @param io_type DEV_READ or DEV_WRITE
* @param dev device nr
* @param pos Byte offset from/to where to r/w.
* @param bytes r/w count in bytes.
* @param proc_nr To whom the buffer belongs.
* @param buf r/w buffer.
*
* @return Zero if success.
*****************************************************************************/
PUBLIC int rw_sector(int io_type, int dev, u64 pos, int bytes, int proc_nr,
void* buf)
{
MESSAGE driver_msg;
driver_msg.type = io_type;
driver_msg.DEVICE = MINOR(dev);
driver_msg.POSITION = pos;
driver_msg.BUF = buf;
driver_msg.CNT = bytes;
driver_msg.PROC_NR = proc_nr;
assert(dd_map[MAJOR(dev)].driver_nr != INVALID_DRIVER);
send_recv(BOTH, dd_map[MAJOR(dev)].driver_nr, &driver_msg);
return 0;
}
/*****************************************************************************
* read_super_block
*****************************************************************************/
/**
* <Ring 1> Read super block from the given device then write it into a free
* super_block[] slot.
*
* @param dev From which device the super block comes.
*****************************************************************************/
PRIVATE void read_super_block(int dev)
{
int i;
MESSAGE driver_msg;
driver_msg.type = DEV_READ;
driver_msg.DEVICE = MINOR(dev);
driver_msg.POSITION = SECTOR_SIZE * 1;
driver_msg.BUF = fsbuf;
driver_msg.CNT = SECTOR_SIZE;
driver_msg.PROC_NR = TASK_FS;
assert(dd_map[MAJOR(dev)].driver_nr != INVALID_DRIVER);
send_recv(BOTH, dd_map[MAJOR(dev)].driver_nr, &driver_msg);
/* find a free slot in super_block[] */
for (i = 0; i < NR_SUPER_BLOCK; i++)
if (super_block[i].sb_dev == NO_DEV)
break;
if (i == NR_SUPER_BLOCK)
panic("super_block slots used up");
assert(i == 0); /* currently we use only the 1st slot */
struct super_block * psb = (struct super_block *)fsbuf;
super_block[i] = *psb;
super_block[i].sb_dev = dev;
}
/*****************************************************************************
* get_super_block
*****************************************************************************/
/**
* <Ring 1> Get the super block from super_block[].
*
* @param dev Device nr.
*
* @return Super block ptr.
*****************************************************************************/
PUBLIC struct super_block * get_super_block(int dev)
{
struct super_block * sb = super_block;
for (; sb < &super_block[NR_SUPER_BLOCK]; sb++)
if (sb->sb_dev == dev)
return sb;
panic("super block of devie %d not found.\n", dev);
return 0;
}
/*****************************************************************************
* get_inode
*****************************************************************************/
/**
* <Ring 1> Get the inode ptr of given inode nr. A cache -- inode_table[] -- is
* maintained to make things faster. If the inode requested is already there,
* just return it. Otherwise the inode will be read from the disk.
*
* @param dev Device nr.
* @param num I-node nr.
*
* @return The inode ptr requested.
*****************************************************************************/
PUBLIC struct inode * get_inode(int dev, int num)
{
if (num == 0)
return 0;
struct inode * p;
struct inode * q = 0;
for (p = &inode_table[0]; p < &inode_table[NR_INODE]; p++) {
if (p->i_cnt) { /* not a free slot */
if ((p->i_dev == dev) && (p->i_num == num)) {
/* this is the inode we want */
p->i_cnt++;
return p;
}
}
else { /* a free slot */
if (!q) /* q hasn't been assigned yet */
q = p; /* q <- the 1st free slot */
}
}
if (!q)
panic("the inode table is full");
q->i_dev = dev;
q->i_num = num;
q->i_cnt = 1;
struct super_block * sb = get_super_block(dev);
int blk_nr = 1 + 1 + sb->nr_imap_sects + sb->nr_smap_sects +
((num - 1) / (SECTOR_SIZE / INODE_SIZE));
RD_SECT(dev, blk_nr);
struct inode * pinode =
(struct inode*)((u8*)fsbuf +
((num - 1 ) % (SECTOR_SIZE / INODE_SIZE))
* INODE_SIZE);
q->i_mode = pinode->i_mode;
q->i_size = pinode->i_size;
q->i_start_sect = pinode->i_start_sect;
q->i_nr_sects = pinode->i_nr_sects;
return q;
}
/*****************************************************************************
* put_inode
*****************************************************************************/
/**
* Decrease the reference nr of a slot in inode_table[]. When the nr reaches
* zero, it means the inode is not used any more and can be overwritten by
* a new inode.
*
* @param pinode I-node ptr.
*****************************************************************************/
PUBLIC void put_inode(struct inode * pinode)
{
assert(pinode->i_cnt > 0);
pinode->i_cnt--;
}
/*****************************************************************************
* sync_inode
*****************************************************************************/
/**
* <Ring 1> Write the inode back to the disk. Commonly invoked as soon as the
* inode is changed.
*
* @param p I-node ptr.
*****************************************************************************/
PUBLIC void sync_inode(struct inode * p)
{
struct inode * pinode;
struct super_block * sb = get_super_block(p->i_dev);
int blk_nr = 1 + 1 + sb->nr_imap_sects + sb->nr_smap_sects +
((p->i_num - 1) / (SECTOR_SIZE / INODE_SIZE));
RD_SECT(p->i_dev, blk_nr);
pinode = (struct inode*)((u8*)fsbuf +
(((p->i_num - 1) % (SECTOR_SIZE / INODE_SIZE))
* INODE_SIZE));
pinode->i_mode = p->i_mode;
pinode->i_size = p->i_size;
pinode->i_start_sect = p->i_start_sect;
pinode->i_nr_sects = p->i_nr_sects;
WR_SECT(p->i_dev, blk_nr);
}
/*****************************************************************************
* fs_fork
*****************************************************************************/
/**
* Perform the aspects of fork() that relate to files.
*
* @return Zero if success, otherwise a negative integer.
*****************************************************************************/
PRIVATE int fs_fork()
{
int i;
struct proc* child = &proc_table[fs_msg.PID];
for (i = 0; i < NR_FILES; i++) {
if (child->filp[i]) {
child->filp[i]->fd_cnt++;
child->filp[i]->fd_inode->i_cnt++;
}
}
return 0;
}
/*****************************************************************************
* fs_exit
*****************************************************************************/
/**
* Perform the aspects of exit() that relate to files.
*
* @return Zero if success.
*****************************************************************************/
PRIVATE int fs_exit()
{
int i;
struct proc* p = &proc_table[fs_msg.PID];
for (i = 0; i < NR_FILES; i++) {
if (p->filp[i]) {
/* release the inode */
p->filp[i]->fd_inode->i_cnt--;
/* release the file desc slot */
if (--p->filp[i]->fd_cnt == 0)
p->filp[i]->fd_inode = 0;
p->filp[i] = 0;
}
}
return 0;
}
修改 untar()
kernel/main.c
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
main.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
#include "type.h"
#include "stdio.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "fs.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "proto.h"
/*****************************************************************************
* kernel_main
*****************************************************************************/
/**
* jmp from kernel.asm::_start.
*
*****************************************************************************/
PUBLIC int kernel_main()
{
disp_str("\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
int i, j, eflags, prio;
u8 rpl;
u8 priv; /* privilege */
struct task * t;
struct proc * p = proc_table;
char * stk = task_stack + STACK_SIZE_TOTAL;
for (i = 0; i < NR_TASKS + NR_PROCS; i++,p++,t++) {
if (i >= NR_TASKS + NR_NATIVE_PROCS) {
p->p_flags = FREE_SLOT;
continue;
}
if (i < NR_TASKS) { /* TASK */
t = task_table + i;
priv = PRIVILEGE_TASK;
rpl = RPL_TASK;
eflags = 0x1202;/* IF=1, IOPL=1, bit 2 is always 1 */
prio = 15;
}
else { /* USER PROC */
t = user_proc_table + (i - NR_TASKS);
priv = PRIVILEGE_USER;
rpl = RPL_USER;
eflags = 0x202; /* IF=1, bit 2 is always 1 */
prio = 5;
}
strcpy(p->name, t->name); /* name of the process */
p->p_parent = NO_TASK;
if (strcmp(t->name, "INIT") != 0) {
p->ldts[INDEX_LDT_C] = gdt[SELECTOR_KERNEL_CS >> 3];
p->ldts[INDEX_LDT_RW] = gdt[SELECTOR_KERNEL_DS >> 3];
/* change the DPLs */
p->ldts[INDEX_LDT_C].attr1 = DA_C | priv << 5;
p->ldts[INDEX_LDT_RW].attr1 = DA_DRW | priv << 5;
}
else { /* INIT process */
unsigned int k_base;
unsigned int k_limit;
int ret = get_kernel_map(&k_base, &k_limit);
assert(ret == 0);
init_desc(&p->ldts[INDEX_LDT_C],
0, /* bytes before the entry point
* are useless (wasted) for the
* INIT process, doesn't matter
*/
(k_base + k_limit) >> LIMIT_4K_SHIFT,
DA_32 | DA_LIMIT_4K | DA_C | priv << 5);
init_desc(&p->ldts[INDEX_LDT_RW],
0, /* bytes before the entry point
* are useless (wasted) for the
* INIT process, doesn't matter
*/
(k_base + k_limit) >> LIMIT_4K_SHIFT,
DA_32 | DA_LIMIT_4K | DA_DRW | priv << 5);
}
p->regs.cs = INDEX_LDT_C << 3 | SA_TIL | rpl;
p->regs.ds =
p->regs.es =
p->regs.fs =
p->regs.ss = INDEX_LDT_RW << 3 | SA_TIL | rpl;
p->regs.gs = (SELECTOR_KERNEL_GS & SA_RPL_MASK) | rpl;
p->regs.eip = (u32)t->initial_eip;
p->regs.esp = (u32)stk;
p->regs.eflags = eflags;
p->ticks = p->priority = prio;
p->p_flags = 0;
p->p_msg = 0;
p->p_recvfrom = NO_TASK;
p->p_sendto = NO_TASK;
p->has_int_msg = 0;
p->q_sending = 0;
p->next_sending = 0;
for (j = 0; j < NR_FILES; j++)
p->filp[j] = 0;
stk -= t->stacksize;
}
k_reenter = 0;
ticks = 0;
p_proc_ready = proc_table;
init_clock();
init_keyboard();
restart();
while(1){}
}
/*****************************************************************************
* get_ticks
*****************************************************************************/
PUBLIC int get_ticks()
{
MESSAGE msg;
reset_msg(&msg);
msg.type = GET_TICKS;
send_recv(BOTH, TASK_SYS, &msg);
return msg.RETVAL;
}
/**
* @struct posix_tar_header
* Borrowed from GNU `tar'
*/
struct posix_tar_header
{ /* byte offset */
char name[100]; /* 0 */
char mode[8]; /* 100 */
char uid[8]; /* 108 */
char gid[8]; /* 116 */
char size[12]; /* 124 */
char mtime[12]; /* 136 */
char chksum[8]; /* 148 */
char typeflag; /* 156 */
char linkname[100]; /* 157 */
char magic[6]; /* 257 */
char version[2]; /* 263 */
char uname[32]; /* 265 */
char gname[32]; /* 297 */
char devmajor[8]; /* 329 */
char devminor[8]; /* 337 */
char prefix[155]; /* 345 */
/* 500 */
};
/*****************************************************************************
* untar
*****************************************************************************/
/**
* Extract the tar file and store them.
*
* @param filename The tar file.
*****************************************************************************/
void untar(const char * filename)
{
printf("[extract `%s'\n", filename);
int fd = open(filename, O_RDWR);
assert(fd != -1);
char buf[SECTOR_SIZE * 16];
int chunk = sizeof(buf);
int i = 0;
int bytes = 0;
while (1) {
bytes = read(fd, buf, SECTOR_SIZE);
assert(bytes == SECTOR_SIZE); /* size of a TAR file
* must be multiple of 512
*/
if (buf[0] == 0) {
if (i == 0)
printf(" need not unpack the file.\n");
break;
}
i++;
struct posix_tar_header * phdr = (struct posix_tar_header *)buf;
/* calculate the file size */
char * p = phdr->size;
int f_len = 0;
while (*p)
f_len = (f_len * 8) + (*p++ - '0'); /* octal */
int bytes_left = f_len;
int fdout = open(phdr->name, O_CREAT | O_RDWR | O_TRUNC);
if (fdout == -1) {
printf(" failed to extract file: %s\n", phdr->name);
printf(" aborted]\n");
close(fd);
return;
}
printf(" %s\n", phdr->name);
while (bytes_left) {
int iobytes = min(chunk, bytes_left);
read(fd, buf,
((iobytes - 1) / SECTOR_SIZE + 1) * SECTOR_SIZE);
bytes = write(fdout, buf, iobytes);
assert(bytes == iobytes);
bytes_left -= iobytes;
}
close(fdout);
}
if (i) {
lseek(fd, 0, SEEK_SET);
buf[0] = 0;
bytes = write(fd, buf, 1);
assert(bytes == 1);
}
close(fd);
printf(" done, %d files extracted]\n", i);
}
/*****************************************************************************
* shabby_shell
*****************************************************************************/
/**
* A very very simple shell.
*
* @param tty_name TTY file name.
*****************************************************************************/
void shabby_shell(const char * tty_name)
{
int fd_stdin = open(tty_name, O_RDWR);
assert(fd_stdin == 0);
int fd_stdout = open(tty_name, O_RDWR);
assert(fd_stdout == 1);
char rdbuf[128];
while (1) {
write(1, "$ ", 2);
int r = read(0, rdbuf, 70);
rdbuf[r] = 0;
int argc = 0;
char * argv[PROC_ORIGIN_STACK];
char * p = rdbuf;
char * s;
int word = 0;
char ch;
do {
ch = *p;
if (*p != ' ' && *p != 0 && !word) {
s = p;
word = 1;
}
if ((*p == ' ' || *p == 0) && word) {
word = 0;
argv[argc++] = s;
*p = 0;
}
p++;
} while(ch);
argv[argc] = 0;
int fd = open(argv[0], O_RDWR);
if (fd == -1) {
if (rdbuf[0]) {
write(1, "{", 1);
write(1, rdbuf, r);
write(1, "}\n", 2);
}
}
else {
close(fd);
int pid = fork();
if (pid != 0) { /* parent */
int s;
wait(&s);
}
else { /* child */
execv(argv[0], argv);
}
}
}
close(1);
close(0);
}
/*****************************************************************************
* Init
*****************************************************************************/
/**
* The hen.
*
*****************************************************************************/
void Init()
{
int fd_stdin = open("/dev_tty0", O_RDWR);
assert(fd_stdin == 0);
int fd_stdout = open("/dev_tty0", O_RDWR);
assert(fd_stdout == 1);
printf("Init() is running ...\n");
/* extract `cmd.tar' */
untar("/cmd.tar");
char * tty_list[] = {"/dev_tty1", "/dev_tty2"};
int i;
for (i = 0; i < sizeof(tty_list) / sizeof(tty_list[0]); i++) {
int pid = fork();
if (pid != 0) { /* parent process */
printf("[parent is running, child pid:%d]\n", pid);
}
else { /* child process */
printf("[child is running, pid:%d]\n", getpid());
close(fd_stdin);
close(fd_stdout);
shabby_shell(tty_list[i]);
assert(0);
}
}
while (1) {
int s;
int child = wait(&s);
printf("child (%d) exited with status: %d.\n", child, s);
}
assert(0);
}
/*======================================================================*
TestA
*======================================================================*/
void TestA()
{
for(;;);
}
/*======================================================================*
TestB
*======================================================================*/
void TestB()
{
for(;;);
}
/*======================================================================*
TestB
*======================================================================*/
void TestC()
{
for(;;);
}
/*****************************************************************************
* panic
*****************************************************************************/
PUBLIC void panic(const char *fmt, ...)
{
int i;
char buf[256];
/* 4 is the size of fmt in the stack */
va_list arg = (va_list)((char*)&fmt + 4);
i = vsprintf(buf, fmt, arg);
printl("%c !!panic!! %s", MAG_CH_PANIC, buf);
/* should never arrive here */
__asm__ __volatile__("ud2");
}
清除舊檔案,寫入新內容
fs/open.c
/*************************************************************************//**
*****************************************************************************
* @file fs/open.c
* The file contains:
* - do_open()
* - do_close()
* - do_lseek()
* - create_file()
* @author Forrest Yu
* @date 2007
*****************************************************************************
*****************************************************************************/
#include "type.h"
#include "stdio.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "fs.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "keyboard.h"
#include "proto.h"
PRIVATE struct inode * create_file(char * path, int flags);
PRIVATE int alloc_imap_bit(int dev);
PRIVATE int alloc_smap_bit(int dev, int nr_sects_to_alloc);
PRIVATE struct inode * new_inode(int dev, int inode_nr, int start_sect);
PRIVATE void new_dir_entry(struct inode * dir_inode, int inode_nr, char * filename);
/*****************************************************************************
* do_open
*****************************************************************************/
/**
* Open a file and return the file descriptor.
*
* @return File descriptor if successful, otherwise a negative error code.
*****************************************************************************/
PUBLIC int do_open()
{
int fd = -1; /* return value */
char pathname[MAX_PATH];
/* get parameters from the message */
int flags = fs_msg.FLAGS; /* access mode */
int name_len = fs_msg.NAME_LEN; /* length of filename */
int src = fs_msg.source; /* caller proc nr. */
assert(name_len < MAX_PATH);
phys_copy((void*)va2la(TASK_FS, pathname),
(void*)va2la(src, fs_msg.PATHNAME),
name_len);
pathname[name_len] = 0;
/* find a free slot in PROCESS::filp[] */
int i;
for (i = 0; i < NR_FILES; i++) {
if (pcaller->filp[i] == 0) {
fd = i;
break;
}
}
if ((fd < 0) || (fd >= NR_FILES))
panic("filp[] is full (PID:%d)", proc2pid(pcaller));
/* find a free slot in f_desc_table[] */
for (i = 0; i < NR_FILE_DESC; i++)
if (f_desc_table[i].fd_inode == 0)
break;
if (i >= NR_FILE_DESC)
panic("f_desc_table[] is full (PID:%d)", proc2pid(pcaller));
int inode_nr = search_file(pathname);
struct inode * pin = 0;
if (inode_nr == INVALID_INODE) { /* file not exists */
if (flags & O_CREAT) {
pin = create_file(pathname, flags);
}
else {
printl("{FS} file not exists: %s\n", pathname);
return -1;
}
}
else if (flags & O_RDWR) { /* file exists */
if ((flags & O_CREAT) && (!(flags & O_TRUNC))) {
assert(flags == (O_RDWR | O_CREAT));
printl("{FS} file exists: %s\n", pathname);
return -1;
}
assert((flags == O_RDWR ) ||
(flags == (O_RDWR | O_TRUNC )) ||
(flags == (O_RDWR | O_TRUNC | O_CREAT)));
char filename[MAX_PATH];
struct inode * dir_inode;
if (strip_path(filename, pathname, &dir_inode) != 0)
return -1;
pin = get_inode(dir_inode->i_dev, inode_nr);
}
else { /* file exists, no O_RDWR flag */
printl("{FS} file exists: %s\n", pathname);
return -1;
}
if (flags & O_TRUNC) {
assert(pin);
pin->i_size = 0;
sync_inode(pin);
}
if (pin) {
/* connects proc with file_descriptor */
pcaller->filp[fd] = &f_desc_table[i];
/* connects file_descriptor with inode */
f_desc_table[i].fd_inode = pin;
f_desc_table[i].fd_mode = flags;
f_desc_table[i].fd_cnt = 1;
f_desc_table[i].fd_pos = 0;
int imode = pin->i_mode & I_TYPE_MASK;
if (imode == I_CHAR_SPECIAL) {
MESSAGE driver_msg;
driver_msg.type = DEV_OPEN;
int dev = pin->i_start_sect;
driver_msg.DEVICE = MINOR(dev);
assert(MAJOR(dev) == 4);
assert(dd_map[MAJOR(dev)].driver_nr != INVALID_DRIVER);
send_recv(BOTH,
dd_map[MAJOR(dev)].driver_nr,
&driver_msg);
}
else if (imode == I_DIRECTORY) {
assert(pin->i_num == ROOT_INODE);
}
else {
assert(pin->i_mode == I_REGULAR);
}
}
else {
return -1;
}
return fd;
}
/*****************************************************************************
* create_file
*****************************************************************************/
/**
* Create a file and return it's inode ptr.
*
* @param[in] path The full path of the new file
* @param[in] flags Attribiutes of the new file
*
* @return Ptr to i-node of the new file if successful, otherwise 0.
*
* @see open()
* @see do_open()
*****************************************************************************/
PRIVATE struct inode * create_file(char * path, int flags)
{
char filename[MAX_PATH];
struct inode * dir_inode;
if (strip_path(filename, path, &dir_inode) != 0)
return 0;
int inode_nr = alloc_imap_bit(dir_inode->i_dev);
int free_sect_nr = alloc_smap_bit(dir_inode->i_dev,
NR_DEFAULT_FILE_SECTS);
struct inode *newino = new_inode(dir_inode->i_dev, inode_nr,
free_sect_nr);
new_dir_entry(dir_inode, newino->i_num, filename);
return newino;
}
/*****************************************************************************
* do_close
*****************************************************************************/
/**
* Handle the message CLOSE.
*
* @return Zero if success.
*****************************************************************************/
PUBLIC int do_close()
{
int fd = fs_msg.FD;
put_inode(pcaller->filp[fd]->fd_inode);
if (--pcaller->filp[fd]->fd_cnt == 0)
pcaller->filp[fd]->fd_inode = 0;
pcaller->filp[fd] = 0;
return 0;
}
/*****************************************************************************
* do_lseek
*****************************************************************************/
/**
* Handle the message LSEEK.
*
* @return The new offset in bytes from the beginning of the file if successful,
* otherwise a negative number.
*****************************************************************************/
PUBLIC int do_lseek()
{
int fd = fs_msg.FD;
int off = fs_msg.OFFSET;
int whence = fs_msg.WHENCE;
int pos = pcaller->filp[fd]->fd_pos;
int f_size = pcaller->filp[fd]->fd_inode->i_size;
switch (whence) {
case SEEK_SET:
pos = off;
break;
case SEEK_CUR:
pos += off;
break;
case SEEK_END:
pos = f_size + off;
break;
default:
return -1;
break;
}
if ((pos > f_size) || (pos < 0)) {
return -1;
}
pcaller->filp[fd]->fd_pos = pos;
return pos;
}
/*****************************************************************************
* alloc_imap_bit
*****************************************************************************/
/**
* Allocate a bit in inode-map.
*
* @param dev In which device the inode-map is located.
*
* @return I-node nr.
*****************************************************************************/
PRIVATE int alloc_imap_bit(int dev)
{
int inode_nr = 0;
int i, j, k;
int imap_blk0_nr = 1 + 1; /* 1 boot sector & 1 super block */
struct super_block * sb = get_super_block(dev);
for (i = 0; i < sb->nr_imap_sects; i++) {
RD_SECT(dev, imap_blk0_nr + i);
for (j = 0; j < SECTOR_SIZE; j++) {
/* skip `11111111' bytes */
if (fsbuf[j] == 0xFF)
continue;
/* skip `1' bits */
for (k = 0; ((fsbuf[j] >> k) & 1) != 0; k++) {}
/* i: sector index; j: byte index; k: bit index */
inode_nr = (i * SECTOR_SIZE + j) * 8 + k;
fsbuf[j] |= (1 << k);
/* write the bit to imap */
WR_SECT(dev, imap_blk0_nr + i);
break;
}
return inode_nr;
}
/* no free bit in imap */
panic("inode-map is probably full.\n");
return 0;
}
/*****************************************************************************
* alloc_smap_bit
*****************************************************************************/
/**
* Allocate a bit in sector-map.
*
* @param dev In which device the sector-map is located.
* @param nr_sects_to_alloc How many sectors are allocated.
*
* @return The 1st sector nr allocated.
*****************************************************************************/
PRIVATE int alloc_smap_bit(int dev, int nr_sects_to_alloc)
{
/* int nr_sects_to_alloc = NR_DEFAULT_FILE_SECTS; */
int i; /* sector index */
int j; /* byte index */
int k; /* bit index */
struct super_block * sb = get_super_block(dev);
int smap_blk0_nr = 1 + 1 + sb->nr_imap_sects;
int free_sect_nr = 0;
for (i = 0; i < sb->nr_smap_sects; i++) { /* smap_blk0_nr + i :
current sect nr. */
RD_SECT(dev, smap_blk0_nr + i);
/* byte offset in current sect */
for (j = 0; j < SECTOR_SIZE && nr_sects_to_alloc > 0; j++) {
k = 0;
if (!free_sect_nr) {
/* loop until a free bit is found */
if (fsbuf[j] == 0xFF) continue;
for (; ((fsbuf[j] >> k) & 1) != 0; k++) {}
free_sect_nr = (i * SECTOR_SIZE + j) * 8 +
k - 1 + sb->n_1st_sect;
}
for (; k < 8; k++) { /* repeat till enough bits are set */
assert(((fsbuf[j] >> k) & 1) == 0);
fsbuf[j] |= (1 << k);
if (--nr_sects_to_alloc == 0)
break;
}
}
if (free_sect_nr) /* free bit found, write the bits to smap */
WR_SECT(dev, smap_blk0_nr + i);
if (nr_sects_to_alloc == 0)
break;
}
assert(nr_sects_to_alloc == 0);
return free_sect_nr;
}
/*****************************************************************************
* new_inode
*****************************************************************************/
/**
* Generate a new i-node and write it to disk.
*
* @param dev Home device of the i-node.
* @param inode_nr I-node nr.
* @param start_sect Start sector of the file pointed by the new i-node.
*
* @return Ptr of the new i-node.
*****************************************************************************/
PRIVATE struct inode * new_inode(int dev, int inode_nr, int start_sect)
{
struct inode * new_inode = get_inode(dev, inode_nr);
new_inode->i_mode = I_REGULAR;
new_inode->i_size = 0;
new_inode->i_start_sect = start_sect;
new_inode->i_nr_sects = NR_DEFAULT_FILE_SECTS;
new_inode->i_dev = dev;
new_inode->i_cnt = 1;
new_inode->i_num = inode_nr;
/* write to the inode array */
sync_inode(new_inode);
return new_inode;
}
/*****************************************************************************
* new_dir_entry
*****************************************************************************/
/**
* Write a new entry into the directory.
*
* @param dir_inode I-node of the directory.
* @param inode_nr I-node nr of the new file.
* @param filename Filename of the new file.
*****************************************************************************/
PRIVATE void new_dir_entry(struct inode *dir_inode,int inode_nr,char *filename)
{
/* write the dir_entry */
int dir_blk0_nr = dir_inode->i_start_sect;
int nr_dir_blks = (dir_inode->i_size + SECTOR_SIZE) / SECTOR_SIZE;
int nr_dir_entries =
dir_inode->i_size / DIR_ENTRY_SIZE; /**
* including unused slots
* (the file has been
* deleted but the slot
* is still there)
*/
int m = 0;
struct dir_entry * pde;
struct dir_entry * new_de = 0;
int i, j;
for (i = 0; i < nr_dir_blks; i++) {
RD_SECT(dir_inode->i_dev, dir_blk0_nr + i);
pde = (struct dir_entry *)fsbuf;
for (j = 0; j < SECTOR_SIZE / DIR_ENTRY_SIZE; j++,pde++) {
if (++m > nr_dir_entries)
break;
if (pde->inode_nr == 0) { /* it's a free slot */
new_de = pde;
break;
}
}
if (m > nr_dir_entries ||/* all entries have been iterated or */
new_de) /* free slot is found */
break;
}
if (!new_de) { /* reached the end of the dir */
new_de = pde;
dir_inode->i_size += DIR_ENTRY_SIZE;
}
new_de->inode_nr = inode_nr;
strcpy(new_de->name, filename);
/* write dir block -- ROOT dir block */
WR_SECT(dir_inode->i_dev, dir_blk0_nr + i);
/* update dir inode */
sync_inode(dir_inode);
}
include/stdio.h
/*************************************************************************//**
*****************************************************************************
* @file stdio.h
* @brief
* @author Forrest Y. Yu
* @date 2008
*****************************************************************************
*****************************************************************************/
#ifndef _ORANGES_STDIO_H_
#define _ORANGES_STDIO_H_
#include "type.h"
/* the assert macro */
#define ASSERT
#ifdef ASSERT
void assertion_failure(char *exp, char *file, char *base_file, int line);
#define assert(exp) if (exp) ; \
else assertion_failure(#exp, __FILE__, __BASE_FILE__, __LINE__)
#else
#define assert(exp)
#endif
/* EXTERN */
#define EXTERN extern /* EXTERN is defined as extern except in global.c */
/* string */
#define STR_DEFAULT_LEN 1024
#define O_CREAT 1
#define O_RDWR 2
#define O_TRUNC 4
#define SEEK_SET 1
#define SEEK_CUR 2
#define SEEK_END 3
#define MAX_PATH 128
/**
* @struct stat
* @brief File status, returned by syscall stat();
*/
struct stat {
int st_dev; /* major/minor device number */
int st_ino; /* i-node number */
int st_mode; /* file mode, protection bits, etc. */
int st_rdev; /* device ID (if special file) */
int st_size; /* file size */
};
/**
* @struct time
* @brief RTC time from CMOS.
*/
struct time {
u32 year;
u32 month;
u32 day;
u32 hour;
u32 minute;
u32 second;
};
#define BCD_TO_DEC(x) ( (x >> 4) * 10 + (x & 0x0f) )
/*========================*
* printf, printl, printx *
*========================*
*
* printf:
*
* [send msg] WRITE DEV_WRITE
* USER_PROC ------------→ FS -------------→ TTY
* ↖______________↙↖_______________/
* [recv msg] SYSCALL_RET SYSCALL_RET
*
*----------------------------------------------------------------------
*
* printl: variant-parameter-version printx
*
* calls vsprintf, then printx (trap into kernel directly)
*
*----------------------------------------------------------------------
*
* printx: low level print without using IPC
*
* trap directly
* USER_PROC -- -- -- -- -- --> KERNEL
*
*
*----------------------------------------------------------------------
*/
/* printf.c */
PUBLIC int printf(const char *fmt, ...);
PUBLIC int printl(const char *fmt, ...);
/* vsprintf.c */
PUBLIC int vsprintf(char *buf, const char *fmt, va_list args);
PUBLIC int sprintf(char *buf, const char *fmt, ...);
/*--------*/
/* 庫函數 */
/*--------*/
#ifdef ENABLE_DISK_LOG
#define SYSLOG syslog
#endif
/* lib/open.c */
PUBLIC int open (const char *pathname, int flags);
/* lib/close.c */
PUBLIC int close (int fd);
/* lib/read.c */
PUBLIC int read (int fd, void *buf, int count);
/* lib/write.c */
PUBLIC int write (int fd, const void *buf, int count);
/* lib/lseek.c */
PUBLIC int lseek (int fd, int offset, int whence);
/* lib/unlink.c */
PUBLIC int unlink (const char *pathname);
/* lib/getpid.c */
PUBLIC int getpid ();
/* lib/fork.c */
PUBLIC int fork ();
/* lib/exit.c */
PUBLIC void exit (int status);
/* lib/wait.c */
PUBLIC int wait (int * status);
/* lib/exec.c */
PUBLIC int exec (const char * path);
PUBLIC int execl (const char * path, const char *arg, ...);
PUBLIC int execv (const char * path, char * argv[]);
/* lib/stat.c */
PUBLIC int stat (const char *path, struct stat *buf);
/* lib/syslog.c */
PUBLIC int syslog (const char *fmt, ...);
#endif /* _ORANGES_STDIO_H_ */
![]() |
| 執行畫面(必須執行兩次,第一次結束後設定 magic number,第二次即不會執行) |

留言
張貼留言