//*****************umount**************** int8_t cnumount(void) { cnclosedir(cwd); fs.superblk->state = VALID_FS; blk_write(BLOCKID_SUPER, &superblk_cache); blk_write(BLOCKID_BLOCK_BITMAP, &block_bm_cache); blk_write(BLOCKID_INODE_BITMAP, &inode_bm_cache); return 0; }
static int addlink(struct filesys *fs, struct inode *target, struct inode *node, const char *name) { struct dir_entry ent, *data; int i, boffs, bidx, len; if(!(target->mode & S_IFDIR)) { return -ENOTDIR; } if(node->mode & S_IFDIR) { return -EPERM; } /* TODO check that the link does not already exist (EEXIST) */ if((len = strlen(name)) > NAME_MAX) { return -ENAMETOOLONG; } ent.ino = node->ino; memcpy(ent.name, name, len + 1); /* find a place to put it */ if(!(data = malloc(BLKSZ))) { return -ENOMEM; } boffs = 0; while((bidx = get_file_block(fs, target, boffs)) > 0) { /* read the block, and search for an empty entry */ blk_read(fs->bdev, bidx, 1, data); /* for all directory entries in this block... */ for(i=0; i<BLK_DIRENT; i++) { if(data[i].ino == 0) { /* found empty */ memcpy(data + i, &ent, sizeof ent); goto success; } } boffs++; } /* didn't find any free entries amongst our blocks, allocate a new one */ if(!(bidx = alloc_file_block(fs, target, boffs))) { free(data); return -ENOSPC; } /* zero-fill the new block and add the first entry */ memset(data, 0, BLKSZ); *data = ent; success: /* write to disk */ blk_write(fs->bdev, bidx, 1, data); node->nlink++; /* increase reference count */ free(data); return 0; }
void inode_bitmap_init(void) { block *inode_btm = calloc(1,sizeof(block)); //Mark first inode as used set_bitmap(inode_btm, 0); blk_write(BLOCKID_INODE_BITMAP, inode_btm); free(inode_btm); }
//******** llwrite ****************** //Writes a file completely and updates inode data int8_t llwrite(inode* inode_ptr, block* buf) { uint32_t* s_ind = calloc(1, sizeof(block)); for(uint8_t i = 0; i < MIN(inode_ptr->blocks,8); i++) { blk_write(inode_ptr->data0[i], buf); buf++; } if(inode_ptr->blocks > 8) { blk_read(inode_ptr->data1, (block*)s_ind); for(uint32_t j = 0; j < inode_ptr->blocks - 8; j++) { blk_write(s_ind[j], buf); buf++; } } free(s_ind); return 0; }
static int check_diskformat(void) { int ret; #ifdef CONFIG_FS_EVFAT struct evfat_format_s fmt = EVFAT_FORMAT_INITIALIZER; /* load MBR */ ret = blk_read(copybuf, sizeof(copybuf), "/dev/mtdblock0p2", 0); if (ret < 0) { return 0; } /* If part2 has MBR signature, this eMMC was formated by PC. * This means the set is just after writing IPL2. */ if (copybuf[510] != 0x55 || copybuf[511] != 0xaa) { return 0; } ret = mkevfatfs(CONFIG_MTD_CP_DEVPATH, &fmt); #endif _info("FORMAT content partition : %d\n", ret); memset(copybuf, 0, sizeof(copybuf)); ret = blk_write(copybuf, 512, CONFIG_MTD_ETC_DEVPATH, 0); _info("clear /etc : %d\n", ret); ret = blk_write(copybuf, 512, CONFIG_MTD_SYSTEM_DEVPATH, 0); _info("clear /system : %d\n", ret); ret = blk_write(copybuf, 512, CONFIG_MTD_CACHE_DEVPATH, 0); _info("clear /cache : %d\n", ret); return 1; }
//*****************mkfs**************** void superblock_init(void) { superblock *sb = calloc(1,sizeof(block)); memset(sb, 0, sizeof(block)); sb->inode_count = INODE_COUNT; sb->block_count = BD_SIZE_BLOCKS; sb->free_inode_count = INODE_COUNT-1; sb->free_block_count = BD_SIZE_BLOCKS-4-INODE_TABLE_BLOCKS; // 4 = super + bitmaps + rootdir sb->magic = FS_MAGIC; sb->state = FS_VALID; blk_write(BLOCKID_SUPER, (block*)sb); free(sb); }
static int write_superblock(struct filesys *fs) { struct superblock *sb = fs->sb; /* write back any changes in the root inode */ if(put_inode(fs, sb->root) == -1) { return -1; } /* write back the block bitmap */ if(blk_write(fs->bdev, sb->bm_start, sb->bm_count, sb->bm) == -1) { return -1; } /* write back the inode bitmap */ if(blk_write(fs->bdev, sb->ibm_start, sb->ibm_count, sb->ibm) == -1) { return -1; } /* write the superblock itself */ if(blk_write(fs->bdev, 1, 1, sb) == -1) { return -1; } return 0; }
/* write the inode to the disk */ static int put_inode(struct filesys *fs, struct inode *inode) { struct inode *buf = malloc(BLKSZ); assert(buf); if(blk_read(fs->bdev, fs->sb->itbl_start + inode->ino / BLK_INODES, 1, buf) == -1) { free(buf); return -1; } memcpy(buf + inode->ino % BLK_INODES, inode, sizeof *inode); if(blk_write(fs->bdev, fs->sb->itbl_start + inode->ino / BLK_INODES, 1, buf) == -1) { free(buf); return -1; } free(buf); return 0; }
void block_bitmap_init(void) { block *block_btm = calloc(1,sizeof(block)); //Mark all reserved blocks as used set_bitmap(block_btm, BLOCKID_SUPER); set_bitmap(block_btm, BLOCKID_BLOCK_BITMAP); set_bitmap(block_btm, BLOCKID_INODE_BITMAP); //Mark all inode table blocks as used for (uint16_t i = BLOCKID_INODE_TABLE; i < INODE_TABLE_BLOCKS + BLOCKID_INODE_TABLE; i++) { set_bitmap(block_btm, i); } //Mark root directory block as used set_bitmap(block_btm, INODE_TABLE_BLOCKS + BLOCKID_INODE_TABLE); blk_write(BLOCKID_BLOCK_BITMAP, block_btm); free(block_btm); }
TEST(blockdev, BlockdevCanReadWrite) { TEST_ASSERT_TRUE(blockdev_attach() == 0); block* test_write_blk = (block*)malloc(BLOCK_SIZE); uint32_t* wblk_32 = (uint32_t*)test_write_blk; wblk_32[0] = 0xDEADBEEF; wblk_32[45] = 0xFEEDBEEF; TEST_ASSERT_TRUE(blk_write(1234, test_write_blk) == 0); free(test_write_blk); TEST_ASSERT_TRUE(blockdev_detach() == 0); TEST_ASSERT_TRUE(blockdev_attach() == 0); block* test_read_blk = (block*)malloc(BLOCK_SIZE); TEST_ASSERT_TRUE(blk_read(1234, test_read_blk) == 0); uint32_t* rblk_32 = (uint32_t*)test_read_blk; TEST_ASSERT_TRUE(rblk_32[0] == 0xDEADBEEF); TEST_ASSERT_TRUE(rblk_32[45] == 0xFEEDBEEF); free(test_read_blk); TEST_ASSERT_TRUE(blockdev_detach() == 0); }
static int _usb_drv_send(int endpoint, void *ptr, int length, bool block) { struct endpoint_t *ep; int ep_num = EP_NUM(endpoint); if (ep_num == 0) ep = &ctrlep[DIR_IN]; else ep = &endpoints[ep_num]; ep->buf = ptr; ep->len = ep->cnt = length; if (block) ep->block = true; else ep->block = false; switch (ep->type) { case USB_ENDPOINT_XFER_CONTROL: ctr_write(); break; case USB_ENDPOINT_XFER_BULK: blk_write(ep_num); break; case USB_ENDPOINT_XFER_INT: int_write(ep_num); break; } if (block) /* wait for transfer to end */ semaphore_wait(&ep->complete, TIMEOUT_BLOCK); return 0; }
//******** creat ******************** int8_t cncreat(dir_ptr* dir, const char* name) { stat_st stat_buf; dir_entry* entry; check(cnstat(dir,name,&stat_buf) != 0, "File exists"); //If this file exists //Create parent directory entry entry = (dir_entry*)(((uint8_t*)dir->data)+dir->index); entry->file_type = ITYPE_FILE; entry->inode = reserve_inode(); memcpy(entry->name, name, strlen(name)); entry->name_len = strlen(name); entry->entry_len = entry->name_len + 8; entry->entry_len += (4 - entry->entry_len % 4); //padding out to 32 bits dir->inode_st.size += entry->entry_len; //TODO: handle creat dir block overflow //Write parent dir and inode dir->inode_st.modified = time(NULL); inode_write(dir->inode_id, &dir->inode_st); blk_write(dir->inode_st.data0[0], dir->data); //Write new file inode inode new_file_i; memset(&new_file_i, 0, sizeof(inode)); uint32_t now = time(NULL); new_file_i.modified = now; new_file_i.type = ITYPE_FILE; new_file_i.size = 0; new_file_i.blocks = 0; inode_write(entry->inode, &new_file_i); return 0; error: return -1; }
void write_root_dir(void) { //Prepare inode inode root_i; memset(&root_i, 0, sizeof(inode)); uint32_t now = time(NULL); root_i.modified = now; root_i.type = ITYPE_DIR; root_i.size = 0; root_i.blocks = 1; root_i.data0[0] = BLOCKID_ROOT_DIR; block* root_dir_block = calloc(1,sizeof(block)); // . (self entry) dir_entry* root_dir_entry = (dir_entry*)root_dir_block; root_dir_entry->inode = 0; root_dir_entry->file_type = ITYPE_DIR; root_dir_entry->name_len = 1; root_dir_entry->entry_len = 12; memcpy(root_dir_entry->name, ".", 1); root_i.size += 12; // .. (parent entry, also itself) root_dir_entry = (dir_entry*)(((char*)root_dir_block) + 12); root_dir_entry->inode = 0; root_dir_entry->file_type = ITYPE_DIR; root_dir_entry->name_len = 2; root_dir_entry->entry_len = 12; memcpy(root_dir_entry->name, "..", 2); root_i.size += 12; inode_write(0, &root_i); blk_write(BLOCKID_ROOT_DIR, root_dir_block); free(root_dir_block); }
//****** realloc_fs_blocks***************** //Allocates at least "blocks_needed" blocks for this file int8_t realloc_fs_blocks(inode* inode, uint32_t blocks_needed) { uint32_t* s_ind = calloc(1, sizeof(block)); if(blocks_needed > inode->blocks) { if(inode->blocks <= 8) { for(; inode->blocks < MIN(8,blocks_needed); inode->blocks++) { inode->data0[inode->blocks] = reserve_block(); } } if(inode->blocks < blocks_needed) //still not enough after allocating direct { //Determine if a single indirect block has been allocated if(inode->data1 == 0) { inode->data1 = reserve_block(); } else { blk_read(inode->data1,(block*)s_ind); } //Allocate the blocks and save in the indirect block for(;inode->blocks < blocks_needed; inode->blocks++) { s_ind[inode->blocks-8] = reserve_block(); } blk_write(inode->data1,(block*)s_ind); } } free(s_ind); return 0; }
/* UDC ISR function */ void INT_UDC(void) { uint32_t txstat, rxstat; int tmp, ep_num; /* read what caused UDC irq */ uint32_t intsrc = INT2FLAG & 0x7fffff; if (intsrc & (1<<1)) /* setup interrupt */ { setup_received(); } else if (intsrc & (1<<2)) /* ep0 in interrupt */ { txstat = TX0STAT; /* read clears flags */ /* TODO handle errors */ if (txstat & (1<<18)) /* check TxACK flag */ { if (ctrlep[DIR_IN].cnt >= 0) { /* we still have data to send (or ZLP) */ ctr_write(); } else { /* final ack received */ usb_core_transfer_complete(0, /* ep */ USB_DIR_IN, /* dir */ 0, /* status */ ctrlep[DIR_IN].len); /* length */ /* release semaphore for blocking transfer */ if (ctrlep[DIR_IN].block) semaphore_release(&ctrlep[DIR_IN].complete); } } } else if (intsrc & (1<<3)) /* ep0 out interrupt */ { rxstat = RX0STAT; /* TODO handle errors */ if (rxstat & (1<<18)) /* RxACK */ { if (ctrlep[DIR_OUT].cnt > 0) ctr_read(); else usb_core_transfer_complete(0, /* ep */ USB_DIR_OUT, /* dir */ 0, /* status */ ctrlep[DIR_OUT].len); /* length */ } } else if (intsrc & (1<<4)) /* usb reset */ { usb_drv_init(); } else if (intsrc & (1<<5)) /* usb resume */ { TX0CON |= (1<<0); /* TxClr */ TX0CON &= ~(1<<0); RX0CON |= (1<<1); /* RxClr */ RX0CON &= (1<<1); } else if (intsrc & (1<<6)) /* usb suspend */ { } else if (intsrc & (1<<7)) /* usb connect */ { } else { /* lets figure out which ep generated irq */ tmp = intsrc >> 7; for (ep_num=1; ep_num < 15; ep_num++) { tmp >>= ep_num; if (tmp & 0x01) break; } if (intsrc & ((1<<8)|(1<<11)|(1<<14)|(1<<17)|(1<<20))) { /* bulk out */ rxstat = BOUT_RXSTAT(ep_num); /* TODO handle errors */ if (rxstat & (1<<18)) /* RxACK */ { if (endpoints[ep_num].cnt > 0) blk_read(ep_num); else usb_core_transfer_complete(ep_num, /* ep */ USB_DIR_OUT, /* dir */ 0, /* status */ endpoints[ep_num].len); /* length */ } } else if (intsrc & ((1<<9)|(1<<12)|(1<<15)|(1<<18)|(1<<21))) { /* bulk in */ txstat = BIN_TXSTAT(ep_num); /* TODO handle errors */ if (txstat & (1<<18)) /* check TxACK flag */ { if (endpoints[ep_num].cnt >= 0) { /* we still have data to send (or ZLP) */ blk_write(ep_num); } else { /* final ack received */ usb_core_transfer_complete(ep_num, /* ep */ USB_DIR_IN, /* dir */ 0, /* status */ endpoints[ep_num].len); /* length */ /* release semaphore for blocking transfer */ if (endpoints[ep_num].block) semaphore_release(&endpoints[ep_num].complete); } } } else if (intsrc & ((1<<10)|(1<13)|(1<<16)|(1<<19)|(1<<22))) { /* int in */ txstat = IIN_TXSTAT(ep_num); /* TODO handle errors */ if (txstat & (1<<18)) /* check TxACK flag */ { if (endpoints[ep_num].cnt >= 0) { /* we still have data to send (or ZLP) */ int_write(ep_num); } else { /* final ack received */ usb_core_transfer_complete(ep_num, /* ep */ USB_DIR_IN, /* dir */ 0, /* status */ endpoints[ep_num].len); /* length */ /* release semaphore for blocking transfer */ if (endpoints[ep_num].block) semaphore_release(&endpoints[ep_num].complete); } } } } }
static int set_config(int num, char *buf) { int ret; ret = blk_write(buf, 512, CONFIG_MTD_CONFIG_DEVPATH, num * 512); return ret; }
static int file_block(struct filesys *fs, struct inode *node, int boffs, int allocate) { int res, idx, node_dirty = 0; blkid *barr; /* out of bounds */ if(boffs < 0 || boffs >= MAX_DIND) { return 0; } /* is it a direct block ? */ if(boffs < NDIRBLK) { if(!(res = node->blk[boffs]) && allocate) { res = node->blk[boffs] = alloc_block(fs); if(res) { zero_block(fs, res); /* also write back the modified inode */ put_inode(fs, node); } } return res; } barr = malloc(fs->sb->blksize); assert(barr); /* is it an indirect block ? */ if(boffs < MAX_IND) { int ind_dirty = 0; if(node->ind) { /* read the indirect block */ blk_read(fs->bdev, node->ind, 1, barr); } else { /* does not exist... try to allocate if requested */ if(!allocate || !(node->ind = alloc_block(fs))) { res = 0; goto end; } /* allocated a block clear the buffer, and invalidate everything */ memset(barr, 0, sizeof fs->sb->blksize); node_dirty = 1; ind_dirty = 1; } idx = boffs - NDIRBLK; if(!(res = barr[idx])) { if(allocate && (res = barr[idx] = alloc_block(fs))) { ind_dirty = 1; } } /* write back the indirect block if needed */ if(ind_dirty) { blk_write(fs->bdev, node->ind, 1, barr); } goto end; } /* TODO check/rewrite this */ #if 0 /* is it a double-indirect block ? */ if(boffs < MAX_DIND) { /* first read the dind block and find the index of the ind block */ if(!node->dind) { if(allocate) { /* allocate and zero-out the double indirect block */ res = node->dind = alloc_block(fs); if(res) { zero_block(fs, res); } } else { res = 0; goto end; } } blk_read(fd->bdev, node->dind, 1, barr); idx = (boffs - MAX_IND) / BLK_BLKID; /* then read the ind block and find the index of the block */ if(!barr[idx]) { res = 0; goto end; } blk_read(fd->bdev, barr[idx], 1, barr); res = barr[(boffs - MAX_IND) % BLK_BLKID]; } #endif end: if(node_dirty) { put_inode(fs, node); } free(barr); return res; }
//************flush_metadata************ void flush_metadata(void) { blk_write(BLOCKID_SUPER, &superblk_cache); blk_write(BLOCKID_BLOCK_BITMAP, &block_bm_cache); blk_write(BLOCKID_INODE_BITMAP, &inode_bm_cache); }
//******** mkdir ******************** int8_t cnmkdir(const char* name) { char* name_copy = strdup(name); char name_tok[256]; char entry_name[256]; char* next_name_tok; dir_entry* entry; dir_ptr *dir = calloc(1,sizeof(dir_ptr)); //Directory file in memory (e.g. DIR object from filedef.h) bool last_dir = false; inode_read(cwd->inode_id, &dir->inode_st); //Start at cwd dir->inode_id = cwd->inode_id; next_name_tok = strtok(name_copy, "/"); do { //name_tok is the dir we are searching for or going to create strcpy(name_tok, next_name_tok); //Read the directory file for this inode dir->data = calloc(dir->inode_st.blocks,sizeof(block)); //Memory for all directory file blocks llread(&dir->inode_st, dir->data); //Read the directory file dir->index = 0; next_name_tok = strtok(NULL, "/"); //Read the next token if(next_name_tok == NULL) //This is the last directory in the path { last_dir = true; } //Find the token in this dir while((entry = cnreaddir(dir))) { memcpy(entry_name, entry->name, entry->name_len); entry_name[entry->name_len] = 0; if(strcmp(entry_name, name_tok) == 0) //If this directory already exists { if(last_dir) { return -1; //Directory already exists } else //Read the directory inode { dir->inode_id = entry->inode; inode_read(entry->inode,&dir->inode_st); //Read the next directory's inode free(dir->data); //Forget the directory we just read break; } } } if(last_dir) //Create the directory at the end of the list { //Create parent directory entry entry = (dir_entry*)(((uint8_t*)dir->data)+dir->index); entry->file_type = ITYPE_DIR; entry->inode = reserve_inode(); memcpy(entry->name,name_tok,strlen(name_tok)); entry->name_len = strlen(name_tok); entry->entry_len = entry->name_len + 8; entry->entry_len += (4 - entry->entry_len % 4); //padding out to 32 bits dir->inode_st.size += entry->entry_len; //TODO: handle mkdir block overflow //Write parent dir and inode dir->inode_st.modified = time(NULL); inode_write(dir->inode_id, &dir->inode_st); blk_write(dir->inode_st.data0[0], dir->data); //Write new directory inode inode new_dir_i; memset(&new_dir_i, 0, sizeof(inode)); uint32_t now = time(NULL); new_dir_i.modified = now; new_dir_i.type = ITYPE_DIR; new_dir_i.size = 0; new_dir_i.blocks = 1; new_dir_i.data0[0] = reserve_block(); //Write new directory file block* new_dir_block = calloc(1,sizeof(block)); // . (self entry) dir_entry* new_dir_self_entry = (dir_entry*)new_dir_block; new_dir_self_entry->inode = entry->inode; new_dir_self_entry->file_type = ITYPE_DIR; new_dir_self_entry->name_len = 1; new_dir_self_entry->entry_len = 12; memcpy(new_dir_self_entry->name, ".", 1); new_dir_i.size += 12; // .. (parent entry) dir_entry* new_dir_parent_entry = (dir_entry*)(((uint8_t*)new_dir_block) + 12); new_dir_parent_entry->inode = dir->inode_id; new_dir_parent_entry->file_type = ITYPE_DIR; new_dir_parent_entry->name_len = 2; new_dir_parent_entry->entry_len = 12; memcpy(new_dir_parent_entry->name, "..", 2); new_dir_i.size += 12; //Write new dir and inode inode_write(entry->inode, &new_dir_i); blk_write(new_dir_i.data0[0], new_dir_block); free(new_dir_block); break; } } while(1); free(dir); free(name_copy); return 0; }