問題一:我們的系統每次啟動都是「全新」的,上次建立的文件到下一次啟動就不見了。
問題二:每次都會執行一次解開 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,第二次即不會執行) |
留言
張貼留言