//handling stat request void stat_handler(Msg *msg, int sender_pid) { char pathname[MAXPATHNAMELEN]; CopyFrom(sender_pid,pathname,msg->ptr1,msg->num1+1); char* filename = pathname+msg->num2; int direct_len = msg->num2; while ((*filename)!='/' && filename!=pathname) { filename--; direct_len--; } if ((*filename)=='/') { direct_len++; filename++; } int parent_inum = path_to_inum(pathname,direct_len,msg->num2,0); int inum=check_dir(parent_inum,filename); struct Stat s; inode_cache *n = read_inode(inum); s.inum = inum; s.type = n->data.type; s.size = n->data.size; s.nlink = n->data.nlink; CopyTo(sender_pid,msg->ptr2,&s,sizeof(struct Stat)); }
//handling readlink request void readlink_handler(Msg *msg, int sender_pid) { char symname[MAXPATHNAMELEN]; memset(symname,'\0',MAXPATHNAMELEN); CopyFrom(sender_pid,symname,msg->ptr1,msg->num2+1); int return_len=msg->num3; char* filename = symname+msg->num2; int direct_len = msg->num2; while ((*filename)!='/' && filename!=symname) { filename--; direct_len--; } if ((*filename)=='/') { direct_len++; filename++; } int parent_inum=path_to_inum(symname,direct_len,msg->num1,0); int sym_inum=check_dir(parent_inum,filename); if(sym_inum<=0){ msg->type=-1; return; } inode_cache *sym_inode=read_inode(sym_inum); block_cache *sym_block=read_block(sym_inode->data.direct[0]); if(sym_inode->data.size<return_len) return_len=sym_inode->data.size; CopyTo(sender_pid,msg->ptr2,sym_block->data,return_len); msg->num3=return_len; }
void mkdir(int fd, std::string name) { std::vector<std::string> dirs = split(name, '/'); int inum = 1; //1 represents the root SuperBlock sb(fd); //Get the i-number for each directory along the path, //Until the first directory along the path isn't found //Create that directory for(std::vector<std::string>::iterator it = dirs.begin(); it != dirs.end(); ++it) { dout << *it << std::endl; int child_inum = path_to_inum(fd, *it, inum); //if the directory is not present if(child_inum < 1) { child_inum = sb.allocate_inode(fd); if(child_inum < 1) { std::cerr << "I-nodes depleted. Cannot allocate directory entry." << std::endl; return; } INode node(child_inum); node.flags = 0x8000 | 0x4000; //allocated and directory //We've allocated an inode, now we need to allocate a data block //Populate that data block with the entries for . and .. //and associate it with the inode. int block = sb.allocate_block(fd); if(block < 0) { std::cerr << "Data blocks depleted. Cannot allocate directory entry." << std::endl; return; } char buffer[BLOCK_SIZE] = {}; write_long(child_inum, sizeof(child_inum), buffer); buffer[sizeof(child_inum)] = '.'; write_long(inum, sizeof(inum), buffer + DIR_SIZE); buffer[sizeof(inum) + DIR_SIZE] = '.'; buffer[sizeof(inum) + DIR_SIZE + 1] = '.'; lseek(fd, block, SEEK_SET); write(fd, buffer, BLOCK_SIZE); char dir_entry[DIR_SIZE]; write_long(child_inum, sizeof(child_inum), dir_entry); strncpy(dir_entry + sizeof(child_inum), (*it).c_str(), DIR_SIZE - sizeof(child_inum)); //Add child inode to parent's directory listing addDirEntry(fd, inum, dir_entry); node.flush(fd); } inum = child_inum; } sb.flush(fd); }
//handling symlink request void symlink_handler(Msg *msg, int sender_pid) { char oldname[MAXPATHNAMELEN], newname[MAXPATHNAMELEN]; memset(oldname,'\0',MAXPATHNAMELEN); memset(newname,'\0',MAXPATHNAMELEN); CopyFrom(sender_pid,oldname,msg->ptr1,msg->num2+1); CopyFrom(sender_pid,newname,msg->ptr2,msg->num3+1); int dir_len=msg->num3; char *dir_newname=newname+msg->num3; while((*dir_newname)!='/'&&dir_newname!=newname){ dir_len--; dir_newname--; } if((*dir_newname)=='/'){ dir_len++; dir_newname++; } int parent_inum=path_to_inum(newname,dir_len,msg->num1,0); int sym_inum=alloc_inode(INODE_SYMLINK,parent_inum); if(sym_inum<=0){ msg->type=-1; return; } inode_cache *parent_inode=read_inode(parent_inum); inode_cache *sym_inode=read_inode(sym_inum); int sym_bnum=alloc_block(); block_cache *sym_block=read_block(sym_bnum); struct dir_entry *sym_dir_entry=search_dir_entry(parent_inum,dir_newname); if(sym_dir_entry!=NULL){ msg->type=-1; return; } if((sym_dir_entry=empty_dir(msg->num1))==NULL){ msg->type=-1; return; } sym_dir_entry->inum=sym_inum; memcpy(sym_dir_entry->name,dir_newname,msg->num3-dir_len); sym_inode->data.size=msg->num2; sym_inode->data.nlink=1; sym_inode->data.direct[0]=sym_bnum; sym_block->dirty=1; memcpy(sym_block->data,oldname,msg->num2); parent_inode->data.size+=sizeof(struct dir_entry); parent_inode->dirty=1; }
//handling mkdir request void mkdir_handler(Msg *msg, int sender_pid) { char pathname[MAXPATHNAMELEN]; CopyFrom(sender_pid,pathname,msg->ptr1,msg->num1+1); char* dir_name = pathname+msg->num1; int direct_len = msg->num1; while ((*dir_name)!='/' && dir_name!=pathname) { dir_name--; direct_len--; } if ((*dir_name)=='/') { direct_len++; dir_name++; } if (strlen(dir_name)==0) { perror("invalid pathname when creating file!"); msg->type = ERROR; return; } int direct_inum = path_to_inum(pathname,direct_len,msg->num2,0); if (direct_inum<=0) { perror("invalid pathname when creating file!"); msg->type = ERROR; return; } int new_inum = check_dir(direct_inum,dir_name); if (new_inum<0) { perror("invalid pathname when creating file!"); msg->type = ERROR; return; } //exist same file name in the directory else if (new_inum>0) { perror("exist a directory with same name"); msg->type = ERROR; return; } else if (new_inum==0) { new_inum = alloc_inode(INODE_DIRECTORY,direct_inum); struct dir_entry *d = empty_dir(direct_inum); if (d==NULL) { perror("no empty space for new directory"); msg->type = ERROR; return; } d->inum = new_inum; memcpy(d->name,dir_name,strlen(dir_name)); inode_cache *n = read_inode(direct_inum); n->data.nlink++; n->data.size+=sizeof(struct dir_entry); n->dirty = 1; msg->num1 = 0; } }
//handling open request void open_handler(Msg *msg, int sender_pid) { //msg->ptr1 is pathname, msg->num1 is length of pathname, msg->num2 is proc_inode char pathname[MAXPATHNAMELEN]; CopyFrom(sender_pid,pathname,msg->ptr1,msg->num1+1); int open_inum = path_to_inum(pathname,msg->num1,msg->num2,0); if (open_inum<=0) { msg->type = ERROR; } else { msg->num1 = open_inum; inode_cache *n = read_inode(open_inum); msg->num2 = n->data.reuse; } }
//handling chdir request void chdir_handler(Msg *msg, int sender_pid) { char pathname[MAXPATHNAMELEN]; CopyFrom(sender_pid,pathname,msg->ptr1,msg->num1+1); int target_inum = path_to_inum(pathname,msg->num1,msg->num2,0); if (target_inum<=0) { perror("illegal destination directory!"); msg->type = ERROR; return; } inode_cache *n = read_inode(target_inum); if (n->data.type!=INODE_DIRECTORY) { perror("trying to change current directory to a non-directory place"); msg->type = ERROR; return; } msg->num1 = target_inum; }
unsigned int path_to_inum(int fd, std::vector<std::string>& path, int inum, int pathPos) { //dout << path << " " << inum << std::endl; //Get the first directory name in the path char delim = '/'; std::string dir; if(pathPos < path.size()) { //Read the inode which represents a directory //and look for a file whose name matches dir dir = path[pathPos]; char buffer[BLOCK_SIZE] = {}; unsigned int block = 0; ByteAndBlock* rtnVal; rtnVal = copyBlock(fd, inum, block); lseek(fd, rtnVal->block * BLOCK_SIZE, SEEK_SET); read(fd, buffer, BLOCK_SIZE); while(rtnVal->bytesRead > 0) { for(int offset = 0; offset < rtnVal->bytesRead; offset += DIR_SIZE) { std::string name(buffer + offset + sizeof(unsigned int), DIR_SIZE - sizeof(unsigned int)); if(stringEquals(dir, name)) { delete rtnVal; return path_to_inum(fd, path, read_long(buffer + offset, sizeof(int)), pathPos + 1); } } delete rtnVal; rtnVal = copyBlock(fd, inum, block++); lseek(fd, rtnVal->block * BLOCK_SIZE, SEEK_SET); read(fd, buffer, BLOCK_SIZE); } delete rtnVal; return -1; } else { return inum; } }
//find an inode along the path int path_to_inum(char *pathname, int len_path, int proc_inum, int symlink_cnt) { if (pathname==NULL) return 0; int cur_inode = proc_inum; if (len_path==0) { return cur_inode; } //get a component in path char node_name[DIRNAMELEN]; memset(node_name,'\0',DIRNAMELEN); if (pathname[0]=='/') { while (len_path>0 && *pathname=='/') { pathname++; len_path--; } cur_inode = ROOTINODE; return path_to_inum(pathname,len_path,cur_inode,symlink_cnt); } int i = 0; while (len_path>0 && (*pathname!='/')) { node_name[i] = *pathname; i++; pathname++; len_path--; } while (len_path>0 && *pathname=='/') { pathname++; len_path--; } //looking up the inum in cur_inode for the acquired component inode_cache *n = read_inode(cur_inode); if (n->data.type!=INODE_DIRECTORY) { perror("illegal pathname!"); return -1; } int sub_inum = check_dir(cur_inode, node_name); if (sub_inum<=0) { //perror("illegal pathname, non-exist directory"); return -1; } n = read_inode(sub_inum); if (n->data.type==INODE_SYMLINK) { if (symlink_cnt>=MAXSYMLINKS) { perror("symlink traverse more than MAXSYMLINKS!"); return -1; } char *new_pathname = (char*)malloc(sizeof(char)*(n->data.size)+len_path+1); block_cache *b = read_block(n->data.direct[0]); memcpy(new_pathname,b->data,n->data.size); char *t1 = new_pathname+n->data.size; *t1 = '/'; t1++; memcpy(t1,pathname,len_path); return path_to_inum(new_pathname,n->data.size+1+len_path,cur_inode,symlink_cnt+1); } else return path_to_inum(pathname,len_path,sub_inum,symlink_cnt); }
//handling unlink request void unlink_handler(Msg *msg, int sender_pid) { char pathname[MAXPATHNAMELEN]; memset(pathname,'\0',MAXPATHNAMELEN); CopyFrom(sender_pid,pathname,msg->ptr1,msg->num2+1); int dir_len=msg->num2; char *dir_pathname=pathname+msg->num2; while((*dir_pathname)!='/'&&dir_pathname!=pathname){ dir_len--; dir_pathname--; } if((*dir_pathname)=='/'){ dir_len++; dir_pathname++; } int parent_inum=path_to_inum(pathname,dir_len,msg->num1,0); int path_inum=check_dir(parent_inum,dir_pathname); if(path_inum<=0||parent_inum<=0){ msg->type=-1; return; } inode_cache *path_inode=read_inode(path_inum); inode_cache *parent_inode=read_inode(parent_inum); if(path_inode->data.type==INODE_DIRECTORY){ msg->type=-1; return; } struct dir_entry *path_dir_entry=search_dir_entry(parent_inum,dir_pathname); if(path_inode->data.nlink>1){ path_dir_entry->inum=0; path_inode->data.nlink--; memset(path_dir_entry->name,'\0',DIRNAMELEN); parent_inode->data.size-=sizeof(struct dir_entry); parent_inode->dirty=1; } else if(path_inode->data.nlink==1){ path_dir_entry->inum=0; path_inode->data.nlink--; memset(path_dir_entry->name,'\0',DIRNAMELEN); free_inode(path_inum);//XXX path_inode->dirty=1; parent_inode->data.size-=sizeof(struct dir_entry); parent_inode->dirty=1; } else{ msg->type=-1; return; } }
//handling link request void link_handler(Msg *msg, int sender_pid) { char oldname[MAXPATHNAMELEN], newname[MAXPATHNAMELEN]; if(path_to_inum(newname,msg->num3,msg->num1,0)>0){ /*newname exists*/ msg->type=-1; return; } memset(oldname,'\0',MAXPATHNAMELEN); memset(newname,'\0',MAXPATHNAMELEN); CopyFrom(sender_pid,oldname,msg->ptr1,msg->num2+1); CopyFrom(sender_pid,newname,msg->ptr2,msg->num3+1); int dir_len=msg->num3; char *dir_newname=newname+msg->num3; while((*dir_newname)!='/'&&dir_newname!=newname){ dir_len--; dir_newname--; } if((*dir_newname)=='/'){ dir_len++; dir_newname++; } int parent_inum=path_to_inum(newname,dir_len,msg->num1,0); int dir_len_old=msg->num2; char *dir_oldname=oldname+msg->num2; while((*dir_oldname)!='/'&&dir_oldname!=oldname){ dir_len_old--; dir_oldname--; } if((*dir_oldname)=='/'){ dir_len_old++; dir_oldname++; } int parent_old_inum=path_to_inum(oldname,dir_len_old,msg->num1,0); int old_inum=check_dir(parent_old_inum,dir_oldname); if(old_inum<=0){ msg->type=-1; return; } inode_cache *old_inode=read_inode(old_inum); if(old_inode->data.type==INODE_DIRECTORY){ msg->type=-1; return; } struct dir_entry *newlink=search_dir_entry(parent_inum,dir_newname); if(newlink!=NULL){ msg->type=-1; return; } if((newlink=empty_dir(parent_inum))==NULL){ msg->type=-1; return; } inode_cache *parent_inode=read_inode(parent_inum); parent_inode->data.size+=sizeof(struct dir_entry); parent_inode->dirty=1; newlink->inum=old_inum; memcpy(newlink->name,dir_newname,msg->num3-dir_len); old_inode->data.nlink++; old_inode->dirty=1; }
//handling rmdir request void rmdir_handler(Msg *msg, int sender_pid) { char pathname[MAXPATHNAMELEN]; CopyFrom(sender_pid,pathname,msg->ptr1,msg->num1); int rm_inum = path_to_inum(pathname,msg->num1,msg->num2,0); if (rm_inum<=0) { msg->type = ERROR; return; } inode_cache *n = read_inode(rm_inum); if (n->data.size>2*sizeof(struct dir_entry)) { perror("try to remove a non-empty directory!"); msg->type = ERROR; return; } block_cache *b = read_block(n->data.direct[0]); struct dir_entry *d = (struct dir_entry*)(b->data); int pare_inum = d[1].inum; free_inode(rm_inum); //remove the dir_entry of rm_inum in parent directory inode_cache *dir = read_inode(pare_inum); if (dir->data.type!=INODE_DIRECTORY) { perror("parent not a directory when remove dir"); return; } dir->data.size-=sizeof(struct dir_entry); int i,block_num; //check direct blocks for (i=0; i<NUM_DIRECT; i++) { if (dir->data.direct[i]<=0) continue; block_num = dir->data.direct[i]; block_cache *b = read_block(block_num); struct dir_entry *d = (struct dir_entry*)(b->data); int j; for (j=0; j<DIRS_PER_BLOCK; j++) { if (d[j].inum<=0) continue; if (d[j].inum==rm_inum) { d[j].inum = 0; memset(d[j].name,'\0',DIRNAMELEN); b->dirty = 1; return; } } } //check indirect bloc if (dir->data.indirect!=0) { block_num = dir->data.indirect; block_cache *b = read_block(block_num); int j; block_cache *tmp; for (j=0; j<BLOCKSIZE; j+=4) { block_num = *(int*)(b->data+j); if (block_num!=0) { tmp = read_block(block_num); struct dir_entry *d = (struct dir_entry*)(tmp->data); int k; for (k=0; k<DIRS_PER_BLOCK; k++) { if (d[j].inum<=0) continue; if (d[j].inum==rm_inum) { d[j].inum = 0; memset(d[j].name,'\0',DIRNAMELEN); tmp->dirty = 1; return; } } } } } }
unsigned int path_to_inum(int fd, std::string path, int inum) { std::vector<std::string> pathVector = split(path, '/'); return path_to_inum(fd, pathVector, inum, 0); }
unsigned int path_to_inum(int fd, std::string path) { return path_to_inum(fd, path, 1); }